From 3f63cd24f69b1996d5d74cdef9a96d306d76d647 Mon Sep 17 00:00:00 2001 From: Felix Stubner Date: Mon, 5 Oct 2026 00:55:19 +0100 Subject: [PATCH] Set the Windows installer's publisher to Felix Stubner, and test the upgrade Without bundle.publisher, Tauri uses the identifier's second segment, so the MSI's Manufacturer, and with it Installed apps, said "netscli" while the signature, winget and the Store listing say Felix Stubner. The WiX template also names per-user registry keys after the manufacturer, so the new installer-upgrade workflow installs the last release and then this build over it on a Windows runner, and checks for one Installed apps entry with the new publisher and version, a working Start menu shortcut, and no key left under the old name. --- .github/workflows/installer-upgrade.yml | 113 +++++++++++++++++++++ CHANGELOG.md | 10 ++ apps/netscli-gui/src-tauri/tauri.conf.json | 1 + 3 files changed, 124 insertions(+) create mode 100644 .github/workflows/installer-upgrade.yml diff --git a/.github/workflows/installer-upgrade.yml b/.github/workflows/installer-upgrade.yml new file mode 100644 index 00000000..62446f22 --- /dev/null +++ b/.github/workflows/installer-upgrade.yml @@ -0,0 +1,113 @@ +# Install the last released Windows MSI, then this branch's MSI over it, and +# check what a user would be left with. +# +# The installer's own settings (publisher, install scope, the WiX template) +# only show their effect on a real install, and a mistake there reaches users +# as a second copy in "Installed apps", a dead Start menu shortcut or a +# leftover registry key. None of that is visible to the other checks, and +# nobody wants to try it on their own machine, so it runs here on a +# disposable runner. +# +# The build is unsigned and has its version raised past any release, so it +# installs as the upgrade the next release will be. +name: Installer upgrade + +on: + pull_request: + paths: + - 'apps/netscli-gui/src-tauri/tauri.conf.json' + - 'apps/netscli-gui/src-tauri/wix/**' + - '.github/workflows/installer-upgrade.yml' + workflow_dispatch: + +permissions: + contents: read + +jobs: + upgrade: + runs-on: windows-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Install Rust + uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable + with: + toolchain: 1.96.0 + + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version-file: .nvmrc + cache: npm + cache-dependency-path: apps/netscli-gui/package-lock.json + + - name: npm ci + run: npm ci + working-directory: apps/netscli-gui + + # A file, not inline JSON: quotes inside an argument do not survive the + # trip through `npm run` in PowerShell. + - name: Build the MSI as the next version + shell: pwsh + working-directory: apps/netscli-gui + run: | + '{ "version": "0.99.0" }' | Set-Content -Encoding utf8 "$env:RUNNER_TEMP\next-version.json" + npm run tauri -- build --bundles msi --config "$env:RUNNER_TEMP\next-version.json" + + - name: Install the last release, then this build over it + shell: pwsh + env: + GH_TOKEN: ${{ github.token }} + run: | + $ErrorActionPreference = 'Stop' + $old = "$env:RUNNER_TEMP\old.msi" + gh release download --repo $env:GITHUB_REPOSITORY --pattern netscli-gui-windows-x86_64.msi --output $old + $new = (Get-ChildItem target\release\bundle\msi\*.msi | Select-Object -First 1).FullName + + function Install([string]$msi, [string]$log) { + $p = Start-Process msiexec -ArgumentList '/i', "`"$msi`"", '/qn', '/l*v', "`"$log`"" -Wait -PassThru + if ($p.ExitCode -ne 0) { Get-Content $log -Tail 40; throw "msiexec exited $($p.ExitCode) for $msi" } + } + Install $old "$env:RUNNER_TEMP\old.log" + Write-Host "--- after the release install" + Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' | + Where-Object DisplayName -like 'NetsCLI*' | Format-Table DisplayName, DisplayVersion, Publisher + Install $new "$env:RUNNER_TEMP\new.log" + + - name: Check what the user is left with + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + $want = (Get-Content apps/netscli-gui/src-tauri/tauri.conf.json -Raw | ConvertFrom-Json).bundle.publisher + $failed = @() + + $entries = @(Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*', 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' -ErrorAction SilentlyContinue | + Where-Object DisplayName -like 'NetsCLI*') + $entries | Format-Table DisplayName, DisplayVersion, Publisher + if ($entries.Count -ne 1) { $failed += "expected one NetsCLI entry in Installed apps, found $($entries.Count)" } + elseif ($entries[0].Publisher -ne $want) { $failed += "publisher is '$($entries[0].Publisher)', expected '$want'" } + elseif ($entries[0].DisplayVersion -ne '0.99.0') { $failed += "version is '$($entries[0].DisplayVersion)', expected the new build's 0.99.0" } + + $exe = 'C:\Program Files\NetsCLI\netscli-gui.exe' + if (-not (Test-Path $exe)) { $failed += "$exe is missing" } + + $shortcut = Get-ChildItem "$env:ProgramData\Microsoft\Windows\Start Menu\Programs", "$env:APPDATA\Microsoft\Windows\Start Menu\Programs" -Recurse -Filter 'NetsCLI.lnk' -ErrorAction SilentlyContinue | Select-Object -First 1 + if (-not $shortcut) { $failed += 'no NetsCLI Start menu shortcut' } + else { + $target = (New-Object -ComObject WScript.Shell).CreateShortcut($shortcut.FullName).TargetPath + Write-Host "Start menu shortcut -> $target" + if (-not (Test-Path $target)) { $failed += "Start menu shortcut points at a missing file: $target" } + } + + # Per-user keys are named after the publisher. Each name the app has + # shipped under should exist only if it is the current one. + foreach ($name in @('netscli', 'Felix Stubner')) { + $key = "HKCU:\Software\$name\NetsCLI" + $present = Test-Path $key + Write-Host "$key present: $present" + if ($present -and $name -ne $want) { $failed += "leftover registry key $key" } + if (-not $present -and $name -eq $want) { $failed += "missing registry key $key" } + } + + if ($failed) { $failed | ForEach-Object { Write-Host "::error::$_" }; exit 1 } + Write-Host "Upgrade from the last release leaves one install, published by $want." diff --git a/CHANGELOG.md b/CHANGELOG.md index 384a4ed3..383e78c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,16 @@ them. It printed "24 Aug 2026" for 0.3.1 for four days on the strength of a date written here when the notes were drafted. An in-flight version keeps its heading and collects entries. The date and the link go on with the tag. +## [Unreleased] + +### Changed + +- **Windows lists the desktop app's publisher as Felix Stubner.** Installed + apps showed "netscli", a default taken from the app's internal identifier, + while the code signature, winget and the Microsoft Store listing all say + Felix Stubner. Upgrading from an earlier version leaves one entry, under the + new name. + ## [0.3.4] - 2026-10-04 ### Added diff --git a/apps/netscli-gui/src-tauri/tauri.conf.json b/apps/netscli-gui/src-tauri/tauri.conf.json index 329b43c1..cfd2ea6c 100644 --- a/apps/netscli-gui/src-tauri/tauri.conf.json +++ b/apps/netscli-gui/src-tauri/tauri.conf.json @@ -44,6 +44,7 @@ }, "bundle": { "active": true, + "publisher": "Felix Stubner", "targets": "all", "icon": [ "icons/32x32.png",