From 7d7c2b3756742708a49a56fd1023949f8bf3dca1 Mon Sep 17 00:00:00 2001 From: tsouth89 Date: Sat, 1 Aug 2026 02:08:55 -0400 Subject: [PATCH] Fix Microsoft Store installer parameters --- .github/workflows/ci.yml | 3 + rust/installer/codexbar.iss | 9 +++ .../ci/test-store-submission-preparation.ps1 | 79 +++++++++++++++++++ scripts/local-check.ps1 | 1 + scripts/prepare-store-submission.ps1 | 28 ++++++- 5 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 scripts/ci/test-store-submission-preparation.ps1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b349d4d7..d96e8170 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,6 +52,9 @@ jobs: with: shared-key: ci-shared - run: cargo fmt --all --check + - name: Test Store submission preparation + shell: pwsh + run: .\scripts\ci\test-store-submission-preparation.ps1 - run: cargo test --manifest-path rust/Cargo.toml - run: cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings diff --git a/rust/installer/codexbar.iss b/rust/installer/codexbar.iss index 9052bb7e..0fe3267f 100644 --- a/rust/installer/codexbar.iss +++ b/rust/installer/codexbar.iss @@ -41,6 +41,7 @@ DefaultDirName={localappdata}\Programs\Ceiling DefaultGroupName=Ceiling DisableProgramGroupPage=yes DisableDirPage=auto +DisableStartupPrompt=yes PrivilegesRequired=lowest UsePreviousAppDir=yes CloseApplications=yes @@ -209,6 +210,14 @@ begin Result := NeedsVCRedistRestart or NeedsWebView2Restart; end; +function GetCustomSetupExitCode(): Integer; +begin + if NeedRestart() then + Result := 3010 + else + Result := 0; +end; + function CanLaunchCeiling(): Boolean; begin Result := not NeedsVCRedistRestart and not NeedsWebView2Restart; diff --git a/scripts/ci/test-store-submission-preparation.ps1 b/scripts/ci/test-store-submission-preparation.ps1 new file mode 100644 index 00000000..6966891c --- /dev/null +++ b/scripts/ci/test-store-submission-preparation.ps1 @@ -0,0 +1,79 @@ +#Requires -Version 5.1 + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$repoRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) +$tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("ceiling-store-test-" + [guid]::NewGuid()) +$currentPath = Join-Path $tempRoot "current.json" +$preparedPath = Join-Path $tempRoot "prepared.json" +$missingParametersPath = Join-Path $tempRoot "missing-parameters.json" +$missingParametersPreparedPath = Join-Path $tempRoot "missing-parameters-prepared.json" +$installerUrl = "https://downloads.ceiling.win/releases/v1.5.21/Ceiling-1.5.21-Store-Setup.exe" +$expectedParameters = "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART" + +try { + New-Item -ItemType Directory -Path $tempRoot | Out-Null + @{ + Packages = @( + @{ + PackageUrl = "https://downloads.ceiling.win/releases/v1.5.19/Ceiling-1.5.19-Store-Setup.exe" + Languages = @("en-us") + Architectures = @("X64") + IsSilentInstall = $false + InstallerParameters = "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP- /RESTARTEXITCODE=3010" + PackageType = "exe" + } + ) + } | ConvertTo-Json -Depth 10 | Set-Content -LiteralPath $currentPath -Encoding utf8 + + & (Join-Path $repoRoot "scripts\prepare-store-submission.ps1") ` + -CurrentPackagePath $currentPath ` + -InstallerUrl $installerUrl ` + -OutputPath $preparedPath + + $prepared = Get-Content -LiteralPath $preparedPath -Raw | ConvertFrom-Json + $package = @($prepared.Packages)[0] + if ($package.PackageUrl -ne $installerUrl) { + throw "Store preparation did not update PackageUrl." + } + if ($package.InstallerParameters -ne $expectedParameters) { + throw "Store preparation did not normalize InstallerParameters." + } + if ($package.InstallerParameters.Length -ne 40) { + throw "Expected 40-character Store installer parameters, got $($package.InstallerParameters.Length)." + } + if ($package.Architectures -ne "X64" -or $package.PackageType -ne "exe") { + throw "Store preparation changed unrelated package metadata." + } + + $package.PSObject.Properties.Remove("InstallerParameters") + $prepared | ConvertTo-Json -Depth 10 | + Set-Content -LiteralPath $missingParametersPath -Encoding utf8 + & (Join-Path $repoRoot "scripts\prepare-store-submission.ps1") ` + -CurrentPackagePath $missingParametersPath ` + -InstallerUrl $installerUrl ` + -OutputPath $missingParametersPreparedPath + $missingParametersPackage = @( + (Get-Content -LiteralPath $missingParametersPreparedPath -Raw | ConvertFrom-Json).Packages + )[0] + $propertyNames = @($missingParametersPackage.PSObject.Properties.Name) + if ($propertyNames -cnotcontains "InstallerParameters" -or + $propertyNames -ccontains "installerParameters") { + throw "Store preparation added InstallerParameters with unexpected casing." + } + + $installerScript = Get-Content -LiteralPath (Join-Path $repoRoot "rust\installer\codexbar.iss") -Raw + if ($installerScript -notmatch '(?m)^DisableStartupPrompt=yes\r?$') { + throw "Installer no longer suppresses the startup prompt internally." + } + if ($installerScript -notmatch '(?m)^function GetCustomSetupExitCode\(\): Integer;\r?$') { + throw "Installer no longer returns 3010 for a successful install requiring restart." + } + + Write-Host "Store submission parameters are valid and preserve installer behavior." +} finally { + if (Test-Path -LiteralPath $tempRoot) { + Remove-Item -LiteralPath $tempRoot -Recurse -Force + } +} diff --git a/scripts/local-check.ps1 b/scripts/local-check.ps1 index 9545e5ca..a429318c 100644 --- a/scripts/local-check.ps1 +++ b/scripts/local-check.ps1 @@ -56,6 +56,7 @@ try { Invoke-Step "Frontend build" "pnpm" @("--dir", "apps\desktop-tauri", "run", "build") } if ($All -or $ReleaseDoctor) { + Invoke-Step "Store submission preparation" "powershell.exe" @("-File", "scripts\ci\test-store-submission-preparation.ps1") $args = @("-File", "scripts\release-doctor.ps1") if ($Version) { $args += @("-Version", $Version) diff --git a/scripts/prepare-store-submission.ps1 b/scripts/prepare-store-submission.ps1 index c1e7e135..3af5d21d 100644 --- a/scripts/prepare-store-submission.ps1 +++ b/scripts/prepare-store-submission.ps1 @@ -8,7 +8,10 @@ param( [string]$InstallerUrl, [Parameter(Mandatory = $true)] - [string]$OutputPath + [string]$OutputPath, + + [ValidateLength(1, 40)] + [string]$InstallerParameters = "/VERYSILENT /SUPPRESSMSGBOXES /NORESTART" ) Set-StrictMode -Version Latest @@ -45,6 +48,18 @@ if (-not $packageUrlProperty) { $packageUrlProperty.Value = $InstallerUrl +# Partner Center caps InstallerParameters at 40 characters. Startup-prompt +# suppression and the 3010 restart exit code live in codexbar.iss, so this +# command keeps the Store install fully silent without exceeding that limit. +$installerParametersProperty = $packages[0].PSObject.Properties | + Where-Object { $_.Name -ieq "installerParameters" } | + Select-Object -First 1 +if ($installerParametersProperty) { + $installerParametersProperty.Value = $InstallerParameters +} else { + $packages[0] | Add-Member -NotePropertyName "InstallerParameters" -NotePropertyValue $InstallerParameters +} + $outputDirectory = Split-Path -Parent $OutputPath if ($outputDirectory -and -not (Test-Path -LiteralPath $outputDirectory)) { New-Item -ItemType Directory -Path $outputDirectory -Force | Out-Null @@ -63,4 +78,15 @@ if ($preparedPackageUrlProperty.Value -ne $InstallerUrl) { throw "Prepared Microsoft Store submission does not contain the expected installer URL." } +$preparedInstallerParametersProperty = @($preparedPackagesProperty.Value)[0].PSObject.Properties | + Where-Object { $_.Name -ieq "installerParameters" } | + Select-Object -First 1 +if (-not $preparedInstallerParametersProperty -or + $preparedInstallerParametersProperty.Value -ne $InstallerParameters) { + throw "Prepared Microsoft Store submission does not contain the expected installer parameters." +} +if ($preparedInstallerParametersProperty.Value.Length -gt 40) { + throw "Prepared Microsoft Store installer parameters exceed Partner Center's 40-character limit." +} + Write-Host "Prepared Microsoft Store package update for $InstallerUrl"