Release #4
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: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Release macOS version" | |
| required: true | |
| type: string | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| jobs: | |
| release: | |
| runs-on: macos-latest | |
| environment: release | |
| env: | |
| CODESIGN_IDENTITY: ${{ vars.CODESIGN_IDENTITY }} | |
| NOTARY_PROFILE_NAME: ${{ vars.NOTARY_PROFILE_NAME }} | |
| APPLE_TEAM_ID: ${{ vars.APPLE_TEAM_ID }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| cache: npm | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Import signing certificate | |
| env: | |
| APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| run: | | |
| set -euo pipefail | |
| KEYCHAIN=build.keychain | |
| CERT_PATH=cert.p12 | |
| echo "$APPLE_CERTIFICATE_P12" | base64 --decode > "$CERT_PATH" 2>/dev/null || \ | |
| echo "$APPLE_CERTIFICATE_P12" | base64 -D > "$CERT_PATH" | |
| security create-keychain -p "" "$KEYCHAIN" | |
| security set-keychain-settings -lut 21600 "$KEYCHAIN" | |
| security unlock-keychain -p "" "$KEYCHAIN" | |
| security import "$CERT_PATH" -k "$KEYCHAIN" -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign | |
| security list-keychains -d user -s "$KEYCHAIN" | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "" "$KEYCHAIN" | |
| - name: Configure notarytool credentials | |
| env: | |
| APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} | |
| APPLE_API_ISSUER_ID: ${{ secrets.APPLE_API_ISSUER_ID }} | |
| APPLE_API_PRIVATE_KEY_B64: ${{ secrets.APPLE_API_PRIVATE_KEY_B64 }} | |
| run: | | |
| set -euo pipefail | |
| mkdir -p private_keys | |
| echo "$APPLE_API_PRIVATE_KEY_B64" | base64 --decode > private_keys/AuthKey.p8 | |
| xcrun notarytool store-credentials "$NOTARY_PROFILE_NAME" \ | |
| --key-id "$APPLE_API_KEY_ID" \ | |
| --issuer "$APPLE_API_ISSUER_ID" \ | |
| --key "private_keys/AuthKey.p8" | |
| - name: Write Tauri signing key | |
| env: | |
| TAURI_SIGNING_PRIVATE_KEY_B64: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_B64 }} | |
| run: | | |
| set -euo pipefail | |
| mkdir -p "$HOME/.tauri" | |
| echo "$TAURI_SIGNING_PRIVATE_KEY_B64" | base64 --decode > "$HOME/.tauri/codexmonitor.key" | |
| - name: Build app bundle | |
| env: | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| run: | | |
| set -euo pipefail | |
| npm run tauri -- build --bundles app | |
| - name: Bundle OpenSSL and re-sign | |
| run: | | |
| set -euo pipefail | |
| CODESIGN_IDENTITY="$CODESIGN_IDENTITY" \ | |
| scripts/macos-fix-openssl.sh | |
| - name: Notarize and staple | |
| run: | | |
| set -euo pipefail | |
| ditto -c -k --keepParent \ | |
| src-tauri/target/release/bundle/macos/CodexMonitor.app \ | |
| CodexMonitor.zip | |
| xcrun notarytool submit CodexMonitor.zip \ | |
| --keychain-profile "$NOTARY_PROFILE_NAME" \ | |
| --wait | |
| xcrun stapler staple \ | |
| src-tauri/target/release/bundle/macos/CodexMonitor.app | |
| - name: Package artifacts | |
| run: | | |
| set -euo pipefail | |
| VERSION="${{ inputs.version }}" | |
| mkdir -p release-artifacts release-artifacts/dmg-root | |
| rm -rf release-artifacts/dmg-root/CodexMonitor.app | |
| ditto src-tauri/target/release/bundle/macos/CodexMonitor.app \ | |
| release-artifacts/dmg-root/CodexMonitor.app | |
| ditto -c -k --keepParent \ | |
| src-tauri/target/release/bundle/macos/CodexMonitor.app \ | |
| release-artifacts/CodexMonitor.zip | |
| hdiutil create -volname "CodexMonitor" \ | |
| -srcfolder release-artifacts/dmg-root \ | |
| -ov -format UDZO \ | |
| release-artifacts/CodexMonitor_${VERSION}_aarch64.dmg | |
| COPYFILE_DISABLE=1 tar -czf \ | |
| src-tauri/target/release/bundle/macos/CodexMonitor.app.tar.gz \ | |
| -C src-tauri/target/release/bundle/macos CodexMonitor.app | |
| npm run tauri signer sign -- \ | |
| -f "$HOME/.tauri/codexmonitor.key" \ | |
| -p "$TAURI_SIGNING_PRIVATE_KEY_PASSWORD" \ | |
| src-tauri/target/release/bundle/macos/CodexMonitor.app.tar.gz | |
| - name: Build latest.json | |
| run: | | |
| set -euo pipefail | |
| VERSION="${{ inputs.version }}" | |
| SIGNATURE=$(cat src-tauri/target/release/bundle/macos/CodexMonitor.app.tar.gz.sig) | |
| LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || true) | |
| if [ -n "$LAST_TAG" ]; then | |
| git log "${LAST_TAG}..HEAD" --pretty=format:"- %s" > release-artifacts/release-notes.md | |
| else | |
| git log --pretty=format:"- %s" > release-artifacts/release-notes.md | |
| fi | |
| python3 - <<PY | |
| import json | |
| from datetime import datetime, timezone | |
| from pathlib import Path | |
| notes = Path("release-artifacts/release-notes.md").read_text().strip() | |
| payload = { | |
| "version": "${VERSION}", | |
| "notes": notes, | |
| "pub_date": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), | |
| "platforms": { | |
| "darwin-aarch64": { | |
| "url": "https://github.com/Dimillian/CodexMonitor/releases/download/v${VERSION}/CodexMonitor.app.tar.gz", | |
| "signature": "${SIGNATURE}", | |
| } | |
| }, | |
| } | |
| Path("release-artifacts/latest.json").write_text(json.dumps(payload, indent=2) + "\\n") | |
| PY | |
| - name: Create GitHub release | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| VERSION="${{ inputs.version }}" | |
| gh release create "v${VERSION}" \ | |
| --title "v${VERSION}" \ | |
| --notes-file release-artifacts/release-notes.md \ | |
| --target "$GITHUB_SHA" \ | |
| release-artifacts/CodexMonitor.zip \ | |
| release-artifacts/CodexMonitor_${VERSION}_aarch64.dmg \ | |
| src-tauri/target/release/bundle/macos/CodexMonitor.app.tar.gz \ | |
| src-tauri/target/release/bundle/macos/CodexMonitor.app.tar.gz.sig \ | |
| release-artifacts/latest.json | |
| - name: Bump version and open PR | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| VERSION="${{ inputs.version }}" | |
| NEXT_VERSION=$(python3 - <<'PY' "$VERSION" | |
| import sys | |
| version = sys.argv[1] | |
| parts = version.split(".") | |
| if len(parts) != 3: | |
| raise SystemExit("Expected version like 0.X.Y") | |
| major, minor, patch = (int(p) for p in parts) | |
| print(f"{major}.{minor}.{patch + 1}") | |
| PY | |
| ) | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| npm version "$NEXT_VERSION" --no-git-tag-version | |
| python3 - <<PY | |
| import json | |
| from pathlib import Path | |
| path = Path("src-tauri/tauri.conf.json") | |
| data = json.loads(path.read_text()) | |
| data["version"] = "$NEXT_VERSION" | |
| path.write_text(json.dumps(data, indent=2) + "\\n") | |
| PY | |
| git checkout -b "chore/bump-version-${NEXT_VERSION}" | |
| git add package.json package-lock.json src-tauri/tauri.conf.json | |
| git commit -m "chore: bump version to ${NEXT_VERSION}" | |
| git push origin "chore/bump-version-${NEXT_VERSION}" | |
| gh pr create \ | |
| --title "chore: bump version to ${NEXT_VERSION}" \ | |
| --body "Post-release version bump to ${NEXT_VERSION}." \ | |
| --base main \ | |
| --head "chore/bump-version-${NEXT_VERSION}" |