Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ebfe93e
docs: specify profile editing and Windows installer
hugoalves-dev Sep 25, 2026
00540f5
chore: ignore local git worktrees
hugoalves-dev Sep 25, 2026
81d04e0
feat: add profile clone and delete operations
hugoalves-dev Sep 25, 2026
f09aeda
fix: prevent reconnecting deleted profiles
hugoalves-dev Sep 25, 2026
f1f8f0e
fix: reject profile path aliases and preserve delete success
hugoalves-dev Sep 25, 2026
ddd26c5
fix: require exact profile identity before deletion
hugoalves-dev Sep 25, 2026
214b39b
feat: expose profile lifecycle actions to desktop
hugoalves-dev Sep 25, 2026
107bae0
fix: retain committed profile actions after refresh errors
hugoalves-dev Sep 25, 2026
bb101bf
feat: add profile clone and delete controls
hugoalves-dev Sep 25, 2026
578d7ba
fix: bind profile deletion to confirmed target
hugoalves-dev Sep 25, 2026
78eba38
feat: add safe SQL script content editing
hugoalves-dev Sep 25, 2026
5849819
test: cover missing SQL and failed atomic write
hugoalves-dev Sep 25, 2026
e258ff0
test: verify repository save survives rename failure
hugoalves-dev Sep 25, 2026
773cd0e
feat: expose SQL content editing through Wails
hugoalves-dev Sep 25, 2026
f2d356c
fix: bind script editing to original profile
hugoalves-dev Sep 25, 2026
7fbe447
feat: add Monaco SQL script editor
hugoalves-dev Sep 25, 2026
ce67a26
fix: keep dirty editor open on discard escape
hugoalves-dev Sep 25, 2026
cc4a280
build: add dual-scope Windows MSI installer
hugoalves-dev Sep 25, 2026
b25cdab
fix: route installer scope through custom WiX UI
hugoalves-dev Sep 25, 2026
a0bded1
fix: give installer scope actions distinct names
hugoalves-dev Sep 25, 2026
d7c7e0e
fix: select installer path with installation scope
hugoalves-dev Sep 25, 2026
d9cc4fe
ci: publish portable exe and Windows MSI
hugoalves-dev Sep 25, 2026
7f548d6
docs: document portable and MSI distribution
hugoalves-dev Sep 25, 2026
1515418
docs: clarify Windows build outputs
hugoalves-dev Sep 25, 2026
7f5f49a
fix: surface modal errors and guard profile refreshes
hugoalves-dev Sep 25, 2026
9216c41
fix: ignore stale profile selection errors
hugoalves-dev Sep 25, 2026
2fcc176
fix: preserve connection state on profile refresh
hugoalves-dev Sep 25, 2026
435b0c3
docs: include approved feature plans
hugoalves-dev Sep 25, 2026
359b00b
ci: accept WiX 7 EULA for installer builds
hugoalves-dev Sep 25, 2026
94cf5ca
ci: accept WiX EULA when listing extensions
hugoalves-dev Sep 25, 2026
aca3b78
fix: align installer build with WiX 7 syntax
hugoalves-dev Sep 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 52 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,21 +86,56 @@ jobs:
- name: Install Wails CLI
run: go install github.com/wailsapp/wails/v2/cmd/wails@v2.13.0

- name: Setup .NET SDK for WiX
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'

- name: Install WiX Toolset 7 and UI extension
shell: pwsh
run: |
$wixVersion = '7.0.0'
$wixDirectory = Join-Path $env:TEMP "go-script-sql-runner-tools\wix\$wixVersion"
New-Item -ItemType Directory -Path $wixDirectory -Force | Out-Null
dotnet tool install wix --version $wixVersion --tool-path $wixDirectory --verbosity quiet
if ($LASTEXITCODE -ne 0) { throw 'Failed to install pinned WiX Toolset 7.0.0.' }

$env:WIX_EXTENSION = Join-Path $env:RUNNER_TEMP 'go-script-sql-runner-wix-extensions-7.0.0'
"WIX_EXTENSION=$env:WIX_EXTENSION" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
& (Join-Path $wixDirectory 'wix.exe') extension add --global 'WixToolset.UI.wixext/7.0.0' -acceptEula wix7
if ($LASTEXITCODE -ne 0) { throw 'Failed to install pinned WiX UI extension 7.0.0.' }

