From 51c23c3f38a87c86cba2a7a2df8b6decc8618a21 Mon Sep 17 00:00:00 2001 From: Chaim Date: Mon, 11 May 2026 16:56:08 +0000 Subject: [PATCH] fix(ci): use msbuild /t:Publish (VSTO standard target) instead of manual mage The VSTO MSBuild Publish target is the same one VS IDE uses internally and handles build + assembly signing + manifest generation + manifest signing + .deploy renaming in one pass. Hand-stitching the steps with mage/signtool on top of /t:Build was producing inconsistent state. Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitea/workflows/build.yml | 86 +++++++++++++------------------------- 1 file changed, 28 insertions(+), 58 deletions(-) diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index afc7741..aee3030 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -265,70 +265,40 @@ jobs: if ($new -ne $cnt) { Set-Content $csproj -Value $new -NoNewline; Write-Host "patched" } else { Write-Host "already patched" } - Write-Host "=== STEP C: msbuild /restore /t:Build ===" + Write-Host "=== STEP C: msbuild /t:Publish (VSTO ClickOnce publish target) ===" + # /t:Publish is the standard VSTO publish target: it builds, signs + # assemblies, generates and signs the manifests, copies everything + # into the PublishDir, and renames payload files to .deploy. We + # don't need separate mage/signtool calls. + $publishDir = (Resolve-Path .).Path + "\publish\" $msbuildArgs = @( - 'OutlookAddin.sln','/restore','/t:Build', - '/p:Configuration=Release','/p:Platform="Any CPU"','/m', + 'OutlookAddin.sln', + '/restore', + '/t:Publish', + '/p:Configuration=Release', + '/p:Platform="Any CPU"', + '/p:PublishDir=' + $publishDir, + '/p:InstallUrl=https://platform.dev.marcus-law.co.il/outlook-addin/', + '/p:UpdateUrl=https://platform.dev.marcus-law.co.il/outlook-addin/', + '/p:ApplicationVersion=' + $env:VERSION, + '/p:MinimumRequiredVersion=' + $env:VERSION, + '/m', '/flp:logfile=publish-msbuild.log;verbosity=detailed' ) + Write-Host " msbuild $($msbuildArgs -join ' ')" & msbuild @msbuildArgs - if ($LASTEXITCODE -ne 0) { throw "msbuild failed with $LASTEXITCODE" } + if ($LASTEXITCODE -ne 0) { throw "msbuild /t:Publish failed with $LASTEXITCODE" } - Write-Host "=== STEP D: signtool sign assemblies ===" - & "$env:SIGNTOOL" sign /sha1 $thumb /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 ` - src/OutlookAddin/bin/Release/MarcusLaw.OutlookAddin.dll ` - src/OutlookAddin.Core/bin/Release/net48/MarcusLaw.OutlookAddin.Core.dll ` - src/OutlookAddin.UI/bin/Release/net48/MarcusLaw.OutlookAddin.UI.dll ` - src/OutlookAddinProtocolHandler/bin/Release/net48/OutlookAddinProtocolHandler.exe - if ($LASTEXITCODE -ne 0) { throw "signtool failed with $LASTEXITCODE" } + # Sanity check: did the VSTO publish target produce a .vsto file? + $vsto = Get-ChildItem -Recurse -Filter '*.vsto' -Path publish | Select-Object -First 1 + if (-not $vsto) { throw "msbuild /t:Publish completed but no .vsto file found under publish/" } + Write-Host " produced $($vsto.FullName)" - Write-Host "=== STEP E: mage publish ClickOnce ===" - $version = $env:VERSION - $versionUscore = $env:VERSION_USCORE - $appBin = "src/OutlookAddin/bin/Release" - $publishDir = "publish" - $appFilesDir = "$publishDir/Application Files/OutlookAddin_$versionUscore" - New-Item -ItemType Directory -Force -Path $appFilesDir | Out-Null - Copy-Item -Recurse -Force "$appBin/*" $appFilesDir - - # Write the PFX to disk so mage can sign via -CertFile (more reliable - # than -CertHash under LocalSystem). - $signPfx = Join-Path $env:TEMP "sign-$([Guid]::NewGuid()).pfx" - [IO.File]::WriteAllBytes($signPfx, [Convert]::FromBase64String($env:PFX_B64)) - - & "$env:MAGE" -New Application -ToFile "$appFilesDir/MarcusLaw.OutlookAddin.dll.manifest" ` - -Name "Marcus-Law OutlookAddin" -Version $version -FromDirectory $appFilesDir -TrustLevel FullTrust - if ($LASTEXITCODE -ne 0) { throw "mage -New Application failed" } - - & "$env:MAGE" -Sign "$appFilesDir/MarcusLaw.OutlookAddin.dll.manifest" ` - -CertFile $signPfx -Password $env:PFX_PWD ` - -TimeStampUri http://timestamp.digicert.com - if ($LASTEXITCODE -ne 0) { throw "mage -Sign app manifest failed" } - - # Create the deployment manifest (.vsto) directly via -New Deployment. - # Don't copy-then-Update -- mage rejects an Application manifest fed - # to -Update because the schema differs. - & "$env:MAGE" -New Deployment ` - -ToFile "$publishDir/OutlookAddin.vsto" ` - -Name "Marcus-Law OutlookAddin" ` - -Version $version ` - -AppManifest "$appFilesDir/MarcusLaw.OutlookAddin.dll.manifest" ` - -ProviderUrl "$env:PROVIDER_URL" ` - -Publisher "Marcus-Law" ` - -Install true - if ($LASTEXITCODE -ne 0) { throw "mage -New Deployment failed" } - - Write-Host "-- mage -Sign deployment manifest --" - $out = & "$env:MAGE" -Sign "$publishDir/OutlookAddin.vsto" ` - -CertFile $signPfx -Password $env:PFX_PWD ` - -TimeStampUri http://timestamp.digicert.com 2>&1 - $out | ForEach-Object { Write-Host "mage: $_" } - if ($LASTEXITCODE -ne 0) { throw "mage -Sign deployment manifest failed (exit $LASTEXITCODE)" } - Remove-Item -Force $signPfx - - Get-ChildItem -Recurse -File "$appFilesDir" | - ? { $_.Extension -notin '.manifest','.deploy' } | - % { Rename-Item -LiteralPath $_.FullName -NewName ($_.Name + '.deploy') } + # Rename to canonical OutlookAddin.vsto so the ClickOnce manifest + # URL matches PROVIDER_URL (which is hardcoded to .../OutlookAddin.vsto). + if ($vsto.Name -ne 'OutlookAddin.vsto') { + Rename-Item -LiteralPath $vsto.FullName -NewName 'OutlookAddin.vsto' + } Write-Host "=== STEP F: stage protocol handler ===" $stagingDir = "publish/protocol-handler"