Skip to content

Commit f3a9afc

Browse files
committed
feat(ci): add multi-platform build and release workflow
- Trigger releases on `v*` tags to align with semantic versioning. - Enable manual `workflow_dispatch` to allow on-demand releases. - Automate version bumping in project files to ensure consistency. - Introduce dedicated build jobs for macOS (universal) and Linux (x64) to expand platform support. - Dynamically generate `latest.json` with update information for all platforms to enable comprehensive auto-updates. - Add a note to macOS releases about code signing to inform users.
1 parent 6c9677f commit f3a9afc

1 file changed

Lines changed: 257 additions & 30 deletions

File tree

.github/workflows/build-release.yml

Lines changed: 257 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,14 @@ name: Build and Release
22

33
on:
44
push:
5-
branches:
6-
- main
5+
tags:
6+
- 'v*'
7+
workflow_dispatch:
8+
inputs:
9+
version:
10+
description: 'Version to release (e.g., 1.1.0)'
11+
required: true
12+
type: string
713

814
permissions:
915
contents: write
@@ -13,6 +19,9 @@ env:
1319
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
1420

1521
jobs:
22+
# ===========================================
23+
# 1. Create Release + Version Bump
24+
# ===========================================
1625
create-release:
1726
runs-on: ubuntu-latest
1827
outputs:
@@ -21,12 +30,48 @@ jobs:
2130
steps:
2231
- name: Checkout
2332
uses: actions/checkout@v4
33+
with:
34+
fetch-depth: 0
35+
token: ${{ secrets.GITHUB_TOKEN }}
2436

25-
- name: Get version from tauri.conf.json
37+
- name: Get version
2638
id: get_version
2739
run: |
28-
VERSION=$(jq -r '.version' src-tauri/tauri.conf.json)
40+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
41+
VERSION="${{ github.event.inputs.version }}"
42+
else
43+
VERSION="${GITHUB_REF#refs/tags/v}"
44+
fi
45+
VERSION="${VERSION#v}"
2946
echo "version=$VERSION" >> $GITHUB_OUTPUT
47+
echo "Releasing version: $VERSION"
48+
49+
- name: Bump version in project files
50+
run: |
51+
chmod +x ./scripts/bump-version.sh
52+
./scripts/bump-version.sh "${{ steps.get_version.outputs.version }}"
53+
54+
- name: Commit version bump
55+
run: |
56+
git config user.name "github-actions[bot]"
57+
git config user.email "github-actions[bot]@users.noreply.github.com"
58+
59+
if git diff --quiet package.json src-tauri/tauri.conf.json src-tauri/Cargo.toml; then
60+
echo "No version changes to commit"
61+
else
62+
git add package.json src-tauri/tauri.conf.json src-tauri/Cargo.toml
63+
git commit -m "chore: bump version to ${{ steps.get_version.outputs.version }} [skip ci]"
64+
git push origin HEAD:main
65+
fi
66+
67+
- name: Create tag (for workflow_dispatch)
68+
if: github.event_name == 'workflow_dispatch'
69+
run: |
70+
TAG_NAME="v${{ steps.get_version.outputs.version }}"
71+
if ! git tag -l | grep -q "^${TAG_NAME}$"; then
72+
git tag -a "${TAG_NAME}" -m "Release ${{ steps.get_version.outputs.version }}"
73+
git push origin "${TAG_NAME}"
74+
fi
3075
3176
- name: Create draft release
3277
id: create_release
@@ -36,13 +81,24 @@ jobs:
3681
name: ZeroLimit v${{ steps.get_version.outputs.version }}
3782
draft: true
3883
generate_release_notes: true
84+
body: |
85+
86+
> ⚠️ **Note**: macOS builds won't be code-signed unless you add Apple signing secrets. Unsigned macOS apps require users to run:
87+
> ```bash
88+
> xattr -cr /Applications/ZeroLimit.app
89+
> ```
3990
91+
# ===========================================
92+
# 2. Build Windows x64
93+
# ===========================================
4094
build-windows-x64:
4195
needs: create-release
4296
runs-on: windows-latest
4397
steps:
4498
- name: Checkout
4599
uses: actions/checkout@v4
100+
with:
101+
ref: main
46102

