-
Notifications
You must be signed in to change notification settings - Fork 0
204 lines (182 loc) · 8.67 KB
/
Copy pathrelease.yml
File metadata and controls
204 lines (182 loc) · 8.67 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
name: Release
on:
push:
branches: [main]
permissions:
contents: write
# Two quick pushes must not race each other against the same draft release /
# latest.json. Queue runs instead (no cancel: killing a half-published release
# is worse than waiting).
concurrency:
group: release
jobs:
# Only release when the version in tauri.conf.json doesn't already have a tag.
check-version:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
should_release: ${{ steps.check_tag.outputs.exists == 'false' }}
steps:
- uses: actions/checkout@v4
- name: Extract version
id: version
run: echo "version=$(jq -r '.version' src-tauri/tauri.conf.json)" >> "$GITHUB_OUTPUT"
- name: Check if tag already exists
id: check_tag
run: |
if git ls-remote --tags origin "refs/tags/v${{ steps.version.outputs.version }}" | grep -q .; then
echo "exists=true" >> "$GITHUB_OUTPUT"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
fi
release:
needs: check-version
if: needs.check-version.outputs.should_release == 'true'
strategy:
fail-fast: false
matrix:
include:
# macOS: one universal binary (Intel + Apple Silicon) — avoids
# per-arch updater-artifact name collisions on the release.
- platform: macos-14
args: --target universal-apple-darwin
- platform: ubuntu-22.04
args: ""
- platform: windows-latest
args: ""
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ contains(matrix.platform, 'macos') && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
- name: Install Linux dependencies
if: contains(matrix.platform, 'ubuntu')
run: |
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev \
libappindicator3-dev \
librsvg2-dev \
patchelf \
libasound2-dev \
libgtk-3-dev \
libsoup-3.0-dev \
libjavascriptcoregtk-4.1-dev \
libxdo-dev
- name: Run tests
working-directory: src-tauri
run: cargo test
# Builds installers + signed updater artifacts (.tar.gz/.nsis.zip + .sig),
# creates/updates the GitHub Release, uploads all assets, and generates
# latest.json (the updater endpoint) — because createUpdaterArtifacts is on
# and the signing key is provided.
- name: Build and release
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Updater (minisign) signing — required for OTA on all platforms.
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
# Apple Developer-ID signing + notarization (macOS only; ignored elsewhere).
# tauri-action signs + notarizes when these are present.
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
with:
projectPath: src-tauri
tagName: v${{ needs.check-version.outputs.version }}
releaseName: MegaBrain v${{ needs.check-version.outputs.version }}
releaseBody: "Download the installer for your platform below. Existing installs update automatically."
# Build into a DRAFT release so it never becomes "latest" with a partial
# latest.json mid-build. The finalize-manifest job publishes it once the
# manifest is complete, so the updater only ever sees finished releases.
releaseDraft: true
prerelease: false
args: ${{ matrix.args }}
# Each matrix job above runs tauri-action, which generates its own latest.json
# containing ONLY that job's platform — so the three jobs clobber each other and
# whichever finishes last wins, leaving a manifest missing the other platforms.
# This final job runs once after all builds, rebuilds latest.json from every
# platform's signature, and uploads it with --clobber so OTA sees all platforms.
finalize-manifest:
needs: [check-version, release]
if: needs.check-version.outputs.should_release == 'true'
runs-on: ubuntu-latest
steps:
- name: Rebuild latest.json from all platform signatures
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
VERSION: ${{ needs.check-version.outputs.version }}
run: |
set -euo pipefail
TAG="v$VERSION"
BASE="https://github.com/$REPO/releases/download/$TAG"
PUBDATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
# All asset names on the release (excludes nothing; we match by suffix).
mapfile -t ASSETS < <(gh release view "$TAG" --repo "$REPO" --json assets -q '.assets[].name')
# Find the updater bundle for a platform by suffix (.sig files never match
# these because their suffix is .sig, not the bundle extension).
find_asset() {
local suffix="$1" a
for a in "${ASSETS[@]}"; do
case "$a" in *"$suffix") echo "$a"; return 0 ;; esac
done
return 0
}
MAC="$(find_asset '.app.tar.gz')"
LINUX="$(find_asset '.AppImage')"
# Tauri v2's NSIS updater artifact is the -setup.exe itself (with a
# sibling .sig), not a .nsis.zip. Fall back to .nsis.zip just in case.
WIN="$(find_asset '-setup.exe')"
[ -z "$WIN" ] && WIN="$(find_asset '.nsis.zip')"
# Pull every signature file so we can inline them into the manifest.
gh release download "$TAG" --repo "$REPO" --pattern '*.sig' --dir sigs --clobber || true
PLATFORMS='{}'
# Add both the plain target key (e.g. darwin-aarch64) and the bundle-
# suffixed key the updater prefers (e.g. darwin-aarch64-app), pointing at
# the same artifact, so any tauri-plugin-updater version resolves it.
add_platform() {
local name="$1" suffix="$2" asset="$3"
if [ -n "$asset" ] && [ -f "sigs/$asset.sig" ]; then
local sig entry; sig="$(cat "sigs/$asset.sig")"
entry="$(jq -n --arg u "$BASE/$asset" --arg s "$sig" '{signature: $s, url: $u}')"
PLATFORMS="$(echo "$PLATFORMS" | jq --arg n "$name" --argjson e "$entry" '. + {($n): $e}')"
PLATFORMS="$(echo "$PLATFORMS" | jq --arg n "$name-$suffix" --argjson e "$entry" '. + {($n): $e}')"
echo "added $name (+ $name-$suffix) -> $asset"
else
echo "skipped $name (asset or signature missing: '$asset')"
fi
}
# macOS ships a single universal bundle; both arch keys point to it.
add_platform "darwin-aarch64" "app" "$MAC"
add_platform "darwin-x86_64" "app" "$MAC"
add_platform "linux-x86_64" "appimage" "$LINUX"
add_platform "windows-x86_64" "nsis" "$WIN"
jq -n \
--arg version "$VERSION" \
--arg pubdate "$PUBDATE" \
--argjson platforms "$PLATFORMS" \
'{version: $version, notes: "See the release page for details.", pub_date: $pubdate, platforms: $platforms}' \
> latest.json
echo "--- latest.json ---"
cat latest.json
# Refuse to publish a manifest missing any platform: OTA clients on a
# missing platform would silently stop seeing updates (asset-name
# drift has caused exactly this before). The release stays a draft so
# the fix is to re-run, not to roll back a live manifest.
for key in darwin-aarch64 darwin-x86_64 linux-x86_64 windows-x86_64; do
if ! jq -e --arg k "$key" '.platforms | has($k)' latest.json >/dev/null; then
echo "::error::latest.json is missing platform '$key' — leaving the release as a draft"
exit 1
fi
done
gh release upload "$TAG" latest.json --repo "$REPO" --clobber
# Manifest is complete — now publish the draft and mark it latest, so the
# updater flips to this version only once every platform is present.
gh release edit "$TAG" --repo "$REPO" --draft=false --latest