Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 48 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
name: Release

# Builds the three published artifacts on a real Windows runner and attaches
# them to a GitHub Release. Triggered by pushing a version tag, e.g. v1.1.3.
# them to a GitHub Release. Triggered by pushing a version tag (v1.1.3), or run
# manually with the tag as an input — the manual path creates the tag itself, so
# a release can be cut without local push access to refs/tags, and a failed
# release can be retried without inventing a new version number.
#
# The build itself is build-release.ps1 — the same script used locally — so a
# release built here and one built by hand cannot drift apart.

on:
push:
tags: ["v*"]
workflow_dispatch:
inputs:
tag:
description: "Version tag to publish, e.g. v1.1.3"
required: true
type: string

permissions:
contents: write
Expand All @@ -21,6 +30,21 @@ jobs:
- name: Checkout
uses: actions/checkout@v4

# Passed through the environment rather than interpolated into the script
# body, so the input cannot inject PowerShell.
- name: Resolve release tag
shell: pwsh
env:
INPUT_TAG: ${{ inputs.tag }}
run: |
$tag = if ($env:GITHUB_EVENT_NAME -eq 'workflow_dispatch') { $env:INPUT_TAG } else { $env:GITHUB_REF_NAME }
$tag = $tag.Trim()
if ($tag -notmatch '^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$') {
throw "Refusing to publish an unexpected tag format: '$tag'"
}
Add-Content -Path $env:GITHUB_ENV -Value "RELEASE_TAG=$tag"
Write-Host "Publishing $tag"

- name: Set up .NET 10
uses: actions/setup-dotnet@v4
with:
Expand All @@ -37,7 +61,7 @@ jobs:
- name: Verify tag matches project version
shell: pwsh
run: |
$tag = $env:GITHUB_REF_NAME
$tag = $env:RELEASE_TAG
$scriptVersion = (Select-String -Path build-release.ps1 -Pattern '^\$Version = "(.+)"').Matches[0].Groups[1].Value
$csprojVersion = ([xml](Get-Content WinBatLens.csproj)).Project.PropertyGroup.Version | Where-Object { $_ }
$issVersion = (Select-String -Path installer/WinBatLens.iss -Pattern '#define MyAppVersion "(.+)"').Matches[0].Groups[1].Value
Expand All @@ -48,14 +72,25 @@ jobs:
if ($csprojVersion -ne $scriptVersion) { throw "WinBatLens.csproj version $csprojVersion does not match $scriptVersion" }
if ($issVersion -ne $scriptVersion) { throw "installer/WinBatLens.iss version $issVersion does not match $scriptVersion" }

# Publishing the same version twice would either fail late or quietly
# replace what people have already downloaded.
- name: Verify the release does not already exist
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release view $env:RELEASE_TAG 2>$null
if ($LASTEXITCODE -eq 0) { throw "Release $env:RELEASE_TAG already exists" }
Write-Host "$env:RELEASE_TAG is free"

- name: Build release packages
shell: pwsh
run: ./build-release.ps1

- name: Verify all three artifacts exist
shell: pwsh
run: |
$version = $env:GITHUB_REF_NAME.TrimStart('v')
$version = $env:RELEASE_TAG.TrimStart('v')
$expected = @(
"dist/WinBatLens_v${version}_Setup_x64.exe",
"dist/WinBatLens_v${version}_Portable_x64.exe",
Expand All @@ -70,7 +105,7 @@ jobs:
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: winbatlens-${{ github.ref_name }}
name: winbatlens-${{ env.RELEASE_TAG }}
path: dist/*
if-no-files-found: error

Expand All @@ -87,15 +122,22 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: |
$tag = $env:GITHUB_REF_NAME
$tag = $env:RELEASE_TAG
$notes = ".github/release-notes/$tag.md"

$isPrerelease = $tag -match '^v[0-9.]+-'
if ((Test-Path $notes) -and (Select-String -Path $notes -Pattern '<!-- prerelease -->' -Quiet)) {
$isPrerelease = $true
}

$ghArgs = @("release", "create", $tag, "--title", "WinBat Lens $tag", "--verify-tag")
$ghArgs = @("release", "create", $tag, "--title", "WinBat Lens $tag")

# On a tag push the tag is already there and must be the one we built.
# On a manual run it does not exist yet, so it is created here against
# the exact commit that produced these artifacts.
if ($env:GITHUB_EVENT_NAME -eq 'workflow_dispatch') { $ghArgs += @("--target", $env:GITHUB_SHA) }
else { $ghArgs += "--verify-tag" }

if ($isPrerelease) { $ghArgs += "--prerelease" }
if (Test-Path $notes) { $ghArgs += @("--notes-file", $notes) }
else { $ghArgs += "--generate-notes" }
Expand Down
Loading