47103
- name: Setup Node.js
48104
uses: actions/setup-node@v4
@@ -95,15 +151,20 @@ jobs:
95151
- name: Upload signatures for latest.json
96152
uses: actions/upload-artifact@v4
97153
with:
98-
name: signatures-x64
154+
name: signatures-windows-x64
99155
path: src-tauri/target/x86_64-pc-windows-msvc/release/bundle/nsis/*.sig
100156

157+
# ===========================================
158+
# 3. Build Windows ARM64
159+
# ===========================================
101160
build-windows-arm64:
102161
needs: create-release
103162
runs-on: windows-latest
104163
steps:
105164
- name: Checkout
106165
uses: actions/checkout@v4
166+
with:
167+
ref: main
107168

108169
- name: Setup Node.js
109170
uses: actions/setup-node@v4
@@ -158,51 +219,217 @@ jobs:
158219
- name: Upload signatures for latest.json
159220
uses: actions/upload-artifact@v4
160221
with:
161-
name: signatures-arm64
222+
name: signatures-windows-arm64
162223
path: src-tauri/target/aarch64-pc-windows-msvc/release/bundle/nsis/*.sig
163224

225+
# ===========================================
226+
# 4. Build macOS (Universal: x64 + ARM64)
227+
# ===========================================
228+
build-macos:
229+
needs: create-release
230+
runs-on: macos-latest
231+
steps:
232+
- name: Checkout
233+
uses: actions/checkout@v4
234+
with:
235+
ref: main
236+
237+
- name: Setup Node.js
238+
uses: actions/setup-node@v4
239+
with:
240+
node-version: 20
241+
242+
- name: Setup pnpm
243+
uses: pnpm/action-setup@v4
244+
245+
- name: Setup Rust
246+
uses: dtolnay/rust-toolchain@stable
247+
with:
248+
targets: aarch64-apple-darwin,x86_64-apple-darwin
249+
250+
- name: Cache Cargo
251+
uses: actions/cache@v4
252+
with:
253+
path: |
254+
~/.cargo/bin/
255+
~/.cargo/registry/index/
256+
~/.cargo/registry/cache/
257+
~/.cargo/git/db/
258+
src-tauri/target/
259+
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
260+
restore-keys: |
261+
${{ runner.os }}-cargo-
262+
263+
- name: Install frontend dependencies
264+
run: pnpm install
265+
266+
- name: Build Tauri (Apple Silicon)
267+
run: pnpm tauri build --target aarch64-apple-darwin
268+
269+
- name: Build Tauri (Intel)
270+
run: pnpm tauri build --target x86_64-apple-darwin
271+
272+
- name: Upload artifacts to release
273+
uses: softprops/action-gh-release@v2
274+
with:
275+
tag_name: v${{ needs.create-release.outputs.version }}
276+
draft: true
277+
files: |
278+
src-tauri/target/aarch64-apple-darwin/release/bundle/dmg/*.dmg
279+
src-tauri/target/aarch64-apple-darwin/release/bundle/macos/*.app.tar.gz
280+
src-tauri/target/aarch64-apple-darwin/release/bundle/macos/*.app.tar.gz.sig
281+
src-tauri/target/x86_64-apple-darwin/release/bundle/dmg/*.dmg
282+
src-tauri/target/x86_64-apple-darwin/release/bundle/macos/*.app.tar.gz
283+
src-tauri/target/x86_64-apple-darwin/release/bundle/macos/*.app.tar.gz.sig
284+
285+
- name: Upload signatures for latest.json
286+
uses: actions/upload-artifact@v4
287+
with:
288+
name: signatures-macos
289+
path: |
290+
src-tauri/target/aarch64-apple-darwin/release/bundle/macos/*.app.tar.gz.sig
291+
src-tauri/target/x86_64-apple-darwin/release/bundle/macos/*.app.tar.gz.sig
292+
293+
# ===========================================
294+
# 5. Build Linux x64
295+
# ===========================================
296+
build-linux:
297+
needs: create-release
298+
runs-on: ubuntu-22.04
299+
steps:
300+
- name: Checkout
301+
uses: actions/checkout@v4
302+
with:
303+
ref: main
304+
305+
- name: Install system dependencies
306+
run: |
307+
sudo apt-get update
308+
sudo apt-get install -y \
309+
libwebkit2gtk-4.1-dev \
310+
libappindicator3-dev \
311+
librsvg2-dev \
312+
patchelf \
313+
libssl-dev \
314+
libgtk-3-dev \
315+
libsoup-3.0-dev \
316+
javascriptcoregtk-4.1-dev
317+
318+
- name: Setup Node.js
319+
uses: actions/setup-node@v4
320+
with:
321+
node-version: 20
322+
323+
- name: Setup pnpm
324+
uses: pnpm/action-setup@v4
325+
326+
- name: Setup Rust
327+
uses: dtolnay/rust-toolchain@stable
328+
329+
- name: Cache Cargo
330+
uses: actions/cache@v4
331+
with:
332+
path: |
333+
~/.cargo/bin/
334+
~/.cargo/registry/index/
335+
~/.cargo/registry/cache/
336+
~/.cargo/git/db/
337+
src-tauri/target/
338+
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
339+
restore-keys: |
340+
${{ runner.os }}-cargo-
341+
342+
- name: Install frontend dependencies
343+
run: pnpm install
344+
345+
- name: Build Tauri
346+
run: pnpm tauri build
347+
348+
- name: Upload artifacts to release
349+
uses: softprops/action-gh-release@v2
350+
with:
351+
tag_name: v${{ needs.create-release.outputs.version }}
352+
draft: true
353+
files: |
354+
src-tauri/target/release/bundle/deb/*.deb
355+
src-tauri/target/release/bundle/rpm/*.rpm
356+
src-tauri/target/release/bundle/appimage/*.AppImage
357+
src-tauri/target/release/bundle/appimage/*.AppImage.tar.gz
358+
src-tauri/target/release/bundle/appimage/*.AppImage.tar.gz.sig
359+
360+
- name: Upload signatures for latest.json
361+
uses: actions/upload-artifact@v4
362+
with:
363+
name: signatures-linux
364+
path: src-tauri/target/release/bundle/appimage/*.AppImage.tar.gz.sig
365+
366+
# ===========================================
367+
# 6. Publish Release + Generate latest.json
368+
# ===========================================
164369
publish-release:
165-
needs: [create-release, build-windows-x64, build-windows-arm64]
370+
needs: [create-release, build-windows-x64, build-windows-arm64, build-macos, build-linux]
166371
runs-on: ubuntu-latest
167372
steps:
168373
- name: Checkout
169374
uses: actions/checkout@v4
170375

171-
- name: Download signatures
376+
- name: Download all signatures
172377
uses: actions/download-artifact@v4
173378
with:
174379
pattern: signatures-*
175380
merge-multiple: true
176381
path: signatures
177382

383+
- name: List signatures (debug)
384+
run: find signatures -type f | sort
385+
178386
- name: Generate latest.json
179387
run: |
180388
VERSION="${{ needs.create-release.outputs.version }}"
181389
REPO="${{ github.repository }}"
182390
DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
183391
184-
# Read signature files
185-
# Use specific version to avoid matching multiple files if present
186-
X64_SIG=$(cat signatures/*_${VERSION}_x64*.exe.sig | head -n 1)
187-
ARM64_SIG=$(cat signatures/*_${VERSION}_arm64*.exe.sig | head -n 1)
188-
189-
cat > latest.json << EOF
190-
{
191-
"version": "$VERSION",
192-
"notes": "See release notes on GitHub",
193-
"pub_date": "$DATE",
194-
"platforms": {
195-
"windows-x86_64": {
196-
"signature": "$X64_SIG",
197-
"url": "https://github.com/$REPO/releases/download/v$VERSION/ZeroLimit_${VERSION}_x64-setup.exe"
198-
},
199-
"windows-aarch64": {
200-
"signature": "$ARM64_SIG",
201-
"url": "https://github.com/$REPO/releases/download/v$VERSION/ZeroLimit_${VERSION}_arm64-setup.exe"
202-
}
203-
}
204-
}
205-
EOF
392+
# Read signature files (use find to be resilient to naming variations)
393+
WIN_X64_SIG=$(find signatures -name "*x64*setup*.sig" -o -name "*x86_64*setup*.sig" | head -1 | xargs cat 2>/dev/null || echo "")
394+
WIN_ARM64_SIG=$(find signatures -name "*arm64*setup*.sig" -o -name "*aarch64*setup*.sig" | head -1 | xargs cat 2>/dev/null || echo "")
395+
MACOS_ARM64_SIG=$(find signatures -path "*aarch64-apple*" -name "*.sig" | head -1 | xargs cat 2>/dev/null || echo "")
396+
MACOS_X64_SIG=$(find signatures -path "*x86_64-apple*" -name "*.sig" | head -1 | xargs cat 2>/dev/null || echo "")
397+
LINUX_SIG=$(find signatures -name "*.AppImage.tar.gz.sig" | head -1 | xargs cat 2>/dev/null || echo "")
398+
399+
# Build platforms JSON dynamically
400+
PLATFORMS="{"
401+
402+
if [ -n "$WIN_X64_SIG" ]; then
403+
PLATFORMS="$PLATFORMS\"windows-x86_64\":{\"signature\":\"$WIN_X64_SIG\",\"url\":\"https://github.com/$REPO/releases/download/v$VERSION/ZeroLimit_${VERSION}_x64-setup.exe\"},"
404+
fi
405+
406+
if [ -n "$WIN_ARM64_SIG" ]; then
407+
PLATFORMS="$PLATFORMS\"windows-aarch64\":{\"signature\":\"$WIN_ARM64_SIG\",\"url\":\"https://github.com/$REPO/releases/download/v$VERSION/ZeroLimit_${VERSION}_arm64-setup.exe\"},"
408+
fi
409+
410+
if [ -n "$MACOS_ARM64_SIG" ]; then
411+
MACOS_ARM64_FILENAME=$(find signatures -path "*aarch64-apple*" -name "*.sig" | head -1 | xargs basename | sed 's/.sig$//')
412+
PLATFORMS="$PLATFORMS\"darwin-aarch64\":{\"signature\":\"$MACOS_ARM64_SIG\",\"url\":\"https://github.com/$REPO/releases/download/v$VERSION/$MACOS_ARM64_FILENAME\"},"
413+
fi
414+
415+
if [ -n "$MACOS_X64_SIG" ]; then
416+
MACOS_X64_FILENAME=$(find signatures -path "*x86_64-apple*" -name "*.sig" | head -1 | xargs basename | sed 's/.sig$//')
417+
PLATFORMS="$PLATFORMS\"darwin-x86_64\":{\"signature\":\"$MACOS_X64_SIG\",\"url\":\"https://github.com/$REPO/releases/download/v$VERSION/$MACOS_X64_FILENAME\"},"
418+
fi
419+
420+
if [ -n "$LINUX_SIG" ]; then
421+
LINUX_FILENAME=$(find signatures -name "*.AppImage.tar.gz.sig" | head -1 | xargs basename | sed 's/.sig$//')
422+
PLATFORMS="$PLATFORMS\"linux-x86_64\":{\"signature\":\"$LINUX_SIG\",\"url\":\"https://github.com/$REPO/releases/download/v$VERSION/$LINUX_FILENAME\"},"
423+
fi
424+
425+
# Remove trailing comma and close
426+
PLATFORMS="${PLATFORMS%,}}"
427+
428+
# Write latest.json
429+
echo "{\"version\":\"$VERSION\",\"notes\":\"See release notes on GitHub\",\"pub_date\":\"$DATE\",\"platforms\":$PLATFORMS}" | jq '.' > latest.json
430+
431+
echo "Generated latest.json:"
432+
cat latest.json
206433
207434
- name: Upload latest.json
208435
uses: softprops/action-gh-release@v2

0 commit comments

Comments
 (0)