-
Notifications
You must be signed in to change notification settings - Fork 7
305 lines (277 loc) Β· 13.9 KB
/
Copy pathtauri-build.yml
File metadata and controls
305 lines (277 loc) Β· 13.9 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
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# Desktop bundles β manual or tagged releases (does not block web CI).
# Produces installable artifacts per OS under Actions β workflow run β Artifacts.
name: Tauri desktop build
on:
workflow_dispatch:
push:
tags:
- 'v*'
permissions:
contents: read
concurrency:
group: tauri-${{ github.ref }}
cancel-in-progress: true
jobs:
verify-release-tag:
name: Verify release tag
if: >-
${{ github.event_name == 'push' && github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/v') }}
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check out the tagged source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Verify GitHub signatures for the release tag
env:
GITHUB_EVENT_NAME: ${{ github.event_name }}
GITHUB_EVENT_PATH: ${{ github.event_path }}
GITHUB_REF_NAME: ${{ github.ref_name }}
GITHUB_REF_TYPE: ${{ github.ref_type }}
GITHUB_REPOSITORY: ${{ github.repository }}
GITHUB_TOKEN: ${{ github.token }}
run: node scripts/signing/verify-github-signatures.mjs
bundle:
name: Bundle (${{ matrix.os }})
needs: [verify-release-tag]
if: >-
${{
always() &&
!cancelled() &&
(
github.event_name == 'workflow_dispatch' ||
needs.verify-release-tag.result == 'success'
)
}}
runs-on: ${{ matrix.os }}
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-22.04
- os: windows-latest
# QNBS-v3: macos-13 (the last Intel/x86_64 hosted runner) removed 2026-07-28 -- it never
# actually provisions a runner (job sits in "queued" indefinitely; timeout-minutes never
# applies since that only counts once a job starts, so 3 consecutive real runs each hung
# the full 24h GitHub Actions queue ceiling before auto-cancelling). GitHub has been
# retiring Intel-hosted macOS runners; macos-latest (Apple Silicon) is the only macOS
# bundle target until a working Intel option exists again. Native Intel-Mac builds are
# tracked as a re-opened follow-up, not silently dropped.
- os: macos-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# QNBS-v3: composite action handles pnpm/node setup + frozen install.
- uses: ./.github/actions/setup
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
with:
workspaces: src-tauri
cache-all-crates: true
# QNBS-v3: bump prefix-key when changing Rust channel or after major Cargo.lock churn
prefix-key: "v1"
- name: Install Linux dependencies (WebKitGTK)
if: contains(matrix.os, 'ubuntu')
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf
- name: Install macOS dependencies (create-dmg)
if: contains(matrix.os, 'macos')
run: brew install create-dmg
- name: Build Tauri app
shell: bash
env:
# Updater signing (minisign) β required for auto-update functionality
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
# QNBS-v3: macOS/Windows code signing env vars are intentionally omitted
# until Apple Developer ID and Authenticode certificates are provisioned.
# Add APPLE_CERTIFICATE, APPLE_CERTIFICATE_PASSWORD, APPLE_ID,
# APPLE_TEAM_ID, APPLE_PASSWORD, WINDOWS_CERTIFICATE,
# WINDOWS_CERTIFICATE_PASSWORD here when ready.
run: |
# QNBS-v3: Strict mode for reliable error handling.
# Best Practice 2026: set -euo pipefail catches undefined vars and pipe failures early.
set -euo pipefail
# QNBS-v3: Skip updater signing for workflow_dispatch test builds.
# Tagged releases (v*) require valid secrets for both signing and updater.
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
unset TAURI_SIGNING_PRIVATE_KEY
unset TAURI_SIGNING_PRIVATE_KEY_PASSWORD
# Disable updater artifacts when no private key is available;
# otherwise Tauri errors: "public key found, but no private key".
jq '.bundle.createUpdaterArtifacts = false' src-tauri/tauri.conf.json > src-tauri/tauri.conf.json.tmp
mv src-tauri/tauri.conf.json.tmp src-tauri/tauri.conf.json
fi
# QNBS-v3: Validate jq succeeded before proceeding
if ! command -v jq &>/dev/null; then
echo "::error::jq is required for Tauri build configuration but not installed"
exit 1
fi
echo "Building Tauri app for ${{ matrix.os }}..."
pnpm exec tauri build
echo "Tauri build completed successfully"
- name: Upload bundle directory
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: tauri-bundle-${{ matrix.os }}
path: src-tauri/target/release/bundle/
if-no-files-found: warn
retention-days: 14
# -----------------------------------------------------------------
# GitHub Release: attach Linux / Windows / macOS installers (tags v* only)
# -----------------------------------------------------------------
release:
name: GitHub Release
needs: [bundle]
if: >-
${{ github.event_name == 'push' && github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/v') }}
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: write
steps:
- name: Check out the exact release tag
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.ref }}
fetch-depth: 1
persist-credentials: false
- name: Download all bundle artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: tauri-bundle-*
path: downloaded
merge-multiple: true
- name: Extract deterministic release notes
run: |
set -euo pipefail
VERSION="${GITHUB_REF_NAME#v}"
awk -v version="$VERSION" '
index($0, "## [" version "] β ") == 1 { in_release = 1 }
in_release && $0 ~ /^## \[/ && index($0, "## [" version "] β ") != 1 { exit }
in_release { print }
' CHANGELOG.md > release-notes.md
test -s release-notes.md
grep -Fq "## [$VERSION] β " release-notes.md
if grep -Eiq '(#332|#341).*(closed|resolved|complete|shipped|fixed)|(#332|#341).*(closure|done)' release-notes.md; then
echo "::error::Release notes claim #332 or #341 closure"
exit 1
fi
if grep -Eiq '(macOS|Mac)[^\n]*(Intel|x86_64)[^\n]*(supported|available|provided|published|built)|Intel[^\n]*(macOS|Mac)[^\n]*(supported|available|provided|published|built)' release-notes.md; then
echo "::error::Release notes claim unsupported Intel macOS support"
exit 1
fi
- name: Collect release assets
id: collect
run: |
mkdir -p release-assets
# QNBS-v3: *.sig and *.app.tar.gz included β sig files feed latest.json; .app.tar.gz is
# the macOS updater bundle (Tauri downloads this to apply updates, not the .dmg installer).
find downloaded -type f \( \
-name '*.deb' -o -name '*.AppImage' -o -name '*.rpm' \
-o -name '*.msi' -o -name '*.exe' \
-o -name '*.dmg' -o -name '*.app.tar.gz' -o -name '*.sig' \
\) -exec cp {} release-assets/ \;
echo "Files to upload:" && ls -la release-assets/ || true
if [ -z "$(ls -A release-assets 2>/dev/null)" ]; then
echo "has_assets=false" >> "$GITHUB_OUTPUT"
echo "::warning::No bundle files found to attach. Check Tauri bundle output paths."
else
echo "has_assets=true" >> "$GITHUB_OUTPUT"
fi
- name: Create GitHub Release
if: steps.collect.outputs.has_assets == 'true'
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
with:
files: release-assets/*
body_path: release-notes.md
generate_release_notes: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Generate latest.json for auto-updater
if: steps.collect.outputs.has_assets == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# QNBS-v3: Tauri v2 updater manifest.
# Version must NOT have a 'v' prefix (matches tauri.conf.json version field).
# Platform keys: linux-x86_64, windows-x86_64, darwin-aarch64, darwin-x86_64.
VERSION="${GITHUB_REF_NAME#v}" # strip 'v': v1.22.1 β 1.22.1
TAG="${GITHUB_REF_NAME}"
REPO_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}"
PUB_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
LINUX_URL="" LINUX_SIG=""
WIN_URL="" WIN_SIG=""
MAC_AARCH64_URL="" MAC_AARCH64_SIG=""
MAC_X64_URL="" MAC_X64_SIG=""
for SIG_FILE in release-assets/*.sig; do
[ -f "$SIG_FILE" ] || continue
BASE="${SIG_FILE%.sig}"
FNAME="$(basename "$BASE")"
# QNBS-v3: GitHub normalizes spaces in uploaded asset names to dots (e.g.
# "WorldScript Studio_*.AppImage" β "WorldScript.Studio_*.AppImage"). The bundle file on
# disk still has the space, so the updater URL MUST use the normalized name or it 404s.
URLNAME="${FNAME// /.}"
SIG_CONTENT="$(cat "$SIG_FILE")"
case "$FNAME" in
*.AppImage)
LINUX_URL="${REPO_URL}/${URLNAME}"; LINUX_SIG="$SIG_CONTENT" ;;
*-setup.exe)
# NSIS installer β preferred Windows updater format
WIN_URL="${REPO_URL}/${URLNAME}"; WIN_SIG="$SIG_CONTENT" ;;
*.msi)
# MSI fallback if no NSIS sig collected yet
[ -z "$WIN_SIG" ] && { WIN_URL="${REPO_URL}/${URLNAME}"; WIN_SIG="$SIG_CONTENT"; } ;;
*_aarch64.app.tar.gz)
# QNBS-v3: macOS updater bundle is .app.tar.gz (not .dmg).
# .dmg is the user-facing installer; .app.tar.gz is what Tauri downloads for in-app updates.
# aarch64 = macos-latest ARM runner. x64 has no runner in the matrix currently
# (macos-13 removed, see the matrix comment above) -- this case is unreachable
# until a working Intel runner is restored, kept so a future re-add needs no
# changes here.
MAC_AARCH64_URL="${REPO_URL}/${URLNAME}"; MAC_AARCH64_SIG="$SIG_CONTENT" ;;
*_x64.app.tar.gz)
MAC_X64_URL="${REPO_URL}/${URLNAME}"; MAC_X64_SIG="$SIG_CONTENT" ;;
*.app.tar.gz)
# Fallback for generic .app.tar.gz (older Tauri versions)
MAC_AARCH64_URL="${REPO_URL}/${URLNAME}"; MAC_AARCH64_SIG="$SIG_CONTENT" ;;
esac
done
# QNBS-v3: report per-arch sig coverage so a half-failed matrix (e.g. macos-13 dropped its
# bundle while macos-latest succeeded) is diagnosable instead of a bare "no sigs" failure.
MISSING=""
[ -z "$LINUX_SIG" ] && MISSING="${MISSING} linux-x86_64"
[ -z "$WIN_SIG" ] && MISSING="${MISSING} windows-x86_64"
[ -z "$MAC_AARCH64_SIG" ] && MISSING="${MISSING} darwin-aarch64"
[ -z "$MAC_X64_SIG" ] && MISSING="${MISSING} darwin-x86_64"
[ -n "$MISSING" ] && echo "::warning::No signed bundle for platform(s):${MISSING}. They will be omitted from latest.json."
# Hard-fail only if NO platform produced a signed bundle.
if [ -z "$LINUX_SIG" ] && [ -z "$WIN_SIG" ] && [ -z "$MAC_AARCH64_SIG" ] && [ -z "$MAC_X64_SIG" ]; then
echo "::error::No signed bundles found in release-assets/. Verify TAURI_SIGNING_PRIVATE_KEY secret and that createUpdaterArtifacts=true."
exit 1
fi
jq -n \
--arg version "$VERSION" \
--arg pub_date "$PUB_DATE" \
--arg linux_url "$LINUX_URL" --arg linux_sig "$LINUX_SIG" \
--arg win_url "$WIN_URL" --arg win_sig "$WIN_SIG" \
--arg mac_aarch64_url "$MAC_AARCH64_URL" --arg mac_aarch64_sig "$MAC_AARCH64_SIG" \
--arg mac_x64_url "$MAC_X64_URL" --arg mac_x64_sig "$MAC_X64_SIG" \
'{version:$version, notes:"See release notes", pub_date:$pub_date,
platforms:({}
| if $linux_sig!="" then .+{"linux-x86_64": {signature:$linux_sig, url:$linux_url}} else . end
| if $win_sig!="" then .+{"windows-x86_64":{signature:$win_sig, url:$win_url}} else . end
| if $mac_aarch64_sig!="" then .+{"darwin-aarch64":{signature:$mac_aarch64_sig, url:$mac_aarch64_url}} else . end
| if $mac_x64_sig!="" then .+{"darwin-x86_64": {signature:$mac_x64_sig, url:$mac_x64_url}} else . end)}' \
> latest.json
echo "Generated latest.json:"
cat latest.json
# QNBS-v3: this job has no actions/checkout, so gh has no local git context β pass --repo
# explicitly or `gh release upload` aborts with "fatal: not a git repository" (v1.23.0 fix).
gh release upload "$TAG" latest.json --clobber --repo "$GITHUB_REPOSITORY"