From caba9b78e6a7bdbe83fbcc0f5c4e4e2d300825cb Mon Sep 17 00:00:00 2001 From: Leilei Zhang Date: Fri, 22 Aug 2025 13:25:47 +0800 Subject: [PATCH] fix wix5 pipeline --- .pipelines/ESRPSigning_installer.json | 4 +- .pipelines/v2/release.yml | 5 + .pipelines/v2/templates/job-build-project.yml | 119 +++++++++--------- .../templates/steps-build-installer-vnext.yml | 31 +++-- 4 files changed, 84 insertions(+), 75 deletions(-) diff --git a/.pipelines/ESRPSigning_installer.json b/.pipelines/ESRPSigning_installer.json index 1e2f1dcd9c..5b194e5972 100644 --- a/.pipelines/ESRPSigning_installer.json +++ b/.pipelines/ESRPSigning_installer.json @@ -9,8 +9,8 @@ "SilentFilesInUseBAFunction.dll", "PowerToys*Setup-*.exe", "PowerToys*Setup-*.msi", - "PowerToys*SetupVNext-*.exe", - "PowerToys*SetupVNext-*.msi" + "PowerToys*Setup-*-new-installer-*.exe", + "PowerToys*Setup-*-new-installer-*.msi" ], "SigningInfo": { "Operations": [ diff --git a/.pipelines/v2/release.yml b/.pipelines/v2/release.yml index d6c2177720..6c9bab54a1 100644 --- a/.pipelines/v2/release.yml +++ b/.pipelines/v2/release.yml @@ -42,6 +42,10 @@ parameters: type: boolean displayName: "Enable AOT (Ahead-of-Time) Compilation for CmdPal" default: true + - name: buildWix5Installer + type: boolean + displayName: "Build with WiX5-style installer naming (append '-new-installer')" + default: true name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr) @@ -105,6 +109,7 @@ extends: clientId: $(SigningOriginalClientId) # Have msbuild use the release nuget config profile additionalBuildOptions: /p:RestoreConfigFile="$(Build.SourcesDirectory)\.pipelines\release-nuget.config" /p:EnableCmdPalAOT=${{ parameters.enableAOT }} + buildWix5Installer: ${{ parameters.buildWix5Installer }} beforeBuildSteps: # Sets versions for all PowerToy created DLLs - pwsh: |- diff --git a/.pipelines/v2/templates/job-build-project.yml b/.pipelines/v2/templates/job-build-project.yml index b5448b3362..58825be435 100644 --- a/.pipelines/v2/templates/job-build-project.yml +++ b/.pipelines/v2/templates/job-build-project.yml @@ -62,6 +62,9 @@ parameters: - name: versionNumber type: string default: '0.0.1' + - name: buildWix5Installer + type: boolean + default: true - name: useLatestWinAppSDK type: boolean default: false @@ -476,20 +479,20 @@ jobs: additionalBuildOptions: ${{ parameters.additionalBuildOptions }} buildUserInstaller: true # NOTE: This is the distinction between the above and below rules - - template: steps-build-installer-vnext.yml - parameters: - codeSign: ${{ parameters.codeSign }} - signingIdentity: ${{ parameters.signingIdentity }} - versionNumber: ${{ parameters.versionNumber }} - additionalBuildOptions: ${{ parameters.additionalBuildOptions }} + - ${{ if eq(parameters.buildWix5Installer, true) }}: + - template: steps-build-installer-vnext.yml + parameters: + codeSign: ${{ parameters.codeSign }} + signingIdentity: ${{ parameters.signingIdentity }} + versionNumber: ${{ parameters.versionNumber }} + additionalBuildOptions: ${{ parameters.additionalBuildOptions }} - - template: steps-build-installer-vnext.yml - parameters: - codeSign: ${{ parameters.codeSign }} - signingIdentity: ${{ parameters.signingIdentity }} - versionNumber: ${{ parameters.versionNumber }} - additionalBuildOptions: ${{ parameters.additionalBuildOptions }} - buildUserInstaller: true # NOTE: This is the distinction between the above and below rules + - template: steps-build-installer-vnext.yml + parameters: + codeSign: ${{ parameters.codeSign }} + signingIdentity: ${{ parameters.signingIdentity }} + versionNumber: ${{ parameters.versionNumber }} + additionalBuildOptions: ${{ parameters.additionalBuildOptions }} # This saves ~1GiB per architecture. We won't need these later. # Removes: @@ -508,17 +511,10 @@ jobs: - task: CopyFiles@2 displayName: Stage Installers - inputs: - contents: "**/PowerToys*Setup-*.exe" - flattenFolders: True - targetFolder: $(JobOutputDirectory) - - - task: CopyFiles@2 - displayName: Stage VNext Installers inputs: contents: |- - installer/PowerToysSetupVNext/**/PowerToys*SetupVNext-*.exe - !installer/PowerToysSetupVNext/obj/** + **/PowerToys*Setup-*.exe + !**/PowerToysSetupVNext/obj/** flattenFolders: True targetFolder: $(JobOutputDirectory) @@ -534,48 +530,47 @@ jobs: - pwsh: |- $p = "$(JobOutputDirectory)\" - $userHash = ((Get-Item $p\PowerToysUserSetup*.exe | Get-FileHash).Hash); - $machineHash = ((Get-Item $p\PowerToysSetup*.exe | Get-FileHash).Hash); - $userPlat = "hash_user_$(BuildPlatform).txt"; - $machinePlat = "hash_machine_$(BuildPlatform).txt"; - $combinedUserPath = $p + $userPlat; - $combinedMachinePath = $p + $machinePlat; - - echo $p - - echo $userPlat - echo $userHash - echo $combinedUserPath - - echo $machinePlat - echo $machineHash - echo $combinedMachinePath - - $userHash | out-file -filepath $combinedUserPath - $machineHash | out-file -filepath $combinedMachinePath - displayName: Calculate file hashes - - # Output config for installer vnext - - pwsh: |- - $p = "$(JobOutputDirectory)\" - $userHash = ((Get-Item $p\PowerToysUserSetupVNext*.exe | Get-FileHash).Hash); - $machineHash = ((Get-Item $p\PowerToysSetupVNext*.exe | Get-FileHash).Hash); - $userPlat = "hash_user_$(BuildPlatform).txt"; - $machinePlat = "hash_machine_$(BuildPlatform).txt"; - $combinedUserPath = $p + $userPlat; - $combinedMachinePath = $p + $machinePlat; - echo $p - echo $userPlat - echo $userHash - echo $combinedUserPath - echo $machinePlat - echo $machineHash - echo $combinedMachinePath + # Calculate hashes for regular installers (without '-new-installer-') + $userSetupFiles = Get-ChildItem -Path $p -Filter "PowerToysUserSetup*.exe" | Where-Object { $_.Name -notmatch "-new-installer-" } + $machineSetupFiles = Get-ChildItem -Path $p -Filter "PowerToysSetup*.exe" | Where-Object { $_.Name -notmatch "-new-installer-" -and $_.Name -notmatch "PowerToysUserSetup" } - $userHash | out-file -filepath $combinedUserPath - $machineHash | out-file -filepath $combinedMachinePath - displayName: Calculate file hashes + if ($userSetupFiles.Count -gt 0) { + $userHash = ($userSetupFiles[0] | Get-FileHash).Hash; + $userPlat = "hash_user_$(BuildPlatform).txt"; + $combinedUserPath = $p + $userPlat; + echo "Regular User: $userHash" + $userHash | out-file -filepath $combinedUserPath + } + + if ($machineSetupFiles.Count -gt 0) { + $machineHash = ($machineSetupFiles[0] | Get-FileHash).Hash; + $machinePlat = "hash_machine_$(BuildPlatform).txt"; + $combinedMachinePath = $p + $machinePlat; + echo "Regular Machine: $machineHash" + $machineHash | out-file -filepath $combinedMachinePath + } + + # Calculate hashes for VNext installers (with '-new-installer-') + $userVNextFiles = Get-ChildItem -Path $p -Filter "PowerToysUserSetup*-new-installer-*.exe" + $machineVNextFiles = Get-ChildItem -Path $p -Filter "PowerToysSetup*-new-installer-*.exe" | Where-Object { $_.Name -notmatch "PowerToysUserSetup" } + + if ($userVNextFiles.Count -gt 0) { + $userVNextHash = ($userVNextFiles[0] | Get-FileHash).Hash; + $userVNextPlat = "hash_user_vnext_$(BuildPlatform).txt"; + $combinedUserVNextPath = $p + $userVNextPlat; + echo "VNext User: $userVNextHash" + $userVNextHash | out-file -filepath $combinedUserVNextPath + } + + if ($machineVNextFiles.Count -gt 0) { + $machineVNextHash = ($machineVNextFiles[0] | Get-FileHash).Hash; + $machineVNextPlat = "hash_machine_vnext_$(BuildPlatform).txt"; + $combinedMachineVNextPath = $p + $machineVNextPlat; + echo "VNext Machine: $machineVNextHash" + $machineVNextHash | out-file -filepath $combinedMachineVNextPath + } + displayName: Calculate file hashes for all installers # Publishing the GPO files - pwsh: |- diff --git a/.pipelines/v2/templates/steps-build-installer-vnext.yml b/.pipelines/v2/templates/steps-build-installer-vnext.yml index c7b4e91b47..c51082a05e 100644 --- a/.pipelines/v2/templates/steps-build-installer-vnext.yml +++ b/.pipelines/v2/templates/steps-build-installer-vnext.yml @@ -29,17 +29,26 @@ steps: displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Clean installer to reduce cross-contamination - pwsh: |- + # Determine whether this is a per-user build $IsPerUser = $${{ parameters.buildUserInstaller }} - $InstallerBuildSlug = "MachineSetup" - $InstallerBasename = "PowerToysSetupVNext" - If($IsPerUser) { - $InstallerBuildSlug = "UserSetup" - $InstallerBasename = "PowerToysUserSetupVNext" + + # Build slug used to locate the artifacts + $InstallerBuildSlug = if ($IsPerUser) { 'UserSetup' } else { 'MachineSetup' } + + # VNext bundle folder; base name intentionally omits the VNext suffix + $InstallerFolder = 'PowerToysSetupVNext' + if ($IsPerUser) { + $InstallerBasename = "PowerToysUserSetup-${{ parameters.versionNumber }}-new-installer-$(BuildPlatform)" } - $InstallerBasename += "-${{ parameters.versionNumber }}-$(BuildPlatform)" + else { + $InstallerBasename = "PowerToysSetup-${{ parameters.versionNumber }}-new-installer-$(BuildPlatform)" + } + + # Export variables for downstream steps Write-Host "##vso[task.setvariable variable=InstallerBuildSlug]$InstallerBuildSlug" Write-Host "##vso[task.setvariable variable=InstallerRelativePath]$(BuildPlatform)\$(BuildConfiguration)\$InstallerBuildSlug" Write-Host "##vso[task.setvariable variable=InstallerBasename]$InstallerBasename" + Write-Host "##vso[task.setvariable variable=InstallerFolder]$InstallerFolder" displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Prepare Installer variables # This dll needs to be built and signed before building the MSI. @@ -91,7 +100,7 @@ steps: maximumCpuCount: true - script: |- - wix msi decompile installer\PowerToysSetupVNext\$(InstallerRelativePath)\$(InstallerBasename).msi -x $(build.sourcesdirectory)\extractedMsi + wix msi decompile installer\$(InstallerFolder)\$(InstallerRelativePath)\$(InstallerBasename).msi -x $(build.sourcesdirectory)\extractedMsi dir $(build.sourcesdirectory)\extractedMsi displayName: "${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} WiX5: Extract and verify MSI" @@ -112,7 +121,7 @@ steps: displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign VNext MSI signingIdentity: ${{ parameters.signingIdentity }} inputs: - FolderPath: 'installer/PowerToysSetupVNext/$(InstallerRelativePath)' + FolderPath: 'installer/$(InstallerFolder)/$(InstallerRelativePath)' signType: batchSigning batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_installer.json' ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml' @@ -140,7 +149,7 @@ steps: # The entirety of bundle unpacking/re-packing is unnecessary if we are not code signing it. - ${{ if eq(parameters.codeSign, true) }}: - script: |- - wix burn detach installer\PowerToysSetupVNext\$(InstallerRelativePath)\$(InstallerBasename).exe -engine installer\engine.exe + wix burn detach installer\$(InstallerFolder)\$(InstallerRelativePath)\$(InstallerBasename).exe -engine installer\engine.exe displayName: "${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} WiX5: Extract Engine from Bundle" - template: steps-esrp-signing.yml @@ -176,7 +185,7 @@ steps: ] - script: |- - wix burn reattach installer\PowerToysSetupVNext\$(InstallerRelativePath)\$(InstallerBasename).exe -engine installer\engine.exe -o installer\PowerToysSetupVNext\$(InstallerRelativePath)\$(InstallerBasename).exe + wix burn reattach installer\$(InstallerFolder)\$(InstallerRelativePath)\$(InstallerBasename).exe -engine installer\engine.exe -o installer\$(InstallerFolder)\$(InstallerRelativePath)\$(InstallerBasename).exe displayName: "${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} WiX5: Reattach Engine to Bundle" - template: steps-esrp-signing.yml @@ -184,7 +193,7 @@ steps: displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign Final Bootstrapper signingIdentity: ${{ parameters.signingIdentity }} inputs: - FolderPath: 'installer/PowerToysSetupVNext/$(InstallerRelativePath)' + FolderPath: 'installer/$(InstallerFolder)/$(InstallerRelativePath)' signType: batchSigning batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_installer.json' ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'