Add Windows installer files to MSI build process
Some checks failed
farmcontrol/farmcontrol-server/pipeline/head There was a failure building this commit

- 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.
This commit is contained in:
Tom Butcher 2026-08-01 20:04:14 +01:00
parent 90da336696
commit 8b8475d11d
3 changed files with 53 additions and 25 deletions

View File

@ -26,6 +26,8 @@
<DirectoryRef Id="INSTALLFOLDER"> <DirectoryRef Id="INSTALLFOLDER">
<Component Id="SetupComponent" Guid="*"> <Component Id="SetupComponent" Guid="*">
<File Id="SetupExe" Source="$(var.SetupExe)" KeyPath="yes" /> <File Id="SetupExe" Source="$(var.SetupExe)" KeyPath="yes" />
<File Id="SetupArchive" Source="$(var.SetupArchive)" />
<File Id="SetupMetadata" Source="$(var.SetupMetadata)" />
</Component> </Component>
</DirectoryRef> </DirectoryRef>

View File

@ -2,6 +2,12 @@ param(
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[string]$SetupExe, [string]$SetupExe,
[Parameter(Mandatory = $true)]
[string]$SetupArchive,
[Parameter(Mandatory = $true)]
[string]$SetupMetadata,
[Parameter(Mandatory = $true)] [Parameter(Mandatory = $true)]
[string]$OutputMsi, [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." 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 $rootDir = Split-Path -Parent $PSScriptRoot
$wxsPath = Join-Path $rootDir "packaging/windows/farmcontrol-server.wxs" $wxsPath = Join-Path $rootDir "packaging/windows/farmcontrol-server.wxs"
$workDir = Join-Path $env:TEMP "farmcontrol-server-msi" $workDir = Join-Path $env:TEMP "farmcontrol-server-msi"
@ -44,28 +58,22 @@ if (Test-Path $workDir) {
} }
New-Item -ItemType Directory -Path $workDir | Out-Null 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" $candle = Find-WixTool "candle"
$light = Find-WixTool "light" $light = Find-WixTool "light"
$wixVersion = ConvertTo-WixVersion $Version $wixVersion = ConvertTo-WixVersion $Version
$setupExePath = (Resolve-Path -LiteralPath $SetupExe).Path $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 = @( $candleArgs = @(
'-nologo' '-nologo'
'-out' '-out'
$wixObj $wixObj
"-dVersion=$wixVersion" "-dVersion=$wixVersion"
"-dSetupExe=$setupExePath" "-dSetupExe=$setupExePath"
"-dSetupArchive=$setupArchivePath"
"-dSetupMetadata=$setupMetadataPath"
$wxsPath $wxsPath
) )

View File

@ -86,7 +86,7 @@ function findMacDmgSource(arch) {
return findByExtension(artifactDir, ".dmg"); return findByExtension(artifactDir, ".dmg");
} }
function findWindowsSetupExe() { function findWindowsInstallerFiles() {
const buildDir = path.join(rootDir, "build"); const buildDir = path.join(rootDir, "build");
if (!existsSync(buildDir)) { if (!existsSync(buildDir)) {
return null; return null;
@ -98,15 +98,26 @@ function findWindowsSetupExe() {
} }
const platformDir = path.join(buildDir, entry); const platformDir = path.join(buildDir, entry);
const setupExe = walkFiles(platformDir).find((filePath) => const files = walkFiles(platformDir);
filePath.toLowerCase().endsWith("-setup.exe"), const setupExe = files.find((filePath) =>
/-setup\.exe$/i.test(filePath),
); );
if (setupExe) { const setupArchive = files.find((filePath) =>
return setupExe; /-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) { function publishArtifact(sourcePath, arch, ext) {
@ -177,7 +188,7 @@ function buildMacPkg(appBundlePath, arch) {
return pkgPath; return pkgPath;
} }
function buildWindowsMsi(setupExePath, arch) { function buildWindowsMsi(installerFiles, arch) {
const scriptPath = path.join(rootDir, "scripts/build-windows-msi.ps1"); const scriptPath = path.join(rootDir, "scripts/build-windows-msi.ps1");
const msiPath = path.join( const msiPath = path.join(
artifactDir, artifactDir,
@ -203,7 +214,11 @@ function buildWindowsMsi(setupExePath, arch) {
"-File", "-File",
scriptPath, scriptPath,
"-SetupExe", "-SetupExe",
setupExePath, installerFiles.setupExe,
"-SetupArchive",
installerFiles.setupArchive,
"-SetupMetadata",
installerFiles.setupMetadata,
"-OutputMsi", "-OutputMsi",
msiPath, msiPath,
"-Version", "-Version",
@ -242,16 +257,19 @@ if (process.platform === "darwin") {
cleanStagingArtifacts(published.map((filePath) => path.basename(filePath))); cleanStagingArtifacts(published.map((filePath) => path.basename(filePath)));
} else if (process.platform === "win32") { } else if (process.platform === "win32") {
const arch = "x64"; const arch = "x64";
const setupExe = findWindowsSetupExe(); const installerFiles = findWindowsInstallerFiles();
if (!setupExe) { if (!installerFiles) {
throw new Error("Could not find the Windows setup executable to publish"); throw new Error(
"Could not find the Windows installer files (setup exe, archive, and metadata)",
);
} }
const published = [ const published = [buildWindowsMsi(installerFiles, arch)];
publishArtifact(setupExe, arch, "exe"),
buildWindowsMsi(setupExe, arch), if (installerFiles.setupZip) {
]; published.push(publishArtifact(installerFiles.setupZip, arch, "zip"));
}
cleanStagingArtifacts(published.map((filePath) => path.basename(filePath))); cleanStagingArtifacts(published.map((filePath) => path.basename(filePath)));
} else { } else {