fix(installer): guard SourceDir/OutputDir with #ifndef so CI can over… #118
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*' # trigger with: git tag v0.85.2 && git push origin v0.85.2 | |
| env: | |
| DOTNET_VERSION: '8.0.x' | |
| PUBLISH_DIR: publish | |
| EXE_NAME: SQLTriage.exe | |
| INSTALLER_NAME: SQLTriage-Setup.exe | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true | |
| jobs: | |
| build-and-release: | |
| name: Build, Sign & Release | |
| runs-on: windows-latest | |
| permissions: | |
| contents: write # needed to create the GitHub Release | |
| steps: | |
| # ── 1. Checkout ────────────────────────────────────────────────────── | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # full history for changelog generation | |
| # ── 2. .NET setup ──────────────────────────────────────────────────── | |
| - name: Setup .NET ${{ env.DOTNET_VERSION }} | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| # ── 3. Read version from Config/version.json ───────────────────────── | |
| - name: Read version | |
| id: ver | |
| shell: pwsh | |
| run: | | |
| $v = (Get-Content Config/version.json | ConvertFrom-Json) | |
| echo "version=$($v.version)" >> $env:GITHUB_OUTPUT | |
| echo "build=$($v.buildNumber)" >> $env:GITHUB_OUTPUT | |
| echo "tag=${{ github.ref_name }}" >> $env:GITHUB_OUTPUT | |
| # ── 4. Restore ─────────────────────────────────────────────────────── | |
| # csproj has <RuntimeIdentifier>win-x64</RuntimeIdentifier> so restore | |
| # must include the win-x64 runtime pack — otherwise NETSDK1112. | |
| - name: Restore NuGet packages | |
| run: dotnet restore SQLTriage.sln -r win-x64 | |
| # ── 5. Build ───────────────────────────────────────────────────────── | |
| - name: Build | |
| run: dotnet build SQLTriage.sln -c Release --no-restore | |
| # ── 6. Test ────────────────────────────────────────────────────────── | |
| - name: Test | |
| run: dotnet test SQLTriage.sln -c Release --no-build --verbosity normal | |
| # ── 7. Build & Publish (self-contained, win-x64) ───────────────────── | |
| # Publish the WPF app project (NOT the solution) so PublishSingleFile | |
| # only emits one exe and the rename step can't accidentally pick up the | |
| # test runner exe. | |
| - name: Publish | |
| run: | | |
| dotnet publish SQLTriage.csproj ` | |
| -c Release ` | |
| -r win-x64 ` | |
| --self-contained true ` | |
| -p:PublishSingleFile=true ` | |
| -p:IncludeNativeLibrariesForSelfExtract=true ` | |
| -o ${{ env.PUBLISH_DIR }} | |
| # ── 8. Code-sign exe (skipped at runtime if secret not configured) ── | |
| # Note: cannot use `if: ${{ secrets.X != '' }}` — GitHub Actions does | |
| # not allow `secrets.*` in `if:` expressions. The runtime guard inside | |
| # the script handles the no-cert case instead. | |
| - name: Sign executable | |
| shell: pwsh | |
| env: | |
| CERT_BASE64: ${{ secrets.CODESIGN_CERT_BASE64 }} | |
| CERT_PASSWORD: ${{ secrets.CODESIGN_CERT_PASSWORD }} | |
| run: | | |
| # Skip if no certificate secret provided | |
| if ([string]::IsNullOrWhiteSpace($env:CERT_BASE64)) { | |
| Write-Host "No code signing certificate — skipping exe signing." | |
| exit 0 | |
| } | |
| $certBytes = [Convert]::FromBase64String($env:CERT_BASE64) | |
| $certPath = "codesign.pfx" | |
| [IO.File]::WriteAllBytes($certPath, $certBytes) | |
| # Find signtool — location varies by Windows SDK version | |
| $signtool = Get-ChildItem "C:\Program Files (x86)\Windows Kits\10\bin" ` | |
| -Recurse -Filter "signtool.exe" | | |
| Where-Object { $_.FullName -like "*x64*" } | | |
| Sort-Object FullName -Descending | | |
| Select-Object -First 1 -ExpandProperty FullName | |
| if (-not $signtool) { Write-Warning "signtool.exe not found — skipping signing"; exit 0 } | |
| & $signtool sign ` | |
| /fd sha256 ` | |
| /tr http://timestamp.digicert.com ` | |
| /td sha256 ` | |
| /f $certPath ` | |
| /p $env:CERT_PASSWORD ` | |
| "${{ env.PUBLISH_DIR }}\SQLTriage.exe" | |
| Remove-Item $certPath -Force | |
| Write-Host "Executable signed successfully." | |
| # ── 9. Verify exe exists ───────────────────────────────────────────── | |
| # Project's <AssemblyName> is SQLTriage so the published exe is already | |
| # SQLTriage.exe. Verify rather than rename so a publish that emits the | |
| # wrong file name fails loudly instead of grabbing createdump.exe etc. | |
| - name: Verify exe | |
| shell: pwsh | |
| run: | | |
| $exePath = Join-Path "${{ env.PUBLISH_DIR }}" "${{ env.EXE_NAME }}" | |
| if (-not (Test-Path $exePath)) { | |
| Write-Error "Expected exe not found at $exePath" | |
| Get-ChildItem "${{ env.PUBLISH_DIR }}" -Filter "*.exe" | ForEach-Object { Write-Host "Found: $($_.Name)" } | |
| exit 1 | |
| } | |
| Write-Host "Exe verified: $exePath ($((Get-Item $exePath).Length) bytes)" | |
| # ── 10. ZIP the raw exe ─────────────────────────────────────────────── | |
| - name: Create ZIP | |
| shell: pwsh | |
| run: | | |
| $zipName = "SQLTriage-${{ steps.ver.outputs.version }}.zip" | |
| Compress-Archive -Path "${{ env.PUBLISH_DIR }}\${{ env.EXE_NAME }}" ` | |
| -DestinationPath $zipName | |
| echo "ZIP_NAME=$zipName" >> $env:GITHUB_ENV | |
| # ── 11. Build Inno Setup installer ──────────────────────────────────── | |
| - name: Install Inno Setup | |
| run: choco install innosetup --no-progress -y | |
| - name: Build installer | |
| shell: pwsh | |
| run: | | |
| # Patch version.iss so the ISS picks up the right version at build time | |
| $ver = "${{ steps.ver.outputs.version }}" | |
| $build = "${{ steps.ver.outputs.build }}" | |
| Set-Content installer\version.iss "#define AppVersion `"$ver`"`n#define BuildNumber `"$build`"" | |
| # Override SourceDir to point at our publish output | |
| $workspace = "${{ github.workspace }}" | |
| $sourceDir = "$workspace\${{ env.PUBLISH_DIR }}" | |
| $outputDir = "$workspace\installer\Output" | |
| $iscc = "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" | |
| & $iscc installer\SQLTriage.iss ` | |
| /DSourceDir="$sourceDir" ` | |
| /DOutputDir="$outputDir" | |
| $setup = Get-ChildItem installer\Output -Filter "*.exe" | Select-Object -First 1 | |
| Copy-Item $setup.FullName "${{ env.INSTALLER_NAME }}" | |
| # ── 12. Sign installer (skipped at runtime if secret not configured) ─ | |
| - name: Sign installer | |
| shell: pwsh | |
| env: | |
| CERT_BASE64: ${{ secrets.CODESIGN_CERT_BASE64 }} | |
| CERT_PASSWORD: ${{ secrets.CODESIGN_CERT_PASSWORD }} | |
| run: | | |
| # Skip if no certificate secret provided | |
| if ([string]::IsNullOrWhiteSpace($env:CERT_BASE64)) { | |
| Write-Host "No code signing certificate — skipping installer signing." | |
| exit 0 | |
| } | |
| $certBytes = [Convert]::FromBase64String($env:CERT_BASE64) | |
| $certPath = "codesign.pfx" | |
| [IO.File]::WriteAllBytes($certPath, $certBytes) | |
| $signtool = Get-ChildItem "C:\Program Files (x86)\Windows Kits\10\bin" ` | |
| -Recurse -Filter "signtool.exe" | | |
| Where-Object { $_.FullName -like "*x64*" } | | |
| Sort-Object FullName -Descending | | |
| Select-Object -First 1 -ExpandProperty FullName | |
| if (-not $signtool) { Write-Warning "signtool.exe not found — skipping signing"; exit 0 } | |
| & $signtool sign ` | |
| /fd sha256 ` | |
| /tr http://timestamp.digicert.com ` | |
| /td sha256 ` | |
| /f $certPath ` | |
| /p $env:CERT_PASSWORD ` | |
| "${{ env.INSTALLER_NAME }}" | |
| Remove-Item $certPath -Force | |
| Write-Host "Installer signed successfully." | |
| # ── 13. Extract release notes from version.json ────────────────────── | |
| - name: Extract release notes | |
| id: notes | |
| shell: pwsh | |
| run: | | |
| $v = Get-Content Config/version.json | ConvertFrom-Json | |
| $notes = $v.whatsnew -join "`n- " | |
| $body = "## What's New in v$($v.version)`n`n- $notes`n`n---`n`n**Full changelog:** [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/main/CHANGELOG.md)" | |
| # Write to file to avoid env var length limits | |
| $body | Out-File -FilePath release_notes.md -Encoding utf8 | |
| # ── 14. Create GitHub Release ───────────────────────────────────────── | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| name: "SQLTriage v${{ steps.ver.outputs.version }}" | |
| body_path: release_notes.md | |
| draft: false | |
| prerelease: ${{ contains(github.ref_name, 'beta') || contains(github.ref_name, 'rc') }} | |
| files: | | |
| ${{ env.ZIP_NAME }} | |
| ${{ env.INSTALLER_NAME }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |