-
Notifications
You must be signed in to change notification settings - Fork 1
228 lines (221 loc) · 9.13 KB
/
Copy pathci.yml
File metadata and controls
228 lines (221 loc) · 9.13 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
name: CI
on:
push:
pull_request:
workflow_dispatch:
inputs:
windows_release_tag:
description: "Tag to attach an UNSIGNED Windows installer to (e.g. v1.1.0). Blank = skip."
required: false
default: ""
linux_release_tag:
description: "Tag to attach an UNSIGNED Linux AppImage/deb to (e.g. v1.5.0). Blank = skip."
required: false
default: ""
jobs:
test:
name: Test (${{ matrix.name }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- name: Linux
os: ubuntu-latest
- name: macOS Apple Silicon
os: macos-15
- name: macOS Intel
os: macos-15-intel
- name: Windows
os: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run ci
# The native macOS bridge daemon gates Screen Watch / creative-app /
# editor actions, so its Swift unit tests must pass before changes land.
# The bridge is macOS-only and needs the Xcode Swift toolchain
# (preinstalled on GitHub macOS runners), so this step is gated to the
# macOS legs of the matrix and skipped on Linux/Windows. `swift test`
# exits non-zero on failure, which fails this job.
- name: Swift bridge tests (macOS only)
if: runner.os == 'macOS'
run: |
swift --version
npm run test:swift:bridge
# iOS companion gate — the Electron matrix can't see iOS regressions, and the
# phone is the monetized launch surface. macOS 26 runner for the iOS 26 SDK
# (TaskWraithUI uses `.glassEffect`), with Xcode PINNED to 26.0 (Swift 6.2) to
# MATCH the shipping toolchain: the runner's default Xcode 26.5 (Swift 6.3.2)
# enforces region-isolation `sending` diagnostics as errors that local
# Swift 6.2.4 does not, so an unpinned lane would fail on latent concurrency
# debt rather than real regressions. (TODO: clear that Swift-6.3 region-
# isolation debt in RemoteSessionModel before bumping the pin.)
ios:
name: iOS (Kit tests)
runs-on: macos-26
steps:
- uses: actions/checkout@v4
- name: Available Xcodes (pre-pin diagnostic)
run: ls -d /Applications/Xcode*.app
- name: Select Xcode 26.0 (Swift 6.2 — matches ship toolchain)
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: "26.0"
- name: Toolchain versions
run: xcodebuild -version && swift --version
# `swift test` builds TaskWraithKit + TaskWraithUI (all the SwiftUI/Glass
# code) for the host and runs the 73 unit tests — the real regression
# gate. An app-target `xcodebuild` is intentionally NOT run here: the
# pinned Xcode 26.0 lacks the iOS simulator PLATFORM (GitHub pre-installs
# it only for the runner's default Xcode 26.5), and `-downloadPlatform iOS`
# would add minutes + GBs per run just to compile the thin app wrapper.
- name: Swift package tests (TaskWraithKit)
run: swift test --package-path ios/TaskWraithKit
notarized-macos-release:
name: Notarized macOS Release
runs-on: macos-15
if: startsWith(github.ref, 'refs/tags/v') && vars.ENABLE_MACOS_NOTARIZED_RELEASE == 'true'
env:
CSC_LINK: ${{ secrets.MACOS_CSC_LINK }}
CSC_KEY_PASSWORD: ${{ secrets.MACOS_CSC_KEY_PASSWORD }}
CSC_NAME: ${{ secrets.MACOS_CSC_NAME }}
APPLE_KEYCHAIN_PROFILE: ${{ secrets.APPLE_KEYCHAIN_PROFILE }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run security:deps
- run: npm run build:mac:notarized
- name: Verify notarized macOS artifacts
run: |
set -euo pipefail
test -d "dist/mac-universal/TaskWraith.app"
codesign --verify --deep --strict --verbose=2 "dist/mac-universal/TaskWraith.app"
spctl --assess --type execute --verbose=4 "dist/mac-universal/TaskWraith.app"
xcrun stapler validate "dist/mac-universal/TaskWraith.app"
for artifact in dist/*.dmg; do
test -f "$artifact"
xcrun stapler validate "$artifact"
done
signed-windows-release:
name: Signed Windows Release
runs-on: windows-latest
if: startsWith(github.ref, 'refs/tags/v') && vars.ENABLE_WINDOWS_SIGNED_RELEASE == 'true'
env:
CSC_LINK: ${{ secrets.WINDOWS_CSC_LINK }}
CSC_KEY_PASSWORD: ${{ secrets.WINDOWS_CSC_KEY_PASSWORD }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run security:deps
- run: npm run build:win:signed
- name: Verify signed Windows artifacts
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
$installers = Get-ChildItem -Path dist -Filter "TaskWraith-*-win-*-setup.exe"
if ($installers.Count -lt 2) {
throw "Expected signed x64 and arm64 Windows installers in dist/."
}
foreach ($installer in $installers) {
$signature = Get-AuthenticodeSignature -FilePath $installer.FullName
if ($signature.Status -ne "Valid") {
throw "Invalid Authenticode signature for $($installer.Name): $($signature.Status)"
}
}
$version = (Get-Content package.json | ConvertFrom-Json).version
$feedPrefix = if ($version -match "-") { "beta" } else { "latest" }
foreach ($arch in @("x64", "arm64")) {
$feed = "dist/$feedPrefix-win-$arch.yml"
if (!(Test-Path $feed)) {
throw "Missing $feed"
}
}
unsigned-windows-build:
name: Unsigned Windows Build (testing)
runs-on: windows-latest
if: github.event_name == 'workflow_dispatch' && inputs.windows_release_tag != ''
permissions:
contents: write
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
# `build:win:nopublish` shares build:win's recipe (compile + electron-builder
# + packaged-app smoke + update-feed write/validate) but forces
# `--publish never`: electron-builder's implicit CI publish would otherwise
# try to attach to the `windows_release_tag` release and refuse any release
# created >2h ago. The packaged-app launch smoke now skips the arm64 binary
# on this x64 runner (it can't be executed natively) instead of crashing
# with "spawn UNKNOWN", so it is safe to run here. Assets are attached by the
# gh step below (gh release upload --clobber works on an existing release).
- run: npm run build:win:nopublish
- name: Upload unsigned Windows installers to the release
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
$tag = "${{ inputs.windows_release_tag }}"
$assets = @(
Get-ChildItem -Path dist -Filter "TaskWraith-*-win-*-setup.exe"
Get-ChildItem -Path dist -Filter "TaskWraith-*-win-*-setup.exe.blockmap"
Get-ChildItem -Path dist -Filter "latest-win-*.yml"
) | ForEach-Object { $_.FullName }
if ($assets.Count -lt 2) {
throw "Expected Windows installers in dist/, found $($assets.Count)."
}
Write-Host "Uploading $($assets.Count) asset(s) to release $tag"
gh release upload $tag @assets --clobber
unsigned-linux-build:
name: Unsigned Linux Build (testing)
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' && inputs.linux_release_tag != ''
permissions:
contents: write
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
# AppImage + deb only — snap needs snapcraft (absent on the default
# runner). `--publish never` stops electron-builder's implicit CI publish
# from trying to attach to a release created >2h ago; the gh step below
# attaches the assets (gh release upload --clobber on an existing release).
- run: npm run build:linux:nopublish
- name: Upload unsigned Linux artifacts to the release
run: |
set -euo pipefail
tag="${{ inputs.linux_release_tag }}"
shopt -s nullglob
assets=(dist/*.AppImage dist/*.deb dist/latest-linux*.yml)
if [ ${#assets[@]} -lt 1 ]; then
echo "Expected Linux artifacts in dist/, found none."
exit 1
fi
echo "Uploading ${#assets[@]} asset(s) to release $tag"
gh release upload "$tag" "${assets[@]}" --clobber