From f6d0c2bced9dee53240ecad1f3a3fe058a0c9972 Mon Sep 17 00:00:00 2001 From: PointStar Date: Mon, 11 May 2026 15:53:50 +0300 Subject: [PATCH] =?UTF-8?q?ci(publish):=20Task=20#8=20=E2=80=94=20fill=20i?= =?UTF-8?q?n=20ClickOnce=20publish=20+=20rsync=20+=20Mattermost?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trigger: tag push v*. - Compute version from tag (vMAJOR.MINOR.PATCH → 4-part for mage) - Sign DLLs + exe with signtool (CODESIGN_THUMBPRINT secret) - Build ClickOnce .dll.manifest + .vsto via mage.exe, sign both, rename payload files with .deploy convention for static-file serving - Stage protocol handler bin/ + install-protocol.ps1 alongside the ClickOnce artifact - Upload publish/ artifact to GH Actions for inspection - Upload to platform.dev:/var/www/outlook-addin/ via rsync (WSL) with scp fallback. PLATFORM_DEV_SSH_KEY secret expects a base64-encoded private key. Skips gracefully if the secret is empty. - POST to MATTERMOST_WEBHOOK_RELEASES on success and failure (#git-verelasim channel). Skips gracefully if the secret is empty. Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitea/workflows/build.yml | 139 ++++++++++++++++++++++++++++++++++--- 1 file changed, 129 insertions(+), 10 deletions(-) diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 148e34a..807ac1d 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -34,10 +34,30 @@ jobs: needs: build if: startsWith(github.ref, 'refs/tags/v') runs-on: windows-latest + env: + MAGE: 'C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\mage.exe' + SIGNTOOL: 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe' + PROVIDER_URL: 'https://platform.dev.marcus-law.co.il/outlook-addin/OutlookAddin.vsto' + REMOTE_DIR: '/var/www/outlook-addin' + REMOTE_HOST: 'platform.dev.marcus-law.co.il' steps: - name: Checkout uses: actions/checkout@v4 + - name: Compute version from tag + id: ver + shell: pwsh + run: | + $tag = "${{ github.ref_name }}" + if ($tag -notmatch '^v(\d+\.\d+\.\d+)$') { + throw "Tag $tag is not in vMAJOR.MINOR.PATCH form" + } + $version = "$($Matches[1]).0" + "version=$version" | Out-File -Append $env:GITHUB_OUTPUT + "versionDot=$($Matches[1])" | Out-File -Append $env:GITHUB_OUTPUT + "versionUscore=$($version -replace '\.','_')" | Out-File -Append $env:GITHUB_OUTPUT + Write-Host "Version: $version" + - name: Restore NuGet run: nuget restore OutlookAddin.sln @@ -47,29 +67,128 @@ jobs: # Code signing — cert installed on the runner's CurrentUser\My store. # Thumbprint comes from a Gitea Actions secret CODESIGN_THUMBPRINT. - name: Sign assemblies + shell: pwsh run: | $thumb = "${{ secrets.CODESIGN_THUMBPRINT }}" - signtool sign /sha1 $thumb /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 ` + & "$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/OutlookAddin.UI/bin/Release/net48/MarcusLaw.OutlookAddin.UI.dll ` + src/OutlookAddinProtocolHandler/bin/Release/net48/OutlookAddinProtocolHandler.exe - # mage.exe creates the ClickOnce .application + .vsto manifests. - # See docs/ARCHITECTURE.md → Deployment for the full command sequence. - name: Publish ClickOnce + shell: pwsh run: | - # TODO: invoke mage.exe / `vsto-publish` script (placeholder) - echo "ClickOnce publish — to be implemented in week 6" + $version = "${{ steps.ver.outputs.version }}" + $vUnderscore = "${{ steps.ver.outputs.versionUscore }}" + $thumb = "${{ secrets.CODESIGN_THUMBPRINT }}" + + $appBin = "src/OutlookAddin/bin/Release" + $publishDir = "publish" + $appFilesDir = "$publishDir/Application Files/OutlookAddin_$vUnderscore" + + New-Item -ItemType Directory -Force -Path $appFilesDir | Out-Null + Copy-Item -Recurse -Force "$appBin/*" $appFilesDir + + # Application manifest (.dll.manifest / .vsto). + & "$env:MAGE" -New Application ` + -ToFile "$appFilesDir/MarcusLaw.OutlookAddin.dll.manifest" ` + -Name "Marcus-Law OutlookAddin" ` + -Version $version ` + -FromDirectory $appFilesDir ` + -TrustLevel FullTrust + + & "$env:MAGE" -Sign "$appFilesDir/MarcusLaw.OutlookAddin.dll.manifest" ` + -CertHash $thumb ` + -TimeStampUri http://timestamp.digicert.com + + # Deployment manifest (.vsto). + Copy-Item "$appFilesDir/MarcusLaw.OutlookAddin.dll.manifest" "$publishDir/OutlookAddin.vsto" + & "$env:MAGE" -Update "$publishDir/OutlookAddin.vsto" ` + -AppManifest "$appFilesDir/MarcusLaw.OutlookAddin.dll.manifest" ` + -ProviderUrl "$env:PROVIDER_URL" ` + -Publisher "Marcus-Law" ` + -Install true + + & "$env:MAGE" -Sign "$publishDir/OutlookAddin.vsto" ` + -CertHash $thumb ` + -TimeStampUri http://timestamp.digicert.com + + # Mark the .deploy convention so IIS/nginx serves a static URL list. + Get-ChildItem -Recurse -File "$appFilesDir" | + Where-Object { $_.Extension -notin '.manifest','.deploy' } | + ForEach-Object { Rename-Item -LiteralPath $_.FullName -NewName ($_.Name + '.deploy') } + + - name: Stage protocol handler + shell: pwsh + run: | + $stagingDir = "publish/protocol-handler" + New-Item -ItemType Directory -Force -Path $stagingDir | Out-Null + Copy-Item -Recurse -Force "src/OutlookAddinProtocolHandler/bin/Release/net48/*" $stagingDir + Copy-Item -Force "tools/install-protocol.ps1" "$stagingDir/install-protocol.ps1" + Copy-Item -Force "tools/uninstall-protocol.ps1" "$stagingDir/uninstall-protocol.ps1" + + - name: Upload artifact (publish/) + uses: actions/upload-artifact@v4 + with: + name: outlookaddin-${{ steps.ver.outputs.versionDot }} + path: publish/ - name: Upload to platform.dev env: SSH_KEY: ${{ secrets.PLATFORM_DEV_SSH_KEY }} + shell: pwsh run: | - # TODO: rsync publish/ to platform.dev.marcus-law.co.il:/var/www/outlook-addin/ - echo "rsync — to be implemented in week 6" + if ([string]::IsNullOrWhiteSpace($env:SSH_KEY)) { + Write-Warning "PLATFORM_DEV_SSH_KEY not set — skipping upload" + exit 0 + } + $keyPath = Join-Path $env:TEMP "platform_ssh_key" + [System.IO.File]::WriteAllBytes($keyPath, [System.Convert]::FromBase64String($env:SSH_KEY)) + icacls $keyPath /inheritance:r /grant:r "$env:USERNAME`:F" | Out-Null + + # Requires WSL on the runner; falls back to scp if rsync isn't available. + $remote = "root@$env:REMOTE_HOST:$env:REMOTE_DIR/" + $useWsl = $false + try { wsl --status | Out-Null; $useWsl = $true } catch { $useWsl = $false } + + if ($useWsl) { + wsl rsync -avz --delete ` + -e "ssh -i /mnt/c/Users/runneradmin/AppData/Local/Temp/platform_ssh_key -o StrictHostKeyChecking=no" ` + ./publish/ ` + $remote + } else { + scp -i $keyPath -o StrictHostKeyChecking=no -r publish/* $remote + } + + Remove-Item $keyPath -Force - name: Notify Mattermost if: success() + shell: pwsh + env: + WEBHOOK: ${{ secrets.MATTERMOST_WEBHOOK_RELEASES }} run: | - # TODO: POST to MATTERMOST_WEBHOOK_RELEASES (from Infisical /mattermost) - echo "Mattermost notification — to be implemented in week 6" + if ([string]::IsNullOrWhiteSpace($env:WEBHOOK)) { + Write-Warning "MATTERMOST_WEBHOOK_RELEASES not set — skipping notification" + exit 0 + } + $version = "${{ steps.ver.outputs.versionDot }}" + $payload = @{ + text = ":package: OutlookAddin **v$version** משוחרר — https://platform.dev.marcus-law.co.il/outlook-addin/OutlookAddin.vsto" + channel = "git-verelasim" + } | ConvertTo-Json -Compress + Invoke-RestMethod -Uri $env:WEBHOOK -Method Post -Body $payload -ContentType "application/json" + + - name: Notify Mattermost on failure + if: failure() + shell: pwsh + env: + WEBHOOK: ${{ secrets.MATTERMOST_WEBHOOK_RELEASES }} + run: | + if ([string]::IsNullOrWhiteSpace($env:WEBHOOK)) { exit 0 } + $payload = @{ + text = ":warning: OutlookAddin publish ל-${{ github.ref_name }} נכשל — ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + channel = "git-verelasim" + } | ConvertTo-Json -Compress + Invoke-RestMethod -Uri $env:WEBHOOK -Method Post -Body $payload -ContentType "application/json"