# This workflow builds the Finicky macOS app for both Silicon (ARM64) and Intel (x86_64) architectures name: macOS Build on: push: branches: [main] pull_request: branches: [main] workflow_dispatch: jobs: build-macos: strategy: matrix: include: - architecture: arm64 display_name: "Apple Silicon (ARM64)" runner: macos-latest - architecture: amd64 display_name: "Intel (x86_64)" runner: macos-13 runs-on: ${{ matrix.runner }} steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: '22' cache: 'npm' cache-dependency-path: | packages/config-api/package-lock.json packages/finicky-ui/package-lock.json - name: Set up Go uses: actions/setup-go@v4 with: go-version: '1.21' cache-dependency-path: | apps/finicky/src/go.sum - name: Install dependencies run: | # Make install script executable and run it chmod +x scripts/install.sh ./scripts/install.sh - name: Build for ${{ matrix.display_name }} env: API_HOST: ${{ vars.API_HOST || '' }} BUILD_TARGET_ARCH: ${{ matrix.architecture }} run: | # Create a temporary .env file with the API_HOST variable echo "API_HOST=${{ vars.API_HOST || '' }}" > .env # Make build script executable and run it chmod +x scripts/build.sh ./scripts/build.sh - name: Create archive run: | cd apps/finicky/build tar -czf Finicky-${{ matrix.architecture }}.tar.gz Finicky-${{ matrix.architecture }}.app - name: Upload build artifact uses: actions/upload-artifact@v4 with: name: Finicky-${{ matrix.architecture }} path: apps/finicky/build/Finicky-${{ matrix.architecture }}.tar.gz retention-days: 30 create-universal-binary: runs-on: macos-latest needs: build-macos steps: - name: Checkout code uses: actions/checkout@v4 - name: Download ARM64 artifact uses: actions/download-artifact@v4 with: name: Finicky-arm64 path: ./artifacts/arm64 - name: Download AMD64 artifact uses: actions/download-artifact@v4 with: name: Finicky-amd64 path: ./artifacts/amd64 - name: Create universal binary run: | # Extract both builds cd artifacts/arm64 tar -xzf Finicky-arm64.tar.gz cd ../amd64 tar -xzf Finicky-amd64.tar.gz cd ../../ # Create universal app structure mkdir -p universal/Finicky.app/Contents/MacOS cp -r artifacts/arm64/Finicky-arm64.app/Contents/Resources universal/Finicky.app/Contents/ cp -r artifacts/arm64/Finicky-arm64.app/Contents/Info.plist universal/Finicky.app/Contents/ || true # Create universal binary using lipo lipo -create \ artifacts/arm64/Finicky-arm64.app/Contents/MacOS/Finicky \ artifacts/amd64/Finicky-amd64.app/Contents/MacOS/Finicky \ -output universal/Finicky.app/Contents/MacOS/Finicky # Verify the universal binary lipo -info universal/Finicky.app/Contents/MacOS/Finicky # Create archive cd universal tar -czf Finicky-universal.tar.gz Finicky.app - name: Upload universal binary uses: actions/upload-artifact@v4 with: name: Finicky-universal path: universal/Finicky-universal.tar.gz retention-days: 14 sign-and-notarize: runs-on: macos-latest needs: create-universal-binary if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main' steps: - name: Checkout code uses: actions/checkout@v4 - name: Download universal binary uses: actions/download-artifact@v4 with: name: Finicky-universal path: ./universal - name: Extract universal binary run: | cd universal tar -xzf Finicky-universal.tar.gz - name: Import signing certificate env: SIGNING_CERTIFICATE_P12_DATA: ${{ secrets.SIGNING_CERTIFICATE_P12_DATA }} SIGNING_CERTIFICATE_PASSWORD: ${{ secrets.SIGNING_CERTIFICATE_PASSWORD }} run: | # Create temporary keychain security create-keychain -p temp_password temp.keychain security default-keychain -s temp.keychain security unlock-keychain -p temp_password temp.keychain # Import certificate echo "$SIGNING_CERTIFICATE_P12_DATA" | base64 --decode > certificate.p12 security import certificate.p12 -k temp.keychain -P "$SIGNING_CERTIFICATE_PASSWORD" -T /usr/bin/codesign # Set partition list security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k temp_password temp.keychain # Clean up rm certificate.p12 - name: Install gon run: | brew install Bearer/tap/gon - name: Update gon config for CI run: | # Create the directory structure expected by the existing gon config mkdir -p apps/finicky/build # Copy the universal binary to the expected location for the existing gon config cp -r universal/Finicky.app apps/finicky/build/Finicky.app - name: Sign and notarize env: AC_USERNAME: ${{ secrets.APPLE_ID_USERNAME }} AC_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} AC_PROVIDER: ${{ secrets.AC_PROVIDER }} run: | mkdir -p dist gon scripts/gon-config.json - name: Upload signed DMG uses: actions/upload-artifact@v4 with: name: Finicky-signed-dmg path: dist/Finicky.dmg retention-days: 30 - name: Cleanup keychain if: always() run: | security delete-keychain temp.keychain || true