Repository navigation
189 lines (164 loc) · 6.77 KB
/
Copy pathrelease.yml
File metadata and controls
189 lines (164 loc) · 6.77 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
name: release
# Push a tag such as v2025.10.01 to build, test and draft a GitHub release.
# The draft is reviewed and published by hand.
on:
push:
tags: ['v*']
permissions:
contents: read
jobs:
build:
runs-on: windows-latest
outputs:
executable-artifact-id: ${{ steps.executable.outputs.artifact-id }}
steps:
- uses: actions/checkout@v6
- uses: actions/setup-dotnet@v5
with:
dotnet-version: '10.0.x'
- name: Read version from tag
id: version
shell: pwsh
run: |
$tag = '${{ github.ref_name }}'
if ($tag -notmatch '^v(\d+\.\d+\.\d+)(-[0-9A-Za-z.-]+)?$') { throw "Tag $tag is not vMAJOR.MINOR.PATCH, e.g. v2025.10.01" }
"number=$($tag.Substring(1))" >> $env:GITHUB_OUTPUT
- name: Cache NuGet packages
uses: actions/cache@v5
with:
path: ~/.nuget/packages
key: nuget-${{ runner.os }}-${{ hashFiles('**/*.fsproj', '**/*.csproj', 'dotnet-tools.json') }}
restore-keys: nuget-${{ runner.os }}-
- name: Build Release
run: dotnet build WindowTabs.sln -c Release -p:Version=${{ steps.version.outputs.number }}
# The settings window, crash reports and settings migration all read this version.
- name: Check the executable carries the tag's version
shell: powershell
env:
EXPECTED: ${{ steps.version.outputs.number }}
run: ./tests/Check-ReleaseVersion.ps1 -Executable WtProgram/bin/Release/WindowTabs.exe -ExpectedVersion $env:EXPECTED
- name: Smoke test isolated Release assembly
shell: powershell
run: ./tests/Run-ReleaseSmoke.ps1
- name: Upload WindowTabs.exe
id: executable
uses: actions/upload-artifact@v6
with:
name: release-executable
path: WtProgram/bin/Release/WindowTabs.exe
if-no-files-found: error
- name: Upload Release diagnostics
if: always()
uses: actions/upload-artifact@v6
with:
name: release-diagnostics
path: |
tests/Debug/*.log
if-no-files-found: ignore
regressions:
name: regressions (${{ matrix.group }})
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- group: architecture
suites: 'Architecture,WindowIcon'
- group: operations
suites: 'GroupOperations,SettingsEditors'
- group: ui
suites: 'Reliability,DpiLayout,SettingsTheme,TabShadow,GroupLifecycle,PopupRendering,TabInteraction,TaskbarPreview,PrintWindowProbe'
steps:
- uses: actions/checkout@v6
- uses: actions/setup-dotnet@v5
with:
dotnet-version: '10.0.x'
- name: Cache NuGet packages
uses: actions/cache@v5
with:
path: ~/.nuget/packages
key: nuget-${{ runner.os }}-${{ hashFiles('**/*.fsproj', '**/*.csproj', 'dotnet-tools.json') }}
restore-keys: nuget-${{ runner.os }}-
# Each group owns a separate runner; native suites stay serial within it.
- name: Run regression tests serially
shell: powershell
env:
REGRESSION_SUITES: ${{ matrix.suites }}
run: ./tests/Run-Tests.ps1 -Suites ($env:REGRESSION_SUITES -split ',')
- name: Upload regression diagnostics
if: always()
uses: actions/upload-artifact@v6
with:
name: regression-diagnostics-${{ matrix.group }}
path: |
tests/Debug/*.log
tests/Debug/test-results.jsonl
if-no-files-found: ignore
# Real input against the very file the draft will carry.
desktop-e2e:
needs: build
uses: ./.github/workflows/desktop-e2e-hosted.yml
with:
profile: Full
executable-artifact: release-executable
# SignPath signs the tested exe once a maintainer approves the request. Until the
# SIGNPATH_ORGANIZATION_ID variable is set, releases are drafted unsigned.
sign:
needs: [build, regressions, desktop-e2e]
if: vars.SIGNPATH_ORGANIZATION_ID != ''
runs-on: windows-latest
permissions:
actions: read
contents: read
steps:
- uses: actions/checkout@v6
- name: Submit signing request
uses: signpath/github-action-submit-signing-request@v1
with:
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
organization-id: ${{ vars.SIGNPATH_ORGANIZATION_ID }}
project-slug: ${{ vars.SIGNPATH_PROJECT_SLUG || 'WindowTabs' }}
signing-policy-slug: ${{ vars.SIGNPATH_SIGNING_POLICY_SLUG || 'release-signing' }}
artifact-configuration-slug: ${{ vars.SIGNPATH_ARTIFACT_CONFIGURATION_SLUG || 'initial' }}
github-artifact-id: ${{ needs.build.outputs.executable-artifact-id }}
wait-for-completion: true
wait-for-completion-timeout-in-seconds: 86400
output-artifact-directory: signed
- name: Check the signed executable
shell: powershell
env:
TAG: ${{ github.ref_name }}
run: |
$signature = Get-AuthenticodeSignature signed/WindowTabs.exe
if ($null -eq $signature.SignerCertificate -or $signature.Status -in 'NotSigned','HashMismatch') {
throw "WindowTabs.exe is not signed: $($signature.StatusMessage)"
}
# The self-signed test certificate is not trusted; the production one must be.
if ($signature.Status -ne 'Valid') { Write-Warning "Signature status: $($signature.Status), $($signature.StatusMessage)" }
Write-Host "Signed by $($signature.SignerCertificate.Subject)"
./tests/Check-ReleaseVersion.ps1 -Executable signed/WindowTabs.exe -ExpectedVersion $env:TAG.Substring(1)
- name: Upload signed WindowTabs.exe
uses: actions/upload-artifact@v6
with:
name: release-executable-signed
path: signed/WindowTabs.exe
if-no-files-found: error
draft:
needs: [build, regressions, desktop-e2e, sign]
if: ${{ !cancelled() && needs.build.result == 'success' && needs.regressions.result == 'success' && needs.desktop-e2e.result == 'success' && (needs.sign.result == 'success' || needs.sign.result == 'skipped') }}
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v7
with:
name: ${{ needs.sign.result == 'success' && 'release-executable-signed' || 'release-executable' }}
- name: Draft GitHub release
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.ref_name }}
shell: pwsh
run: |
$flags = @('--draft', '--generate-notes', '--title', $env:TAG, '--repo', '${{ github.repository }}')
if ($env:TAG -match '^v\d+\.\d+\.\d+-') { $flags += '--prerelease' }
gh release create $env:TAG WindowTabs.exe @flags