name: Build on: workflow_call: inputs: upload_artifacts: required: false type: boolean default: false description: 'Whether to upload build artifacts' secrets: MAC_CERT_P12_BASE64: required: false MAC_CERT_P12_PASSWORD: required: false APPLE_API_KEY_ID: required: false APPLE_API_ISSUER: required: false APPLE_API_KEY_P8_BASE64: required: false VITE_GLITCHTIP_DSN: required: false SENTRY_URL: required: false SENTRY_ORG: required: false SENTRY_PROJECT: required: false SENTRY_AUTH_TOKEN: required: false jobs: build: runs-on: ${{ matrix.os }} strategy: matrix: include: - platform: windows os: windows-latest build_script: pnpm run build:win mac_ffmpeg_mode: native - platform: macos os: macos-latest build_script: pnpm run build:mac mac_ffmpeg_mode: universal - platform: linux os: ubuntu-latest build_script: pnpm run build:linux mac_ffmpeg_mode: native steps: - name: Check out Git repository uses: actions/checkout@v4 - name: Install Node.js uses: actions/setup-node@v4 with: node-version: 22 - name: Install pnpm uses: pnpm/action-setup@v4 with: version: 11.1.2 - name: Install Dependencies run: pnpm install --frozen-lockfile - name: Lint and format check run: pnpm run check && pnpm run typecheck - name: Setup macOS signing if: matrix.platform == 'macos' shell: bash env: MAC_CERT_P12_BASE64: ${{ secrets.MAC_CERT_P12_BASE64 }} MAC_CERT_P12_PASSWORD: ${{ secrets.MAC_CERT_P12_PASSWORD }} APPLE_API_KEY_P8_BASE64: ${{ secrets.APPLE_API_KEY_P8_BASE64 }} APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} run: | set -euo pipefail echo "SIGNING_AVAILABLE=false" >> "$GITHUB_ENV" # Check if all required secrets are present if [[ -z "$MAC_CERT_P12_BASE64" ]] || [[ -z "$MAC_CERT_P12_PASSWORD" ]] || \ [[ -z "$APPLE_API_KEY_ID" ]] || [[ -z "$APPLE_API_ISSUER" ]] || \ [[ -z "$APPLE_API_KEY_P8_BASE64" ]]; then echo "::notice::macOS signing secrets not available, skipping code signing setup" exit 0 fi CERT_PATH="$RUNNER_TEMP/mac_cert.p12" KEYCHAIN_PATH="$RUNNER_TEMP/build.keychain" API_KEY_PATH="$RUNNER_TEMP/AuthKey.p8" echo "$MAC_CERT_P12_BASE64" | base64 --decode > "$CERT_PATH" echo "$APPLE_API_KEY_P8_BASE64" | base64 --decode > "$API_KEY_PATH" security create-keychain -p "$MAC_CERT_P12_PASSWORD" "$KEYCHAIN_PATH" security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" security unlock-keychain -p "$MAC_CERT_P12_PASSWORD" "$KEYCHAIN_PATH" security import "$CERT_PATH" -k "$KEYCHAIN_PATH" -P "$MAC_CERT_P12_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productbuild security list-keychain -d user -s "$KEYCHAIN_PATH" security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MAC_CERT_P12_PASSWORD" "$KEYCHAIN_PATH" echo "CSC_KEYCHAIN=$KEYCHAIN_PATH" >> "$GITHUB_ENV" echo "CSC_KEY_PASSWORD=$MAC_CERT_P12_PASSWORD" >> "$GITHUB_ENV" echo "APPLE_API_KEY=$API_KEY_PATH" >> "$GITHUB_ENV" echo "APPLE_API_KEY_ID=$APPLE_API_KEY_ID" >> "$GITHUB_ENV" echo "APPLE_API_ISSUER=$APPLE_API_ISSUER" >> "$GITHUB_ENV" echo "SIGNING_AVAILABLE=true" >> "$GITHUB_ENV" - name: Stamp release version and channel from tag if: github.ref_type == 'tag' shell: bash # Stamp the tag version into package.json and, for prerelease tags, set the publish # channel so electron-builder emits preview*.yml instead of latest*.yml (its GitHub # provider does not derive the channel from the version on its own). run: node apps/desktop/scripts/stamp-release.mjs "${GITHUB_REF_NAME}" - name: Build application env: VIDBEE_MAC_FFMPEG_MODE: ${{ matrix.mac_ffmpeg_mode }} VITE_GLITCHTIP_DSN: ${{ secrets.VITE_GLITCHTIP_DSN }} VITE_GLITCHTIP_ENVIRONMENT: production SENTRY_URL: ${{ secrets.SENTRY_URL }} SENTRY_ORG: ${{ secrets.SENTRY_ORG }} SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} run: ${{ matrix.build_script }} - name: Verify Windows release artifacts if: matrix.platform == 'windows' shell: pwsh run: | $dist = "apps/desktop/dist" $requiredPatterns = @("*-setup.exe", "*-portable.exe", "*-windows-portable.zip") foreach ($pattern in $requiredPatterns) { $matches = Get-ChildItem -Path $dist -Filter $pattern -File if ($matches.Count -eq 0) { Write-Error "Missing Windows release artifact matching $pattern" exit 1 } $matches | ForEach-Object { Write-Host "Found Windows release artifact: $($_.Name)" } } - name: Verify macOS codesign and notarization if: matrix.platform == 'macos' && env.SIGNING_AVAILABLE == 'true' shell: bash run: | set -euo pipefail apps_found=0 while IFS= read -r app; do apps_found=1 echo "Verifying codesign for $app" codesign --verify --deep --strict --verbose=2 "$app" spctl -a -t exec -vv "$app" echo "Validating notarization ticket for $app" xcrun stapler validate "$app" done < <(find apps/desktop/dist -type d -name "*.app" -prune -print) if [[ "$apps_found" -eq 0 ]]; then echo "::error::No .app bundles found in dist" exit 1 fi dmgs_found=0 while IFS= read -r dmg; do dmgs_found=1 echo "Submitting DMG for notarization: $dmg" xcrun notarytool submit "$dmg" --key "$APPLE_API_KEY" --key-id "$APPLE_API_KEY_ID" --issuer "$APPLE_API_ISSUER" --wait echo "Stapling notarization ticket for $dmg" xcrun stapler staple "$dmg" echo "Validating notarization ticket for $dmg" xcrun stapler validate "$dmg" done < <(find apps/desktop/dist -type f -name "*.dmg" -print) if [[ "$dmgs_found" -eq 0 ]]; then echo "::notice::No DMG artifacts found to validate" fi - name: Upload build artifacts if: inputs.upload_artifacts == true uses: actions/upload-artifact@v4 with: name: dist-${{ matrix.os }} path: | apps/desktop/dist/*.exe apps/desktop/dist/*.zip apps/desktop/dist/*.dmg apps/desktop/dist/*.AppImage apps/desktop/dist/*.snap apps/desktop/dist/*.deb apps/desktop/dist/*.rpm apps/desktop/dist/*.tar.gz apps/desktop/dist/*.yml apps/desktop/dist/*.blockmap retention-days: 1 if-no-files-found: error