From 8b8475d11dc6083a38a7b933e761749b12416d42 Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Sat, 1 Aug 2026 20:04:14 +0100 Subject: [PATCH] Add Windows installer files to MSI build process - Updated the farmcontrol-server.wxs file to include SetupArchive and SetupMetadata files for the MSI packaging. - Modified the build-windows-msi.ps1 script to accept new parameters for SetupArchive and SetupMetadata, enhancing the MSI build process. - Refactored the finalize-desktop-artifacts script to find and handle multiple Windows installer files, ensuring proper artifact publication. --- packaging/windows/farmcontrol-server.wxs | 2 + scripts/build-windows-msi.ps1 | 28 +++++++++----- scripts/finalize-desktop-artifacts.mjs | 48 ++++++++++++++++-------- 3 files changed, 53 insertions(+), 25 deletions(-) diff --git a/packaging/windows/farmcontrol-server.wxs b/packaging/windows/farmcontrol-server.wxs index 571a23e..67f708c 100644 --- a/packaging/windows/farmcontrol-server.wxs +++ b/packaging/windows/farmcontrol-server.wxs @@ -26,6 +26,8 @@ + + diff --git a/scripts/build-windows-msi.ps1 b/scripts/build-windows-msi.ps1 index ca5e34c..0859fd4 100644 --- a/scripts/build-windows-msi.ps1 +++ b/scripts/build-windows-msi.ps1 @@ -2,6 +2,12 @@ param( [Parameter(Mandatory = $true)] [string]$SetupExe, + [Parameter(Mandatory = $true)] + [string]$SetupArchive, + + [Parameter(Mandatory = $true)] + [string]$SetupMetadata, + [Parameter(Mandatory = $true)] [string]$OutputMsi, @@ -34,6 +40,14 @@ function Find-WixTool($toolName) { throw "Could not find $toolName. Install WiX Toolset v3.11 or v3.14 on the Windows build agent." } +function ConvertTo-WixVersion([string]$rawVersion) { + $parts = $rawVersion.Split('.') + while ($parts.Count -lt 4) { + $parts += '0' + } + return ($parts[0..3] -join '.') +} + $rootDir = Split-Path -Parent $PSScriptRoot $wxsPath = Join-Path $rootDir "packaging/windows/farmcontrol-server.wxs" $workDir = Join-Path $env:TEMP "farmcontrol-server-msi" @@ -44,28 +58,22 @@ if (Test-Path $workDir) { } New-Item -ItemType Directory -Path $workDir | Out-Null -function ConvertTo-WixVersion([string]$rawVersion) { - $parts = $rawVersion.Split('.') - while ($parts.Count -lt 4) { - $parts += '0' - } - return ($parts[0..3] -join '.') -} - $candle = Find-WixTool "candle" $light = Find-WixTool "light" $wixVersion = ConvertTo-WixVersion $Version $setupExePath = (Resolve-Path -LiteralPath $SetupExe).Path +$setupArchivePath = (Resolve-Path -LiteralPath $SetupArchive).Path +$setupMetadataPath = (Resolve-Path -LiteralPath $SetupMetadata).Path -# Quote -d defines so PowerShell passes them as single args to candle.exe. -# Unquoted -dVersion=$Version is parsed incorrectly; paths with spaces also break. $candleArgs = @( '-nologo' '-out' $wixObj "-dVersion=$wixVersion" "-dSetupExe=$setupExePath" + "-dSetupArchive=$setupArchivePath" + "-dSetupMetadata=$setupMetadataPath" $wxsPath ) diff --git a/scripts/finalize-desktop-artifacts.mjs b/scripts/finalize-desktop-artifacts.mjs index c83c738..078e9c9 100644 --- a/scripts/finalize-desktop-artifacts.mjs +++ b/scripts/finalize-desktop-artifacts.mjs @@ -86,7 +86,7 @@ function findMacDmgSource(arch) { return findByExtension(artifactDir, ".dmg"); } -function findWindowsSetupExe() { +function findWindowsInstallerFiles() { const buildDir = path.join(rootDir, "build"); if (!existsSync(buildDir)) { return null; @@ -98,15 +98,26 @@ function findWindowsSetupExe() { } const platformDir = path.join(buildDir, entry); - const setupExe = walkFiles(platformDir).find((filePath) => - filePath.toLowerCase().endsWith("-setup.exe"), + const files = walkFiles(platformDir); + const setupExe = files.find((filePath) => + /-setup\.exe$/i.test(filePath), ); - if (setupExe) { - return setupExe; + const setupArchive = files.find((filePath) => + /-setup\.tar\.zst$/i.test(filePath), + ); + const setupMetadata = files.find((filePath) => + /-setup\.metadata\.json$/i.test(filePath), + ); + const setupZip = files.find((filePath) => + /-setup\.zip$/i.test(filePath), + ); + + if (setupExe && setupArchive && setupMetadata) { + return { setupExe, setupArchive, setupMetadata, setupZip }; } } - return findByExtension(buildDir, "-Setup.exe"); + return null; } function publishArtifact(sourcePath, arch, ext) { @@ -177,7 +188,7 @@ function buildMacPkg(appBundlePath, arch) { return pkgPath; } -function buildWindowsMsi(setupExePath, arch) { +function buildWindowsMsi(installerFiles, arch) { const scriptPath = path.join(rootDir, "scripts/build-windows-msi.ps1"); const msiPath = path.join( artifactDir, @@ -203,7 +214,11 @@ function buildWindowsMsi(setupExePath, arch) { "-File", scriptPath, "-SetupExe", - setupExePath, + installerFiles.setupExe, + "-SetupArchive", + installerFiles.setupArchive, + "-SetupMetadata", + installerFiles.setupMetadata, "-OutputMsi", msiPath, "-Version", @@ -242,16 +257,19 @@ if (process.platform === "darwin") { cleanStagingArtifacts(published.map((filePath) => path.basename(filePath))); } else if (process.platform === "win32") { const arch = "x64"; - const setupExe = findWindowsSetupExe(); + const installerFiles = findWindowsInstallerFiles(); - if (!setupExe) { - throw new Error("Could not find the Windows setup executable to publish"); + if (!installerFiles) { + throw new Error( + "Could not find the Windows installer files (setup exe, archive, and metadata)", + ); } - const published = [ - publishArtifact(setupExe, arch, "exe"), - buildWindowsMsi(setupExe, arch), - ]; + const published = [buildWindowsMsi(installerFiles, arch)]; + + if (installerFiles.setupZip) { + published.push(publishArtifact(installerFiles.setupZip, arch, "zip")); + } cleanStagingArtifacts(published.map((filePath) => path.basename(filePath))); } else {