Repository navigation
202 lines (182 loc) · 7.2 KB
/
Copy pathrelease.yml
File metadata and controls
202 lines (182 loc) · 7.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
name: Release
on:
workflow_dispatch:
inputs:
version:
description: 'Version to build and release (e.g. 3.0.0)'
required: true
type: string
push:
tags:
- 'release_*'
permissions:
contents: read
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
jobs:
version:
name: Resolve version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.resolve.outputs.version }}
steps:
- name: Resolve and validate version
id: resolve
shell: pwsh
env:
INPUT_VERSION: ${{ inputs.version }}
REF_NAME: ${{ github.ref_name }}
EVENT_NAME: ${{ github.event_name }}
run: |
$version = if ($env:EVENT_NAME -eq 'workflow_dispatch') { $env:INPUT_VERSION } else { $env:REF_NAME -replace '^release_', '' }
$version = "$version".Trim()
if ($version -notmatch '^\d+\.\d+\.\d+$') { throw "Invalid version '$version' - expected a three-part version such as 3.0.0." }
"version=$version" >> $env:GITHUB_OUTPUT
Write-Host "Release version: $version"
verify:
name: Verify build & tests
needs: [version]
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Set up .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.0.x
cache: true
cache-dependency-path: '**/*.csproj'
- name: Verify csproj version matches
shell: pwsh
env:
VERSION: ${{ needs.version.outputs.version }}
run: |
[xml]$app = Get-Content -LiteralPath SimpleZipDrive\SimpleZipDrive.csproj
$assemblyVersion = $app.Project.PropertyGroup.AssemblyVersion | Where-Object { $_ } | Select-Object -First 1
if ($assemblyVersion -ne $env:VERSION) {
throw "Version mismatch: release $($env:VERSION) but SimpleZipDrive AssemblyVersion is '$assemblyVersion'. Bump the csproj files first."
}
- name: Restore
run: dotnet restore CSharp_SimpleZipDrive.sln
- name: Build (Release)
run: dotnet build CSharp_SimpleZipDrive.sln -c Release --no-restore
- name: Test
run: dotnet test SimpleZipDrive.Tests\SimpleZipDrive.Tests.csproj -c Release --no-build
bundles:
name: Build bundles (${{ matrix.name }})
needs: [version, verify]
strategy:
fail-fast: false
matrix:
include:
- name: windows
os: windows-latest
rids: win-x64,win-arm64
- name: linux
os: ubuntu-latest
rids: linux-x64,linux-arm64
- name: macos
os: macos-latest
rids: osx-x64,osx-arm64
runs-on: ${{ matrix.os }}
env:
VERSION: ${{ needs.version.outputs.version }}
RIDS: ${{ matrix.rids }}
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Set up .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.0.x
cache: true
cache-dependency-path: '**/*.csproj'
- name: Package bundles
shell: pwsh
run: |
$rids = $env:RIDS.Split(',', [System.StringSplitOptions]::RemoveEmptyEntries)
./scripts/package-release.ps1 -Version $env:VERSION -RuntimeIdentifiers $rids -OutputDirectory "$env:RUNNER_TEMP/bundles" -StagingDirectory "$env:RUNNER_TEMP/staging" -SkipTests
- name: Write checksum summary
shell: pwsh
run: |
$lines = @('## Bundles ready for review', '')
Get-ChildItem -LiteralPath "$env:RUNNER_TEMP/bundles" -Filter *.zip | Sort-Object Name | ForEach-Object {
$hash = (Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash
$lines += ('- `{0}` - {1:N0} bytes - SHA256 `{2}`' -f $_.Name, $_.Length, $hash)
}
$lines += ''
$lines += 'The **Publish release** job is waiting for approval in the protected `release` environment.'
$lines | Set-Content -LiteralPath $env:GITHUB_STEP_SUMMARY -Encoding utf8
- name: Upload bundles for review
uses: actions/upload-artifact@v7
with:
name: release-bundles-${{ matrix.name }}
path: ${{ runner.temp }}/bundles/*.zip
if-no-files-found: error
retention-days: 30
publish:
name: Publish release (approval required)
needs: [version, bundles]
runs-on: ubuntu-latest
environment: release
permissions:
contents: write
env:
VERSION: ${{ needs.version.outputs.version }}
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
steps:
- name: Checkout (for release notes)
uses: actions/checkout@v5
- name: Download bundles
uses: actions/download-artifact@v8
with:
pattern: release-bundles-*
merge-multiple: true
path: bundles
- name: Verify the expected bundles are present
shell: pwsh
run: |
$expected = @(
"release_$($env:VERSION)_win-x64.zip",
"release_$($env:VERSION)_win-arm64.zip",
"release_$($env:VERSION)_linux-x64.zip",
"release_$($env:VERSION)_linux-arm64.zip",
"release_$($env:VERSION)_osx-x64.zip",
"release_$($env:VERSION)_osx-arm64.zip"
)
foreach ($name in $expected) {
if (-not (Test-Path -LiteralPath (Join-Path 'bundles' $name))) { throw "Missing expected bundle: $name" }
}
Get-ChildItem -LiteralPath bundles -File | Select-Object Name, Length
- name: Generate release notes from WhatsNew.md
shell: pwsh
run: |
$content = Get-Content -LiteralPath WhatsNew.md -Raw
$pattern = "(?ms)^##\s+$([regex]::Escape($env:VERSION))\s*\r?\n(.*?)(?=^##\s+|\z)"
$match = [regex]::Match($content, $pattern)
if ($match.Success) {
$notes = $match.Groups[1].Value.Trim()
} else {
$notes = "Release $($env:VERSION). See WhatsNew.md for the full changelog."
}
$notes += "`n`n---`n`nFull changelog: [$env:GITHUB_SERVER_URL/$env:GITHUB_REPOSITORY/blob/master/WhatsNew.md]($env:GITHUB_SERVER_URL/$env:GITHUB_REPOSITORY/blob/master/WhatsNew.md)"
Set-Content -LiteralPath bundles/release-notes.md -Value $notes -Encoding utf8
- name: Create or update the GitHub release
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
RELEASE_SHA: ${{ github.sha }}
run: |
TAG="release_${VERSION}"
if gh release view "$TAG" >/dev/null 2>&1; then
echo "Release $TAG already exists - updating notes and uploading/replacing the bundles."
gh release edit "$TAG" --notes-file bundles/release-notes.md
gh release upload "$TAG" bundles/*.zip --clobber
elif [ "$EVENT_NAME" = "workflow_dispatch" ]; then
gh release create "$TAG" --title "$VERSION" --target "$RELEASE_SHA" --notes-file bundles/release-notes.md bundles/*.zip
else
gh release create "$TAG" --title "$VERSION" --notes-file bundles/release-notes.md bundles/*.zip
fi
echo "Published: $(gh release view "$TAG" --json url --jq .url)"