- name: Build executable
run: wails build -clean -webview2 embed -windowsconsole -ldflags "-X main.currentBuildTag=build-${{ github.run_number }}"
run: wails build -clean -webview2 embed -windowsconsole -ldflags "-X main.currentBuildTag=build-${{ github.run_number }}" -o go-script-sql-runner-portable.exe

- name: Verify executable
- name: Build MSI installer
shell: pwsh
run: |
if (-not (Test-Path 'build/bin/go-script-sql-runner.exe')) {
throw 'Expected build/bin/go-script-sql-runner.exe was not produced.'
./scripts/build-windows-installer.ps1 `
-AppVersion '0.1.${{ github.run_number }}' `
-ExecutablePath 'build/bin/go-script-sql-runner-portable.exe' `
-OutputDirectory 'build/bin'

- name: Verify Windows release files
shell: pwsh
run: |
$expectedFiles = @(
'build/bin/go-script-sql-runner-portable.exe',
'build/bin/go-script-sql-runner-setup.msi'
)
foreach ($file in $expectedFiles) {
if (-not (Test-Path -LiteralPath $file -PathType Leaf)) {
throw "Expected release file was not produced: $file"
}
}

- name: Upload executable artifact
- name: Upload Windows release files
uses: actions/upload-artifact@v4
with:
name: go-script-sql-runner-windows
path: build/bin/go-script-sql-runner.exe
path: |
build/bin/go-script-sql-runner-portable.exe
build/bin/go-script-sql-runner-setup.msi
if-no-files-found: error
retention-days: 14

Expand All @@ -112,17 +147,20 @@ jobs:
permissions:
contents: write
steps:
- name: Download executable artifact
- name: Download Windows release files
uses: actions/download-artifact@v5
with:
name: go-script-sql-runner-windows
path: release

- name: Verify release asset
- name: Verify Windows release files
shell: bash
run: test -f release/go-script-sql-runner.exe
run: |
set -euo pipefail
test -f release/go-script-sql-runner-portable.exe
test -f release/go-script-sql-runner-setup.msi

- name: Publish executable release
- name: Publish Windows release files
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
Expand All @@ -133,7 +171,8 @@ jobs:

if gh release view "${RELEASE_TAG}" >/dev/null 2>&1; then
gh release upload "${RELEASE_TAG}" \
release/go-script-sql-runner.exe \
'release/go-script-sql-runner-portable.exe#Windows portable executable' \
'release/go-script-sql-runner-setup.msi#Windows installer (MSI)' \
--clobber

gh release edit "${RELEASE_TAG}" \
Expand All @@ -143,7 +182,8 @@ jobs:
--latest
else
gh release create "${RELEASE_TAG}" \
'release/go-script-sql-runner.exe#Windows executable' \
'release/go-script-sql-runner-portable.exe#Windows portable executable' \
'release/go-script-sql-runner-setup.msi#Windows installer (MSI)' \
--target "${GITHUB_SHA}" \
--title "Go Script SQL Runner - Build #${GITHUB_RUN_NUMBER}" \
--notes "Automated Windows build from main. Commit: ${GITHUB_SHA}" \
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ frontend/dist/*
!frontend/dist/index.html

# Local runtime/profile artifacts
.worktrees/
GoScriptSQLRunner/
appdata/
.local/
Expand Down
25 changes: 18 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ For development/builds:
- Go 1.26+
- Node.js 24+
- Wails v2.13.0
- .NET SDK 10.0+ (used by the WiX 7 MSI builder)

## Windows downloads

GitHub Releases provide two Windows assets:

- `go-script-sql-runner-portable.exe` is the portable application executable. Run it directly; it does not install application files or create a Start Menu shortcut. Profiles and logs are still stored in the current Windows user's `%AppData%` directory described below, not beside the executable.
- `go-script-sql-runner-setup.msi` is the wizard installer. Choose **Only for me** to install under `%LocalAppData%\Programs\Go Script SQL Runner` without administrator rights, or **For all users** to install under `%ProgramFiles%\Go Script SQL Runner`, which requires Windows administrator approval.

Both MSI choices keep each Windows user's profiles and logs in that user's `%AppData%\GoScriptSQLRunner\profiles` and `%AppData%\GoScriptSQLRunner\logs` directories. The MSI installs or removes the application and shortcut; it does not move or delete this per-user data. Each Windows account continues to use its own profiles, including when the app is installed for all users.

## Build

Expand All @@ -25,12 +35,13 @@ Use the reproducible build script:
.\scripts\build.ps1
```

It runs Go tests, installs the locked frontend dependencies with `npm ci`, runs frontend tests/build, and builds the Wails executable with the embedded WebView2 bootstrapper.
It runs Go tests, installs the locked frontend dependencies with `npm ci`, runs frontend tests/build, and builds both the portable Wails executable with the embedded WebView2 bootstrapper and the MSI wizard installer.

Output:

```text
build/bin/go-script-sql-runner.exe
build/bin/go-script-sql-runner-portable.exe
build/bin/go-script-sql-runner-setup.msi
```

## AppData location
Expand All @@ -50,7 +61,7 @@ Each profile owns its copied SQL scripts under its profile directory. The fronte
Start the executable without arguments:

```powershell
.\go-script-sql-runner.exe
.\go-script-sql-runner-portable.exe
```

The default desktop window exposes the essential workflow without navigating to another screen:
Expand All @@ -70,15 +81,15 @@ Run-level overrides do not silently modify the saved profile. A script-level tra
Supplying arguments routes the same executable to the CLI:

```powershell
.\go-script-sql-runner.exe profile list
.\go-script-sql-runner.exe profile show example
.\go-script-sql-runner.exe run example
.\go-script-sql-runner-portable.exe profile list
.\go-script-sql-runner-portable.exe profile show example
.\go-script-sql-runner-portable.exe run example
```

For the complete command list:

```powershell
.\go-script-sql-runner.exe --help
.\go-script-sql-runner-portable.exe --help
```

## Profile import/export warning
Expand Down
61 changes: 61 additions & 0 deletions build/windows/installer/Package.wxs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
<Package Name="Go Script SQL Runner"
Manufacturer="Go Script SQL Runner"
Version="$(var.AppVersion)"
UpgradeCode="{4A6E52B1-7B7B-4B4E-85C4-6B858CA16B37}"
Scope="perUserOrMachine"
InstallerVersion="500"
Compressed="yes">
<!-- perUserOrMachine initializes ALLUSERS=2 and MSIINSTALLPERUSER=1. -->
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes" />

<Property Id="INSTALL_SCOPE" Value="CurrentUser" Secure="yes" />
<Property Id="ARPHELPLINK" Value="https://github.com/vitorhugo-dotnet/go-script-sql-runner" />
<Property Id="ARPURLINFOABOUT" Value="https://github.com/vitorhugo-dotnet/go-script-sql-runner" />

<SetDirectory Id="INSTALLFOLDER"
Action="SetCurrentUserInstallFolder"
Value="[LocalAppDataFolder]Programs\Go Script SQL Runner"
Sequence="both"
Condition="MSIINSTALLPERUSER = &quot;1&quot;" />
<SetDirectory Id="INSTALLFOLDER"
Action="SetAllUsersInstallFolder"
Value="[ProgramFiles64Folder]Go Script SQL Runner"
Sequence="both"
Condition="MSIINSTALLPERUSER &lt;&gt; &quot;1&quot;" />

<StandardDirectory Id="ProgramFiles64Folder">
<Directory Id="INSTALLFOLDER" Name="Go Script SQL Runner">
<Component Id="PortableApplication" Guid="{D33D284B-C90D-4285-A38D-FDCB81FEAE14}">
<File Id="PortableExecutable"
Source="$(var.PortableExecutable)"
KeyPath="yes" />
</Component>
</Directory>
</StandardDirectory>

<StandardDirectory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="Go Script SQL Runner">
<Component Id="StartMenuShortcut" Guid="{FA70E3F8-797E-451A-A4AA-E4E4D2D8381F}" KeyPath="yes">
<CreateFolder />
<Shortcut Id="ApplicationStartMenuShortcut"
Name="Go Script SQL Runner"
Target="[#PortableExecutable]"
WorkingDirectory="INSTALLFOLDER" />
<RemoveFolder Id="RemoveApplicationProgramsFolder" On="uninstall" />
</Component>
</Directory>
</StandardDirectory>

<Feature Id="Complete" Title="Go Script SQL Runner" Level="1">
<ComponentRef Id="PortableApplication" />
<ComponentRef Id="StartMenuShortcut" />
</Feature>

<UI>
<ui:WixUI Id="ScopeInstallDir" InstallDirectory="INSTALLFOLDER" />
</UI>
</Package>
</Wix>
103 changes: 103 additions & 0 deletions build/windows/installer/ScopeSelectionDlg.wxs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Fragment>
<UI>
<Dialog Id="ScopeSelectionDlg"
Width="370"
Height="270"
Title="[ProductName] Setup"
NoMinimize="yes">
<Control Id="Title"
Type="Text"
X="20"
Y="15"
Width="330"
Height="30"
Transparent="yes"
NoPrefix="yes"
Text="Choose who can use Go Script SQL Runner" />
<Control Id="Description"
Type="Text"
X="20"
Y="50"
Width="330"
Height="35"
Transparent="yes"
NoPrefix="yes"
Text="Choose an installation scope. Profiles and logs remain in your Windows user account in either mode." />
<Control Id="InstallScope"
Type="RadioButtonGroup"
X="20"
Y="100"
Width="330"
Height="70"
Property="INSTALL_SCOPE">
<RadioButtonGroup Property="INSTALL_SCOPE">
<RadioButton Value="CurrentUser" X="0" Y="0" Width="320" Height="20" Text="Only for me (recommended; no administrator required)" />
<RadioButton Value="AllUsers" X="0" Y="25" Width="320" Height="20" Text="For all users (installs under Program Files; administrator required)" />
</RadioButtonGroup>
</Control>
<Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="&amp;Back">
<Publish Event="NewDialog" Value="WelcomeDlg" Condition="1" />
</Control>
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="&amp;Next">
<Publish Property="MSIINSTALLPERUSER" Value="1" Order="1" Condition="INSTALL_SCOPE = &quot;CurrentUser&quot;" />
<Publish Property="INSTALLFOLDER" Value="[LocalAppDataFolder]Programs\Go Script SQL Runner" Order="2" Condition="INSTALL_SCOPE = &quot;CurrentUser&quot;" />
<Publish Property="MSIINSTALLPERUSER" Order="1" Condition="INSTALL_SCOPE = &quot;AllUsers&quot;" />
<Publish Property="INSTALLFOLDER" Value="[ProgramFiles64Folder]Go Script SQL Runner" Order="2" Condition="INSTALL_SCOPE = &quot;AllUsers&quot;" />
<Publish Event="NewDialog" Value="LicenseAgreementDlg" Order="3" Condition="1" />
</Control>
<Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="Cancel">
<Publish Event="SpawnDialog" Value="CancelDlg" Condition="1" />
</Control>
</Dialog>
</UI>
</Fragment>
<?foreach WIXUIARCH in X86;X64;A64 ?>
<Fragment>
<UI Id="ScopeInstallDir_$(WIXUIARCH)">
<Publish Dialog="BrowseDlg" Control="OK" Event="CheckTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1" />
<Publish Dialog="InstallDirDlg" Control="Next" Event="CheckTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1" />
<Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="4" />
</UI>
<UIRef Id="ScopeInstallDir" />
</Fragment>
<?endforeach?>
<Fragment>
<UI Id="file ScopeInstallDir">
<TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" />
<TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" />
<TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />
<Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
<DialogRef Id="BrowseDlg" />
<DialogRef Id="DiskCostDlg" />
<DialogRef Id="ErrorDlg" />
<DialogRef Id="FatalError" />
<DialogRef Id="FilesInUse" />
<DialogRef Id="MsiRMFilesInUse" />
<DialogRef Id="PrepareDlg" />
<DialogRef Id="ProgressDlg" />
<DialogRef Id="ResumeDlg" />
<DialogRef Id="UserExit" />
<Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999" />
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="ScopeSelectionDlg" Condition="NOT Installed" />
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Condition="Installed AND PATCH" />
<Publish Dialog="LicenseAgreementDlg" Control="Back" Event="NewDialog" Value="ScopeSelectionDlg" />
<Publish Dialog="LicenseAgreementDlg" Control="Next" Event="NewDialog" Value="InstallDirDlg" Condition="LicenseAccepted = &quot;1&quot;" />
<Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="LicenseAgreementDlg" />
<Publish Dialog="InstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="3" />
<Publish Dialog="InstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="1" />
<Publish Dialog="InstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2" />
<Publish Dialog="BrowseDlg" Control="OK" Event="SetTargetPath" Value="[_BrowseProperty]" Order="3" />
<Publish Dialog="BrowseDlg" Control="OK" Event="EndDialog" Value="Return" Order="4" />
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="InstallDirDlg" Order="1" Condition="NOT Installed" />
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="2" Condition="Installed AND NOT PATCH" />
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2" Condition="Installed AND PATCH" />
<Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg" />
<Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg" />
<Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg" />
<Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg" />
<Property Id="ARPNOMODIFY" Value="1" />
</UI>
<UIRef Id="WixUI_Common" />
</Fragment>
</Wix>
Loading
Loading