Skip to content

Commit 68d557d

Browse files
committed
ci: add GitHub Actions workflows for multi-platform builds
- Add build-linux.yml for Ubuntu/Linux x86_64 builds - Installs required system dependencies (webkit2gtk, GTK3, etc.) - Builds Tauri application for Linux platform - Uploads build artifacts for distribution - Add build-macos.yml for macOS Intel and Apple Silicon builds - Supports both x86_64 and aarch64 architectures - Handles Apple certificate import and code signing - Creates notarized DMG installers - Includes Homebrew cask generation - Allows skipping builds and using previous artifacts - Add release.yml for automated releases - Triggers on version tags (v*) - Orchestrates builds across all platforms - Creates GitHub releases with all artifacts - Supports manual workflow dispatch with version input
1 parent 9c253ba commit 68d557d

3 files changed

Lines changed: 463 additions & 0 deletions

File tree

.github/workflows/build-linux.yml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
name: Build Linux
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches: [main, test-linux-workflow]
7+
8+
jobs:
9+
build:
10+
name: Build Linux x86_64
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- name: Install system dependencies
17+
run: |
18+
sudo apt-get update
19+
sudo apt-get install -y \
20+
pkg-config \
21+
libwebkit2gtk-4.1-dev \
22+
libgtk-3-dev \
23+
libssl-dev \
24+
libayatana-appindicator3-dev \
25+
librsvg2-dev
26+
27+
- name: Setup Rust
28+
uses: dtolnay/rust-toolchain@stable
29+
with:
30+
targets: x86_64-unknown-linux-gnu
31+
32+
- name: Setup Rust cache
33+
uses: Swatinem/rust-cache@v2
34+
with:
35+
workspaces: src-tauri
36+
37+
- name: Setup Bun
38+
uses: oven-sh/setup-bun@v2
39+
40+
- name: Install dependencies
41+
run: bun install
42+
43+
- name: Build Tauri app
44+
run: bun run tauri build --target x86_64-unknown-linux-gnu
45+
46+
- name: Create artifacts directory
47+
run: |
48+
mkdir -p dist/linux-x86_64
49+
cp src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/deb/*.deb dist/linux-x86_64/ || true
50+
cp src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/appimage/*.AppImage dist/linux-x86_64/ || true
51+
52+
# Generate checksums
53+
cd dist/linux-x86_64
54+
sha256sum * > checksums.txt
55+
56+
- name: Upload artifacts
57+
uses: actions/upload-artifact@v4
58+
with:
59+
name: linux-x86_64
60+
path: dist/linux-x86_64/*

.github/workflows/build-macos.yml

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
name: Build macOS
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
skip_build:
7+
description: 'Skip build and use artifacts from a previous run'
8+
required: false
9+
default: false
10+
type: boolean
11+
run_id:
12+
description: 'Run ID to download artifacts from (leave empty for latest)'
13+
required: false
14+
type: string
15+
push:
16+
branches: [main, test-linux-workflow]
17+
18+
jobs:
19+
build:
20+
name: Build macOS ${{ matrix.target }}
21+
if: ${{ !inputs.skip_build }}
22+
runs-on: ${{ matrix.os }}
23+
strategy:
24+
matrix:
25+
include:
26+
- os: macos-13 # Intel
27+
target: x86_64-apple-darwin
28+
arch: x86_64
29+
- os: macos-14 # Apple Silicon
30+
target: aarch64-apple-darwin
31+
arch: aarch64
32+
33+
steps:
34+
- uses: actions/checkout@v4
35+
36+
- name: Setup Rust
37+
uses: dtolnay/rust-toolchain@stable
38+
39+
- name: Setup Rust cache
40+
uses: Swatinem/rust-cache@v2
41+
with:
42+
workspaces: src-tauri
43+
44+
- name: Setup Bun
45+
uses: oven-sh/setup-bun@v2
46+
47+
- name: Install dependencies
48+
run: bun install
49+
50+
- name: Import Apple certificates
51+
env:
52+
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
53+
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
54+
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
55+
run: |
56+
# Create variables
57+
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
58+
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
59+
60+
# Import certificate from secrets
61+
echo -n "$APPLE_CERTIFICATE" | base64 --decode -o $CERTIFICATE_PATH
62+
63+
# Create temporary keychain
64+
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
65+
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
66+
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
67+
68+
# Import certificate to keychain
69+
security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
70+
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
71+
security list-keychain -d user -s $KEYCHAIN_PATH
72+
73+
- name: Build native
74+
run: bun run tauri build
75+
76+
- name: Upload architecture-specific artifacts
77+
uses: actions/upload-artifact@v4
78+
with:
79+
name: macos-${{ matrix.arch }}
80+
path: |
81+
src-tauri/target/release/bundle/macos/Claudia.app
82+
src-tauri/target/release/bundle/dmg/*.dmg
83+
retention-days: 1
84+
85+
universal:
86+
name: Create Universal Binary
87+
needs: [build]
88+
if: ${{ !cancelled() && (needs.build.result == 'success' || needs.build.result == 'skipped') }}
89+
runs-on: macos-latest
90+
steps:
91+
- uses: actions/checkout@v4
92+
93+
- name: Download artifacts from current workflow
94+
if: ${{ !inputs.skip_build }}
95+
uses: actions/download-artifact@v4
96+
with:
97+
pattern: macos-*
98+
path: artifacts
99+
100+
- name: Download artifacts from specific run
101+
if: ${{ inputs.skip_build && inputs.run_id != '' }}
102+
uses: dawidd6/action-download-artifact@v3
103+
with:
104+
workflow: build-macos.yml
105+
run_id: ${{ inputs.run_id }}
106+
name: macos-*
107+
path: artifacts
108+
109+
- name: Download artifacts from latest run
110+
if: ${{ inputs.skip_build && inputs.run_id == '' }}
111+
uses: dawidd6/action-download-artifact@v3
112+
with:
113+
workflow: build-macos.yml
114+
workflow_conclusion: success
115+
name: macos-*
116+
path: artifacts
117+
118+
- name: List downloaded artifacts
119+
run: |
120+
echo "📁 Artifact structure:"
121+
find artifacts -type f -name "*.app" -o -name "*.dmg" | head -20
122+
echo ""
123+
echo "📁 Full directory structure:"
124+
ls -la artifacts/
125+
ls -la artifacts/macos-aarch64/ || echo "macos-aarch64 directory not found"
126+
ls -la artifacts/macos-x86_64/ || echo "macos-x86_64 directory not found"
127+
128+
- name: Import Apple certificates
129+
env:
130+
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
131+
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
132+
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
133+
run: |
134+
# Create variables
135+
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
136+
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
137+
138+
# Import certificate from secrets
139+
echo -n "$APPLE_CERTIFICATE" | base64 --decode -o $CERTIFICATE_PATH
140+
141+
# Create temporary keychain
142+
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
143+
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
144+
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
145+
146+
# Import certificate to keychain
147+
security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
148+
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
149+
security list-keychain -d user -s $KEYCHAIN_PATH
150+
151+
- name: Create universal app
152+
run: |
153+
# Create temp directory
154+
mkdir -p dmg_temp
155+
156+
# Extract zip files if they exist
157+
if [ -f "artifacts/macos-aarch64.zip" ]; then
158+
echo "📦 Extracting macos-aarch64.zip..."
159+
unzip -q artifacts/macos-aarch64.zip -d artifacts/macos-aarch64/
160+
fi
161+
162+
if [ -f "artifacts/macos-x86_64.zip" ]; then
163+
echo "📦 Extracting macos-x86_64.zip..."
164+
unzip -q artifacts/macos-x86_64.zip -d artifacts/macos-x86_64/
165+
fi
166+
167+
# Find the actual app paths
168+
AARCH64_APP=$(find artifacts/macos-aarch64 -name "Claudia.app" -type d | head -1)
169+
X86_64_APP=$(find artifacts/macos-x86_64 -name "Claudia.app" -type d | head -1)
170+
171+
if [ -z "$AARCH64_APP" ] || [ -z "$X86_64_APP" ]; then
172+
echo "❌ Could not find app bundles"
173+
echo "AARCH64_APP: $AARCH64_APP"
174+
echo "X86_64_APP: $X86_64_APP"
175+
exit 1
176+
fi
177+
178+
echo "✅ Found app bundles:"
179+
echo " ARM64: $AARCH64_APP"
180+
echo " x86_64: $X86_64_APP"
181+
182+
# Copy ARM64 app as base
183+
cp -R "$AARCH64_APP" dmg_temp/
184+
185+
# Create universal binary using lipo
186+
lipo -create -output dmg_temp/Claudia.app/Contents/MacOS/claudia \
187+
"$AARCH64_APP/Contents/MacOS/claudia" \
188+
"$X86_64_APP/Contents/MacOS/claudia"
189+
190+
echo "✅ Universal binary created"
191+
lipo -info dmg_temp/Claudia.app/Contents/MacOS/claudia
192+
193+
- name: Sign app bundle
194+
env:
195+
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
196+
run: |
197+
codesign --sign "$APPLE_SIGNING_IDENTITY" \
198+
--timestamp \
199+
--options runtime \
200+
--force \
201+
--deep \
202+
--entitlements src-tauri/entitlements.plist \
203+
dmg_temp/Claudia.app
204+
205+
- name: Create DMG
206+
run: |
207+
hdiutil create -volname "Claudia Installer" \
208+
-srcfolder dmg_temp \
209+
-ov -format UDZO Claudia.dmg
210+
211+
- name: Sign DMG
212+
env:
213+
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
214+
run: |
215+
codesign --sign "$APPLE_SIGNING_IDENTITY" \
216+
--timestamp \
217+
--force Claudia.dmg
218+
219+
- name: Notarize DMG
220+
env:
221+
APPLE_ID: ${{ secrets.APPLE_ID }}
222+
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
223+
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
224+
run: |
225+
# Store notarization credentials
226+
xcrun notarytool store-credentials "notarytool-profile" \
227+
--apple-id "$APPLE_ID" \
228+
--team-id "$APPLE_TEAM_ID" \
229+
--password "$APPLE_PASSWORD"
230+
231+
# Submit for notarization
232+
xcrun notarytool submit Claudia.dmg \
233+
--keychain-profile "notarytool-profile" \
234+
--wait
235+
236+
- name: Staple notarization
237+
run: xcrun stapler staple Claudia.dmg
238+
239+
- name: Verify DMG
240+
run: |
241+
spctl -a -t open -vvv --context context:primary-signature Claudia.dmg
242+
echo "✅ DMG verification complete"
243+
244+
- name: Create artifacts directory
245+
run: |
246+
mkdir -p dist/macos-universal
247+
cp Claudia.dmg dist/macos-universal/
248+
249+
# Also save the app bundle
250+
cd dmg_temp && zip -r ../dist/macos-universal/Claudia.app.zip Claudia.app && cd ..
251+
252+
# Generate checksum
253+
shasum -a 256 dist/macos-universal/* > dist/macos-universal/checksums.txt
254+
255+
- name: Upload artifacts
256+
uses: actions/upload-artifact@v4
257+
with:
258+
name: macos-universal
259+
path: dist/macos-universal/*
260+
261+
- name: Cleanup
262+
if: always()
263+
run: |
264+
echo "🧹 Cleaning up temporary directories..."
265+
rm -rf dmg_temp temp_x86 artifacts
266+
267+
# Clean up keychain
268+
if [ -n "$RUNNER_TEMP" ] && [ -f "$RUNNER_TEMP/app-signing.keychain-db" ]; then
269+
security delete-keychain "$RUNNER_TEMP/app-signing.keychain-db" || true
270+
fi
271+
272+
echo "✅ Cleanup complete"

0 commit comments

Comments
 (0)