Repository navigation
252 lines (242 loc) · 9.49 KB
/
Copy pathrelease.yml
File metadata and controls
252 lines (242 loc) · 9.49 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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
name: Release
# Builds the release bundles and publishes them on GitHub.
#
# Push a tag `v<version>` (e.g. `v1.1.0`, `v1.2.0-beta.1`; valid SemVer after the
# leading `v`, no `+build` metadata) to:
# 1. publish the framework-dependent single-file CLI for win-x64, win-arm64,
# linux-x64, linux-arm64, osx-x64 and osx-arm64 (the .NET 10 runtime is NOT
# embedded: target machines install the .NET 10 Runtime), smoke-test each
# binary on a native runner, and zip it with LICENSE, THIRD-PARTY-NOTICES.md,
# README.md and WhatsNew.md -> rvzsharp_v<version>_<rid>.zip (the naming the
# update-check clients expect)
# 2. pack the RVZSharp NuGet package (embedded PDBs, so no symbols package)
# 3. create the GitHub Release with the zips, SHA256SUMS.txt and the packages;
# the release notes come from docs/release-notes-<version>.md when present
# 4. push the package to nuget.org for stable versions (needs the NUGET_API_KEY
# repository secret from nuget.org -> API Keys)
#
# Run it manually (workflow_dispatch) for a dry run: everything above runs except
# the GitHub Release creation and the nuget.org push, and the artifacts stay
# available on the workflow run for inspection.
on:
push:
tags: ['v*']
workflow_dispatch:
inputs:
version:
description: 'Version to build (e.g. 1.1.0 or 1.2.0-beta.1). Dry run only: no GitHub Release, no nuget.org push.'
required: true
permissions:
contents: read
env:
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
jobs:
version:
name: Resolve version
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
version: ${{ steps.resolve.outputs.version }}
prerelease: ${{ steps.resolve.outputs.prerelease }}
tag: ${{ steps.resolve.outputs.tag }}
steps:
- name: Resolve version
id: resolve
shell: pwsh
run: |
$raw = '${{ github.event.inputs.version }}'
if ([string]::IsNullOrWhiteSpace($raw)) {
if ('${{ github.ref_type }}' -ne 'tag') { throw 'No version input and this is not a tag push.' }
$raw = '${{ github.ref_name }}'
}
# Strip exactly one leading 'v' (TrimStart would eat them all: 'vv1.2.3').
# Build metadata ('+...') is rejected: -p:Version cannot represent it.
$version = $raw.StartsWith('v') ? $raw.Substring(1) : $raw
if ($version -notmatch '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$') { throw "Not SemVer: '$raw'." }
$prerelease = [bool]($version -match '-')
"version=$version" >> $env:GITHUB_OUTPUT
"prerelease=$($prerelease.ToString().ToLower())" >> $env:GITHUB_OUTPUT
"tag=v$version" >> $env:GITHUB_OUTPUT
Write-Output "version=$version prerelease=$prerelease"
cli:
name: Bundle CLI (${{ matrix.rid }})
needs: version
strategy:
fail-fast: false
matrix:
include:
- rid: win-x64
os: windows-latest
exe: RVZSharp.exe
- rid: win-arm64
os: windows-11-arm
exe: RVZSharp.exe
- rid: linux-x64
os: ubuntu-latest
exe: RVZSharp
- rid: linux-arm64
os: ubuntu-24.04-arm
exe: RVZSharp
- rid: osx-x64
os: macos-15-intel
exe: RVZSharp
- rid: osx-arm64
os: macos-latest
exe: RVZSharp
runs-on: ${{ matrix.os }}
timeout-minutes: 30
env:
VERSION: ${{ needs.version.outputs.version }}
RID: ${{ matrix.rid }}
steps:
- uses: actions/checkout@v7
- uses: actions/setup-dotnet@v6
with:
dotnet-version: 10.0.x
# Framework-dependent single-file CLI: one binary per runtime, no .NET runtime
# embedded. Target machines install the .NET 10 Runtime; each bundle is smoke
# tested on a native runner so a broken apphost cannot ship.
- name: Publish
run: >
dotnet publish RVZSharp.Cli/RVZSharp.Cli.csproj -c Release -f net10.0
-r ${{ matrix.rid }} --self-contained false
-p:Version=${{ needs.version.outputs.version }}
-p:PublishSingleFile=true
-o artifacts/publish/${{ matrix.rid }}
- name: Smoke test
run: ./artifacts/publish/${{ matrix.rid }}/${{ matrix.exe }} --help
- name: Bundle zip
shell: pwsh
run: |
$bundle = "artifacts/bundle/rvzsharp_v$($env:VERSION)_$($env:RID)"
New-Item -ItemType Directory -Path $bundle -Force | Out-Null
Copy-Item "artifacts/publish/$env:RID/*" $bundle
Copy-Item LICENSE, THIRD-PARTY-NOTICES.md, README.md, WhatsNew.md $bundle
if ($IsWindows) {
Compress-Archive -Path "$bundle/*" -DestinationPath "$bundle.zip" -CompressionLevel Optimal
} else {
# zip(1) keeps the executable bit that Compress-Archive drops on Unix.
Push-Location $bundle
& zip -r -q "../rvzsharp_v$($env:VERSION)_$($env:RID).zip" .
Pop-Location
}
Get-Item "$bundle.zip"
- name: Upload bundle
uses: actions/upload-artifact@v6
with:
name: rvzsharp-${{ needs.version.outputs.version }}-${{ matrix.rid }}
path: artifacts/bundle/rvzsharp_v${{ needs.version.outputs.version }}_${{ matrix.rid }}.zip
if-no-files-found: error
retention-days: 30
package:
name: Pack NuGet
needs: version
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v7
- uses: actions/setup-dotnet@v6
with:
dotnet-version: 10.0.x
# Runs EnablePackageValidation (baseline: last published release) and embeds the
# SPDX SBOM (Microsoft.Sbom.Targets, Release only).
- name: Pack
run: >
dotnet pack RVZSharp/RVZSharp.csproj -c Release
-p:Version=${{ needs.version.outputs.version }}
-p:ContinuousIntegrationBuild=true
-o artifacts/packages
- name: Upload packages
uses: actions/upload-artifact@v6
with:
name: packages-${{ needs.version.outputs.version }}
path: artifacts/packages/*
if-no-files-found: error
retention-days: 30
release:
name: GitHub Release
needs: [version, cli, package]
if: github.ref_type == 'tag'
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write
steps:
- uses: actions/checkout@v7
with:
ref: ${{ needs.version.outputs.tag }}
- name: Download bundles
uses: actions/download-artifact@v4
with:
pattern: rvzsharp-${{ needs.version.outputs.version }}-*
path: artifacts/release
merge-multiple: true
- name: Download packages
uses: actions/download-artifact@v4
with:
name: packages-${{ needs.version.outputs.version }}
path: artifacts/release
- name: Checksums + release body
shell: pwsh
env:
VERSION: ${{ needs.version.outputs.version }}
run: |
Set-Location artifacts/release
Get-ChildItem *.zip | ForEach-Object {
$hash = (Get-FileHash $_.FullName -Algorithm SHA256).Hash.ToLower()
"$hash $($_.Name)" >> SHA256SUMS.txt
}
Get-Content SHA256SUMS.txt
$notes = "../../docs/release-notes-$env:VERSION.md"
if (Test-Path -LiteralPath $notes) {
Copy-Item $notes body.md
Write-Output "Using $notes as the release body."
} else {
Set-Content body.md "# RVZSharp $env:VERSION`n`nNo release notes file found at docs/release-notes-$env:VERSION.md.`n`nSee the [documentation](https://github.com/purelogiccode/RVZSharp/wiki) for usage."
Write-Output 'No release notes file; using the fallback body.'
}
- name: Create release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.version.outputs.tag }}
name: RVZSharp ${{ needs.version.outputs.version }}
body_path: artifacts/release/body.md
prerelease: ${{ needs.version.outputs.prerelease }}
draft: false
fail_on_unmatched_files: true
files: |
artifacts/release/*.zip
artifacts/release/SHA256SUMS.txt
artifacts/release/*.nupkg
nuget:
name: Push to nuget.org
needs: [version, package, release]
if: github.ref_type == 'tag' && needs.version.outputs.prerelease == 'false'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/setup-dotnet@v6
with:
dotnet-version: 10.0.x
- name: Download packages
uses: actions/download-artifact@v4
with:
name: packages-${{ needs.version.outputs.version }}
path: artifacts/packages
- name: Push (skipped without NUGET_API_KEY)
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: |
if [ -z "${NUGET_API_KEY}" ]; then
echo '::warning::NUGET_API_KEY is not set (nuget.org -> API Keys -> repository secret); the GitHub Release above is the only published artifact.'
exit 0
fi
shopt -s nullglob
for pkg in artifacts/packages/*.nupkg; do
dotnet nuget push "$pkg" --source https://api.nuget.org/v3/index.json --api-key "${NUGET_API_KEY}" --skip-duplicate
done