Skip to content

fix(installer): guard SourceDir/OutputDir with #ifndef so CI can over… #119

fix(installer): guard SourceDir/OutputDir with #ifndef so CI can over…

fix(installer): guard SourceDir/OutputDir with #ifndef so CI can over… #119

Workflow file for this run

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 }}