Build and Test - macOS #6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: "Build and Test - macOS" | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| build-type: | |
| description: 'Build type' | |
| required: true | |
| type: choice | |
| options: | |
| - debug | |
| - release | |
| default: release | |
| sign-build: | |
| description: 'Sign the build' | |
| required: true | |
| type: boolean | |
| default: true | |
| upload-artifacts: | |
| description: 'Upload build artifacts' | |
| required: true | |
| type: boolean | |
| default: true | |
| # Cancel duplicate workflow runs | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| RUST_BACKTRACE: 1 | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| build-macos: | |
| name: Build macOS (Apple Silicon) | |
| runs-on: macos-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Get version from tauri.conf.json | |
| id: get-version | |
| shell: bash | |
| run: | | |
| VERSION=$(grep -o '"version": "[^"]*"' frontend/src-tauri/tauri.conf.json | cut -d'"' -f4) | |
| echo "Application version: $VERSION" | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| - name: Determine build profile | |
| id: build-profile | |
| shell: bash | |
| run: | | |
| if [[ "${{ github.event.inputs.build-type }}" == "debug" ]]; then | |
| echo "profile=debug" >> "$GITHUB_OUTPUT" | |
| echo "args=--debug" >> "$GITHUB_OUTPUT" | |
| echo "Build profile: debug" | |
| else | |
| echo "profile=release" >> "$GITHUB_OUTPUT" | |
| echo "args=" >> "$GITHUB_OUTPUT" | |
| echo "Build profile: release" | |
| fi | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 8 | |
| run_install: false | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: | | |
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| - name: Setup pnpm cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-store- | |
| - name: Install Rust stable | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: aarch64-apple-darwin | |
| - name: Rust cache | |
| uses: swatinem/rust-cache@v2 | |
| with: | |
| workspaces: ". -> target" | |
| key: macos-latest-aarch64-apple-darwin | |
| - name: Install frontend dependencies | |
| run: | | |
| cd frontend | |
| pnpm install | |
| - name: Import Apple Developer Certificate | |
| if: ${{ github.event.inputs.sign-build == 'true' }} | |
| env: | |
| APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} | |
| run: | | |
| echo $APPLE_CERTIFICATE | base64 --decode > certificate.p12 | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain | |
| security default-keychain -s build.keychain | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain | |
| security set-keychain-settings -t 3600 -u build.keychain | |
| security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain | |
| security find-identity -v -p codesigning build.keychain | |
| - name: Verify certificate | |
| if: ${{ github.event.inputs.sign-build == 'true' }} | |
| run: | | |
| CERT_INFO=$(security find-identity -v -p codesigning build.keychain | grep "Developer ID Application") | |
| CERT_ID=$(echo "$CERT_INFO" | awk -F'"' '{print $2}') | |
| echo "CERT_ID=$CERT_ID" >> $GITHUB_ENV | |
| echo "Certificate imported: $CERT_ID" | |
| - name: Configure build acceleration | |
| run: | | |
| echo "✓ macOS build will use Metal GPU acceleration (enabled by default)" | |
| echo "✓ CoreML acceleration available for Apple Silicon" | |
| - name: Build llama-helper sidecar | |
| run: | | |
| echo "Building llama-helper sidecar with Metal support..." | |
| cargo build --release -p llama-helper --features metal | |
| # Copy binary to binaries directory | |
| mkdir -p frontend/src-tauri/binaries | |
| cp target/release/llama-helper frontend/src-tauri/binaries/llama-helper-aarch64-apple-darwin | |
| echo "Copied llama-helper to frontend/src-tauri/binaries/" | |
| ls -la frontend/src-tauri/binaries/ | |
| - name: Cache FFmpeg binary | |
| uses: actions/cache@v4 | |
| with: | |
| path: frontend/src-tauri/binaries/ffmpeg-* | |
| key: ${{ runner.os }}-ffmpeg-${{ hashFiles('frontend/src-tauri/build.rs', 'frontend/src-tauri/build/ffmpeg.rs') }} | |
| - name: Build Tauri app (with code signing) | |
| if: ${{ github.event.inputs.sign-build == 'true' }} | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # macOS code signing | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} | |
| APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| APPLE_SIGNING_IDENTITY: ${{ env.CERT_ID }} | |
| # Tauri updater signing (ALWAYS enabled for .sig files) | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| # License validation RSA public key (embedded at build time) | |
| MEETILY_RSA_PUBLIC_KEY: ${{ secrets.MEETILY_RSA_PUBLIC_KEY }} | |
| # Supabase configuration (for online license verification) | |
| SUPABASE_URL: ${{ secrets.SUPABASE_URL }} | |
| SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }} | |
| with: | |
| projectPath: frontend | |
| args: --target aarch64-apple-darwin ${{ steps.build-profile.outputs.args }} | |
| - name: Build Tauri app (unsigned) | |
| if: ${{ github.event.inputs.sign-build != 'true' }} | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # Tauri updater signing (ALWAYS enabled for .sig files) | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| # License validation RSA public key (embedded at build time) | |
| MEETILY_RSA_PUBLIC_KEY: ${{ secrets.MEETILY_RSA_PUBLIC_KEY }} | |
| # Supabase configuration (for online license verification) | |
| SUPABASE_URL: ${{ secrets.SUPABASE_URL }} | |
| SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }} | |
| with: | |
| projectPath: frontend | |
| args: --target aarch64-apple-darwin ${{ steps.build-profile.outputs.args }} | |
| - name: Verify build artifacts | |
| run: | | |
| echo "Build artifacts:" | |
| find target/aarch64-apple-darwin/${{ steps.build-profile.outputs.profile }}/bundle -type f | |
| - name: Verify code signing (App Bundle) | |
| if: ${{ github.event.inputs.sign-build == 'true' }} | |
| run: | | |
| APP_PATH=$(find target/aarch64-apple-darwin/${{ steps.build-profile.outputs.profile }}/bundle/macos -name "*.app" | head -1) | |
| if [ -n "$APP_PATH" ]; then | |
| echo "=== Verifying App Bundle: $APP_PATH ===" | |
| echo "" | |
| echo "Code signature details:" | |
| codesign -dv --verbose=4 "$APP_PATH" 2>&1 | grep -i "signature\|authority" | |
| echo "" | |
| echo "Verifying signature..." | |
| codesign --verify --deep --strict "$APP_PATH" && echo "✓ Code signature is valid" | |
| echo "" | |
| echo "Checking notarization..." | |
| spctl -a -vvv "$APP_PATH" && echo "✓ App is notarized and will be accepted by Gatekeeper" | |
| else | |
| echo "No App bundle found to verify" | |
| fi | |
| - name: Verify code signing (DMG) | |
| if: ${{ github.event.inputs.sign-build == 'true' }} | |
| run: | | |
| DMG_PATH=$(find target/aarch64-apple-darwin/${{ steps.build-profile.outputs.profile }}/bundle/dmg -name "*.dmg" | head -1) | |
| if [ -n "$DMG_PATH" ]; then | |
| echo "=== Verifying DMG: $DMG_PATH ===" | |
| echo "" | |
| echo "Code signature details:" | |
| codesign -dv --verbose=4 "$DMG_PATH" 2>&1 | grep -i "signature\|authority" | |
| echo "" | |
| echo "Verifying signature..." | |
| codesign --verify --deep --strict "$DMG_PATH" && echo "✓ DMG signature is valid" | |
| echo "" | |
| echo "Note: DMG contains notarized .app bundle but DMG itself may not be notarized" | |
| echo "This is acceptable - users will mount the DMG and run the notarized .app inside" | |
| else | |
| echo "No DMG found to verify" | |
| fi | |
| - name: Upload artifacts | |
| if: ${{ github.event.inputs.upload-artifacts == 'true' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: meetily-macos-aarch64-${{ steps.build-profile.outputs.profile }}-${{ steps.get-version.outputs.version }} | |
| path: | | |
| target/aarch64-apple-darwin/${{ steps.build-profile.outputs.profile }}/bundle/dmg/*.dmg | |
| target/aarch64-apple-darwin/${{ steps.build-profile.outputs.profile }}/bundle/macos/*.app | |
| target/aarch64-apple-darwin/${{ steps.build-profile.outputs.profile }}/bundle/macos/*.app.tar.gz | |
| target/aarch64-apple-darwin/${{ steps.build-profile.outputs.profile }}/bundle/macos/*.app.tar.gz.sig | |
| retention-days: 30 | |
| - name: Generate build summary | |
| run: | | |
| echo "## 🍎 macOS Build Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY | |
| echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| **Version** | ${{ steps.get-version.outputs.version }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| **Build Profile** | ${{ steps.build-profile.outputs.profile }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| **Target** | aarch64-apple-darwin (Apple Silicon) |" >> $GITHUB_STEP_SUMMARY | |
| echo "| **Signed** | ${{ github.event.inputs.sign-build == 'true' && '✅ Yes' || '❌ No' }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 📦 Build Artifacts" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| File Type | Count |" >> $GITHUB_STEP_SUMMARY | |
| echo "|-----------|-------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| DMG Installers | $(find target/aarch64-apple-darwin/${{ steps.build-profile.outputs.profile }}/bundle/dmg -name "*.dmg" 2>/dev/null | wc -l) |" >> $GITHUB_STEP_SUMMARY | |
| echo "| APP Bundles | $(find target/aarch64-apple-darwin/${{ steps.build-profile.outputs.profile }}/bundle/macos -name "*.app" -type d 2>/dev/null | wc -l) |" >> $GITHUB_STEP_SUMMARY | |
| echo "| APP Archives | $(find target/aarch64-apple-darwin/${{ steps.build-profile.outputs.profile }}/bundle/macos -name "*.app.tar.gz" 2>/dev/null | wc -l) |" >> $GITHUB_STEP_SUMMARY | |
| echo "| APP Signatures | $(find target/aarch64-apple-darwin/${{ steps.build-profile.outputs.profile }}/bundle/macos -name "*.app.tar.gz.sig" 2>/dev/null | wc -l) |" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "<details>" >> $GITHUB_STEP_SUMMARY | |
| echo "<summary>📋 File List</summary>" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | |
| find target/aarch64-apple-darwin/${{ steps.build-profile.outputs.profile }}/bundle -type f \( -name "*.dmg" -o -name "*.tar.gz" -o -name "*.sig" \) 2>/dev/null >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "</details>" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY |