feat: ship v0.1.0 production readiness (prebuilt brew + privacy) (#31) #3
Workflow file for this run
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: Release | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| jobs: | |
| build: | |
| name: build (${{ matrix.target }}) | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: macos-latest | |
| target: aarch64-apple-darwin | |
| - os: macos-latest | |
| target: x86_64-apple-darwin | |
| - os: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Build | |
| run: cargo build --release -p microbridged -p microbridgectl --target ${{ matrix.target }} | |
| - name: Package | |
| run: | | |
| STAGE=microbridge-${{ github.ref_name }}-${{ matrix.target }} | |
| mkdir -p "staging/${STAGE}" | |
| cp "target/${{ matrix.target }}/release/microbridged" "staging/${STAGE}/" | |
| cp "target/${{ matrix.target }}/release/microbridgectl" "staging/${STAGE}/" | |
| cp README.md LICENSE-MIT LICENSE-APACHE INSTALL.md "staging/${STAGE}/" | |
| tar -C staging -czf "${STAGE}.tar.gz" "${STAGE}" | |
| echo "ASSET=${STAGE}.tar.gz" >> "$GITHUB_ENV" | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: binaries-${{ matrix.target }} | |
| path: ${{ env.ASSET }} | |
| build-ui-macos: | |
| name: build menu bar app (${{ matrix.target }}) | |
| runs-on: macos-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| target: [aarch64-apple-darwin, x86_64-apple-darwin] | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: "apps/microbridge-ui/src-tauri -> target" | |
| - uses: actions/setup-node@v7 | |
| with: | |
| node-version: "22" | |
| cache: npm | |
| cache-dependency-path: apps/microbridge-ui/package-lock.json | |
| - name: Import Developer ID certificate | |
| env: | |
| APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} | |
| run: | | |
| if [[ -z "${APPLE_CERTIFICATE:-}" ]]; then | |
| echo "APPLE_CERTIFICATE secret missing — UI build will be unsigned" | |
| echo "SIGNED=0" >> "$GITHUB_ENV" | |
| exit 0 | |
| fi | |
| echo "SIGNED=1" >> "$GITHUB_ENV" | |
| CERT_PATH="$RUNNER_TEMP/certificate.p12" | |
| echo "$APPLE_CERTIFICATE" | base64 --decode > "$CERT_PATH" | |
| 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 "$CERT_PATH" -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" \ | |
| -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain | |
| security list-keychains -d user -s build.keychain $(security list-keychains -d user | sed -e 's/"//g') | |
| IDENTITY="${{ secrets.APPLE_SIGNING_IDENTITY }}" | |
| if [[ -z "$IDENTITY" ]]; then | |
| IDENTITY="$(security find-identity -v -p codesigning build.keychain \ | |
| | awk -F'"' '/Developer ID Application/{print $2; exit}')" | |
| fi | |
| test -n "$IDENTITY" | |
| echo "APPLE_SIGNING_IDENTITY=$IDENTITY" >> "$GITHUB_ENV" | |
| security find-identity -v -p codesigning build.keychain | |
| - name: Prepare App Store Connect API key for notarization | |
| if: env.SIGNED == '1' | |
| env: | |
| APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} | |
| APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} | |
| APPLE_API_KEY_P8: ${{ secrets.APPLE_API_KEY_P8 }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| run: | | |
| test -n "${APPLE_API_KEY:-}" | |
| test -n "${APPLE_API_ISSUER:-}" | |
| test -n "${APPLE_API_KEY_P8:-}" | |
| KEY_PATH="$RUNNER_TEMP/AuthKey_${APPLE_API_KEY}.p8" | |
| printf '%s\n' "$APPLE_API_KEY_P8" > "$KEY_PATH" | |
| chmod 600 "$KEY_PATH" | |
| { | |
| echo "APPLE_API_KEY=$APPLE_API_KEY" | |
| echo "APPLE_API_ISSUER=$APPLE_API_ISSUER" | |
| echo "APPLE_API_KEY_PATH=$KEY_PATH" | |
| echo "APPLE_TEAM_ID=${APPLE_TEAM_ID:-3NQG568C4Q}" | |
| } >> "$GITHUB_ENV" | |
| - name: Build signed Microbridge.app + DMG | |
| working-directory: apps/microbridge-ui | |
| env: | |
| APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| APPLE_SIGNING_IDENTITY: ${{ env.APPLE_SIGNING_IDENTITY }} | |
| APPLE_API_KEY: ${{ env.APPLE_API_KEY }} | |
| APPLE_API_ISSUER: ${{ env.APPLE_API_ISSUER }} | |
| APPLE_API_KEY_PATH: ${{ env.APPLE_API_KEY_PATH }} | |
| APPLE_TEAM_ID: ${{ env.APPLE_TEAM_ID }} | |
| run: | | |
| npm ci | |
| if [[ "${SIGNED:-0}" == "1" ]]; then | |
| npm run tauri build -- --bundles app,dmg --target ${{ matrix.target }} | |
| else | |
| npm run tauri build -- --bundles app --target ${{ matrix.target }} | |
| fi | |
| - name: Package .app and DMG | |
| run: | | |
| set -euo pipefail | |
| APP="$(find apps/microbridge-ui/src-tauri/target/${{ matrix.target }}/release/bundle/macos \ | |
| apps/microbridge-ui/src-tauri/target/release/bundle/macos \ | |
| -name 'Microbridge.app' -type d 2>/dev/null | head -n1)" | |
| test -n "$APP" | |
| STAGE="microbridge-ui-${GITHUB_REF_NAME}-${{ matrix.target }}" | |
| mkdir -p "staging/${STAGE}" "ui-out" | |
| cp -R "$APP" "staging/${STAGE}/" | |
| cp README.md LICENSE-MIT LICENSE-APACHE INSTALL.md "staging/${STAGE}/" | |
| tar -C staging -czf "ui-out/${STAGE}.tar.gz" "${STAGE}" | |
| DMG="$(find apps/microbridge-ui/src-tauri/target/${{ matrix.target }}/release/bundle/dmg \ | |
| apps/microbridge-ui/src-tauri/target/release/bundle/dmg \ | |
| -name '*.dmg' -type f 2>/dev/null | head -n1 || true)" | |
| if [[ -n "${DMG:-}" ]]; then | |
| DMG_OUT="ui-out/microbridge-ui-${GITHUB_REF_NAME}-${{ matrix.target }}.dmg" | |
| cp "$DMG" "$DMG_OUT" | |
| echo "Packed signed DMG: $DMG_OUT" | |
| spctl --assess --type open --context context:primary-signature "$DMG_OUT" || true | |
| codesign -dv --verbose=2 "$APP" || true | |
| else | |
| echo "No DMG produced (unsigned build or bundle skipped)" | |
| fi | |
| ls -la ui-out | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: ui-${{ matrix.target }} | |
| path: ui-out/* | |
| publish: | |
| name: publish release | |
| needs: [build, build-ui-macos] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| path: artifacts | |
| - name: Collect assets | |
| run: | | |
| mkdir -p release-assets | |
| find artifacts -type f \( -name '*.tar.gz' -o -name '*.dmg' \) -exec cp {} release-assets/ \; | |
| ls -la release-assets | |
| - uses: softprops/action-gh-release@v3 | |
| with: | |
| generate_release_notes: true | |
| files: release-assets/* | |
| body: | | |
| ## Install (macOS) | |
| Menu bar app + daemon (not CLI-only): | |
| ```sh | |
| brew tap DevVig/microbridge https://github.com/DevVig/microbridge | |
| brew install microbridge | |
| brew services start microbridge | |
| open ~/Applications/Microbridge.app | |
| ``` | |
| Upgrade later: `brew update && brew upgrade microbridge` | |
| ### Direct download (signed + notarized DMG) | |
| Grab `microbridge-ui-${{ github.ref_name }}-aarch64-apple-darwin.dmg` (Apple Silicon) | |
| or `…-x86_64-apple-darwin.dmg` (Intel) from the assets below, open it, and drag | |
| Microbridge into Applications. Pair with the daemon archive or Homebrew formula. | |
| Binary + app archive: `./scripts/install-from-release.sh ${{ github.ref_name }}` | |
| Full guide: [INSTALL.md](INSTALL.md). | |
| bump-formula: | |
| name: bump Homebrew formula | |
| needs: publish | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| ref: main | |
| - name: Bump Formula url + sha256 | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| chmod +x scripts/bump-formula.sh | |
| ./scripts/bump-formula.sh "${{ github.ref_name }}" | |
| - name: Open PR | |
| uses: peter-evans/create-pull-request@v7 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| commit-message: "chore(brew): bump formula to ${{ github.ref_name }}" | |
| title: "chore(brew): bump formula to ${{ github.ref_name }}" | |
| body: | | |
| Auto-bump `Formula/microbridge.rb` after release `${{ github.ref_name }}`. | |
| After merge, users get the new version via: | |
| ```sh | |
| brew update && brew upgrade microbridge | |
| ``` | |
| branch: chore/brew-${{ github.ref_name }} | |
| delete-branch: true |