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
This commit is contained in:
60
.github/workflows/build-linux.yml
vendored
Normal file
60
.github/workflows/build-linux.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
name: Build Linux
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [main, test-linux-workflow]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build Linux x86_64
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install system dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
pkg-config \
|
||||
libwebkit2gtk-4.1-dev \
|
||||
libgtk-3-dev \
|
||||
libssl-dev \
|
||||
libayatana-appindicator3-dev \
|
||||
librsvg2-dev
|
||||
|
||||
- name: Setup Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: x86_64-unknown-linux-gnu
|
||||
|
||||
- name: Setup Rust cache
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: src-tauri
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Build Tauri app
|
||||
run: bun run tauri build --target x86_64-unknown-linux-gnu
|
||||
|
||||
- name: Create artifacts directory
|
||||
run: |
|
||||
mkdir -p dist/linux-x86_64
|
||||
cp src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/deb/*.deb dist/linux-x86_64/ || true
|
||||
cp src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/appimage/*.AppImage dist/linux-x86_64/ || true
|
||||
|
||||
# Generate checksums
|
||||
cd dist/linux-x86_64
|
||||
sha256sum * > checksums.txt
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux-x86_64
|
||||
path: dist/linux-x86_64/*
|
272
.github/workflows/build-macos.yml
vendored
Normal file
272
.github/workflows/build-macos.yml
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
name: Build macOS
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
skip_build:
|
||||
description: 'Skip build and use artifacts from a previous run'
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
run_id:
|
||||
description: 'Run ID to download artifacts from (leave empty for latest)'
|
||||
required: false
|
||||
type: string
|
||||
push:
|
||||
branches: [main, test-linux-workflow]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build macOS ${{ matrix.target }}
|
||||
if: ${{ !inputs.skip_build }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: macos-13 # Intel
|
||||
target: x86_64-apple-darwin
|
||||
arch: x86_64
|
||||
- os: macos-14 # Apple Silicon
|
||||
target: aarch64-apple-darwin
|
||||
arch: aarch64
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Setup Rust cache
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: src-tauri
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Import Apple certificates
|
||||
env:
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||
run: |
|
||||
# Create variables
|
||||
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
|
||||
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
||||
|
||||
# Import certificate from secrets
|
||||
echo -n "$APPLE_CERTIFICATE" | base64 --decode -o $CERTIFICATE_PATH
|
||||
|
||||
# Create temporary keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||
|
||||
# Import certificate to keychain
|
||||
security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
||||
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||
security list-keychain -d user -s $KEYCHAIN_PATH
|
||||
|
||||
- name: Build native
|
||||
run: bun run tauri build
|
||||
|
||||
- name: Upload architecture-specific artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: macos-${{ matrix.arch }}
|
||||
path: |
|
||||
src-tauri/target/release/bundle/macos/Claudia.app
|
||||
src-tauri/target/release/bundle/dmg/*.dmg
|
||||
retention-days: 1
|
||||
|
||||
universal:
|
||||
name: Create Universal Binary
|
||||
needs: [build]
|
||||
if: ${{ !cancelled() && (needs.build.result == 'success' || needs.build.result == 'skipped') }}
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Download artifacts from current workflow
|
||||
if: ${{ !inputs.skip_build }}
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: macos-*
|
||||
path: artifacts
|
||||
|
||||
- name: Download artifacts from specific run
|
||||
if: ${{ inputs.skip_build && inputs.run_id != '' }}
|
||||
uses: dawidd6/action-download-artifact@v3
|
||||
with:
|
||||
workflow: build-macos.yml
|
||||
run_id: ${{ inputs.run_id }}
|
||||
name: macos-*
|
||||
path: artifacts
|
||||
|
||||
- name: Download artifacts from latest run
|
||||
if: ${{ inputs.skip_build && inputs.run_id == '' }}
|
||||
uses: dawidd6/action-download-artifact@v3
|
||||
with:
|
||||
workflow: build-macos.yml
|
||||
workflow_conclusion: success
|
||||
name: macos-*
|
||||
path: artifacts
|
||||
|
||||
- name: List downloaded artifacts
|
||||
run: |
|
||||
echo "📁 Artifact structure:"
|
||||
find artifacts -type f -name "*.app" -o -name "*.dmg" | head -20
|
||||
echo ""
|
||||
echo "📁 Full directory structure:"
|
||||
ls -la artifacts/
|
||||
ls -la artifacts/macos-aarch64/ || echo "macos-aarch64 directory not found"
|
||||
ls -la artifacts/macos-x86_64/ || echo "macos-x86_64 directory not found"
|
||||
|
||||
- name: Import Apple certificates
|
||||
env:
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||
run: |
|
||||
# Create variables
|
||||
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
|
||||
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
||||
|
||||
# Import certificate from secrets
|
||||
echo -n "$APPLE_CERTIFICATE" | base64 --decode -o $CERTIFICATE_PATH
|
||||
|
||||
# Create temporary keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||
|
||||
# Import certificate to keychain
|
||||
security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
||||
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||
security list-keychain -d user -s $KEYCHAIN_PATH
|
||||
|
||||
- name: Create universal app
|
||||
run: |
|
||||
# Create temp directory
|
||||
mkdir -p dmg_temp
|
||||
|
||||
# Extract zip files if they exist
|
||||
if [ -f "artifacts/macos-aarch64.zip" ]; then
|
||||
echo "📦 Extracting macos-aarch64.zip..."
|
||||
unzip -q artifacts/macos-aarch64.zip -d artifacts/macos-aarch64/
|
||||
fi
|
||||
|
||||
if [ -f "artifacts/macos-x86_64.zip" ]; then
|
||||
echo "📦 Extracting macos-x86_64.zip..."
|
||||
unzip -q artifacts/macos-x86_64.zip -d artifacts/macos-x86_64/
|
||||
fi
|
||||
|
||||
# Find the actual app paths
|
||||
AARCH64_APP=$(find artifacts/macos-aarch64 -name "Claudia.app" -type d | head -1)
|
||||
X86_64_APP=$(find artifacts/macos-x86_64 -name "Claudia.app" -type d | head -1)
|
||||
|
||||
if [ -z "$AARCH64_APP" ] || [ -z "$X86_64_APP" ]; then
|
||||
echo "❌ Could not find app bundles"
|
||||
echo "AARCH64_APP: $AARCH64_APP"
|
||||
echo "X86_64_APP: $X86_64_APP"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Found app bundles:"
|
||||
echo " ARM64: $AARCH64_APP"
|
||||
echo " x86_64: $X86_64_APP"
|
||||
|
||||
# Copy ARM64 app as base
|
||||
cp -R "$AARCH64_APP" dmg_temp/
|
||||
|
||||
# Create universal binary using lipo
|
||||
lipo -create -output dmg_temp/Claudia.app/Contents/MacOS/claudia \
|
||||
"$AARCH64_APP/Contents/MacOS/claudia" \
|
||||
"$X86_64_APP/Contents/MacOS/claudia"
|
||||
|
||||
echo "✅ Universal binary created"
|
||||
lipo -info dmg_temp/Claudia.app/Contents/MacOS/claudia
|
||||
|
||||
- name: Sign app bundle
|
||||
env:
|
||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
||||
run: |
|
||||
codesign --sign "$APPLE_SIGNING_IDENTITY" \
|
||||
--timestamp \
|
||||
--options runtime \
|
||||
--force \
|
||||
--deep \
|
||||
--entitlements src-tauri/entitlements.plist \
|
||||
dmg_temp/Claudia.app
|
||||
|
||||
- name: Create DMG
|
||||
run: |
|
||||
hdiutil create -volname "Claudia Installer" \
|
||||
-srcfolder dmg_temp \
|
||||
-ov -format UDZO Claudia.dmg
|
||||
|
||||
- name: Sign DMG
|
||||
env:
|
||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
||||
run: |
|
||||
codesign --sign "$APPLE_SIGNING_IDENTITY" \
|
||||
--timestamp \
|
||||
--force Claudia.dmg
|
||||
|
||||
- name: Notarize DMG
|
||||
env:
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||
run: |
|
||||
# Store notarization credentials
|
||||
xcrun notarytool store-credentials "notarytool-profile" \
|
||||
--apple-id "$APPLE_ID" \
|
||||
--team-id "$APPLE_TEAM_ID" \
|
||||
--password "$APPLE_PASSWORD"
|
||||
|
||||
# Submit for notarization
|
||||
xcrun notarytool submit Claudia.dmg \
|
||||
--keychain-profile "notarytool-profile" \
|
||||
--wait
|
||||
|
||||
- name: Staple notarization
|
||||
run: xcrun stapler staple Claudia.dmg
|
||||
|
||||
- name: Verify DMG
|
||||
run: |
|
||||
spctl -a -t open -vvv --context context:primary-signature Claudia.dmg
|
||||
echo "✅ DMG verification complete"
|
||||
|
||||
- name: Create artifacts directory
|
||||
run: |
|
||||
mkdir -p dist/macos-universal
|
||||
cp Claudia.dmg dist/macos-universal/
|
||||
|
||||
# Also save the app bundle
|
||||
cd dmg_temp && zip -r ../dist/macos-universal/Claudia.app.zip Claudia.app && cd ..
|
||||
|
||||
# Generate checksum
|
||||
shasum -a 256 dist/macos-universal/* > dist/macos-universal/checksums.txt
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: macos-universal
|
||||
path: dist/macos-universal/*
|
||||
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
run: |
|
||||
echo "🧹 Cleaning up temporary directories..."
|
||||
rm -rf dmg_temp temp_x86 artifacts
|
||||
|
||||
# Clean up keychain
|
||||
if [ -n "$RUNNER_TEMP" ] && [ -f "$RUNNER_TEMP/app-signing.keychain-db" ]; then
|
||||
security delete-keychain "$RUNNER_TEMP/app-signing.keychain-db" || true
|
||||
fi
|
||||
|
||||
echo "✅ Cleanup complete"
|
131
.github/workflows/release.yml
vendored
Normal file
131
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Version to release (e.g., v1.0.0)'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
# Build jobs for each platform
|
||||
build-linux:
|
||||
uses: ./.github/workflows/build-linux.yml
|
||||
secrets: inherit
|
||||
|
||||
build-macos:
|
||||
uses: ./.github/workflows/build-macos.yml
|
||||
secrets: inherit
|
||||
|
||||
|
||||
# Create release after all builds complete
|
||||
create-release:
|
||||
name: Create Release
|
||||
needs: [build-linux, build-macos]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Determine version
|
||||
id: version
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "push" ]; then
|
||||
VERSION="${GITHUB_REF#refs/tags/}"
|
||||
else
|
||||
VERSION="${{ inputs.version }}"
|
||||
fi
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Version: $VERSION"
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: artifacts
|
||||
|
||||
- name: Prepare release assets
|
||||
run: |
|
||||
mkdir -p release-assets
|
||||
|
||||
# Linux artifacts
|
||||
if [ -d "artifacts/linux-x86_64" ]; then
|
||||
cp artifacts/linux-x86_64/*.deb release-assets/Claudia_${{ steps.version.outputs.version }}_linux_x86_64.deb || true
|
||||
cp artifacts/linux-x86_64/*.AppImage release-assets/Claudia_${{ steps.version.outputs.version }}_linux_x86_64.AppImage || true
|
||||
fi
|
||||
|
||||
# macOS artifacts
|
||||
if [ -d "artifacts/macos-universal" ]; then
|
||||
cp artifacts/macos-universal/Claudia.dmg release-assets/Claudia_${{ steps.version.outputs.version }}_macos_universal.dmg || true
|
||||
cp artifacts/macos-universal/Claudia.app.zip release-assets/Claudia_${{ steps.version.outputs.version }}_macos_universal.app.tar.gz || true
|
||||
fi
|
||||
|
||||
# Create source code archives
|
||||
# Clean version without 'v' prefix for archive names
|
||||
CLEAN_VERSION="${{ steps.version.outputs.version }}"
|
||||
CLEAN_VERSION="${CLEAN_VERSION#v}"
|
||||
|
||||
# Create source code archives (excluding .git and other unnecessary files)
|
||||
echo "Creating source code archives..."
|
||||
|
||||
# Create a clean export of the repository
|
||||
git archive --format=tar.gz --prefix=claudia-${CLEAN_VERSION}/ -o release-assets/claudia-${CLEAN_VERSION}.tar.gz HEAD
|
||||
git archive --format=zip --prefix=claudia-${CLEAN_VERSION}/ -o release-assets/claudia-${CLEAN_VERSION}.zip HEAD
|
||||
|
||||
# Generate signatures for all files
|
||||
cd release-assets
|
||||
for file in *; do
|
||||
if [ -f "$file" ]; then
|
||||
sha256sum "$file" > "$file.sha256"
|
||||
fi
|
||||
done
|
||||
cd ..
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: ${{ steps.version.outputs.version }}
|
||||
name: Claudia ${{ steps.version.outputs.version }}
|
||||
draft: true
|
||||
prerelease: false
|
||||
generate_release_notes: true
|
||||
files: release-assets/*
|
||||
body: |
|
||||
## Claudia ${{ steps.version.outputs.version }}
|
||||
|
||||
### Downloads
|
||||
|
||||
#### macOS
|
||||
- Universal binary (Intel + Apple Silicon)
|
||||
- `.dmg` - Disk image installer (recommended)
|
||||
- `.app.tar.gz` - Application bundle
|
||||
|
||||
|
||||
#### Linux
|
||||
- `.AppImage` - Universal Linux package (recommended)
|
||||
- `.deb` - Debian/Ubuntu package
|
||||
|
||||
#### Source Code
|
||||
- `claudia-{version}.tar.gz` - Source code (tar.gz)
|
||||
- `claudia-{version}.zip` - Source code (zip)
|
||||
|
||||
### Installation
|
||||
|
||||
**macOS**: Download the `.dmg` file, open it, and drag Claudia to your Applications folder.
|
||||
|
||||
|
||||
**Linux**: Download the `.AppImage` file, make it executable (`chmod +x`), and run it. For Debian/Ubuntu, use the `.deb` file.
|
||||
|
||||
### Verification
|
||||
|
||||
All files include `.sha256` signature files for verification.
|
||||
|
||||
### What's Changed
|
||||
|
||||
See below for a full list of changes in this release.
|
Reference in New Issue
Block a user