Release #15
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 version. Defaults to VERSION. | |
| required: false | |
| type: string | |
| build_number: | |
| description: Build number. Defaults to the GitHub run number. | |
| required: false | |
| type: string | |
| dry_run: | |
| description: Build and verify on Jarvis without signing secrets, notarization, or draft release creation. | |
| required: false | |
| default: true | |
| type: boolean | |
| permissions: | |
| contents: write | |
| jobs: | |
| dry-run: | |
| name: Dry-run macOS artifact | |
| if: ${{ inputs.dry_run == true }} | |
| runs-on: | |
| - self-hosted | |
| - macOS | |
| - ARM64 | |
| - jarvis | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@v6 | |
| - name: Show toolchain | |
| run: | | |
| sw_vers | |
| xcodebuild -version | |
| swift --version | |
| curl --version | sed -n '1p' | |
| jq --version | |
| - name: Resolve release metadata | |
| run: | | |
| version="${{ inputs.version }}" | |
| build_number="${{ inputs.build_number }}" | |
| if [[ -z "$version" ]]; then | |
| version="$(tr -d '[:space:]' < VERSION)" | |
| fi | |
| if [[ -z "$build_number" ]]; then | |
| build_number="${{ github.run_number }}" | |
| fi | |
| { | |
| echo "BONSAI_VERSION=$version" | |
| echo "BONSAI_BUILD_NUMBER=$build_number" | |
| echo "BONSAI_RELEASE_DRY_RUN=true" | |
| } >> "$GITHUB_ENV" | |
| - name: Validate source | |
| run: make validate | |
| - name: Build dry-run archive | |
| run: make release-verify-archive | |
| - name: Verify release artifacts | |
| run: make release-verify-artifacts | |
| - name: Upload dry-run artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: Bonsai-${{ env.BONSAI_VERSION }}-${{ env.BONSAI_BUILD_NUMBER }}-dry-run | |
| path: | | |
| dist/release/Bonsai.dmg | |
| dist/release/Bonsai.release.plist | |
| if-no-files-found: error | |
| retention-days: 7 | |
| notarize: | |
| name: Notarized macOS artifact | |
| if: ${{ inputs.dry_run != true }} | |
| runs-on: | |
| - self-hosted | |
| - macOS | |
| - ARM64 | |
| - jarvis | |
| environment: release | |
| env: | |
| BONSAI_CODESIGN_IDENTITY: ${{ secrets.BONSAI_CODESIGN_IDENTITY }} | |
| BONSAI_NOTARY_PROFILE: bonsai-ci-notary | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@v6 | |
| - name: Show toolchain | |
| run: | | |
| sw_vers | |
| xcodebuild -version | |
| swift --version | |
| curl --version | sed -n '1p' | |
| jq --version | |
| - name: Resolve release metadata | |
| run: | | |
| version="${{ inputs.version }}" | |
| build_number="${{ inputs.build_number }}" | |
| if [[ -z "$version" ]]; then | |
| version="$(tr -d '[:space:]' < VERSION)" | |
| fi | |
| if [[ -z "$build_number" ]]; then | |
| build_number="${{ github.run_number }}" | |
| fi | |
| { | |
| echo "BONSAI_VERSION=$version" | |
| echo "BONSAI_BUILD_NUMBER=$build_number" | |
| echo "BONSAI_RELEASE_DRY_RUN=false" | |
| echo "BONSAI_NOTARY_KEYCHAIN=$RUNNER_TEMP/bonsai-signing.keychain-db" | |
| } >> "$GITHUB_ENV" | |
| - name: Validate source | |
| run: make validate | |
| - name: Check release secrets | |
| env: | |
| BONSAI_DEVELOPER_ID_CERTIFICATE_BASE64: ${{ secrets.BONSAI_DEVELOPER_ID_CERTIFICATE_BASE64 }} | |
| BONSAI_DEVELOPER_ID_CERTIFICATE_PASSWORD: ${{ secrets.BONSAI_DEVELOPER_ID_CERTIFICATE_PASSWORD }} | |
| BONSAI_NOTARY_APPLE_ID: ${{ secrets.BONSAI_NOTARY_APPLE_ID }} | |
| BONSAI_NOTARY_APP_PASSWORD: ${{ secrets.BONSAI_NOTARY_APP_PASSWORD }} | |
| BONSAI_NOTARY_TEAM_ID: ${{ secrets.BONSAI_NOTARY_TEAM_ID }} | |
| run: | | |
| missing=0 | |
| for name in \ | |
| BONSAI_CODESIGN_IDENTITY \ | |
| BONSAI_DEVELOPER_ID_CERTIFICATE_BASE64 \ | |
| BONSAI_DEVELOPER_ID_CERTIFICATE_PASSWORD \ | |
| BONSAI_NOTARY_APPLE_ID \ | |
| BONSAI_NOTARY_APP_PASSWORD \ | |
| BONSAI_NOTARY_TEAM_ID; do | |
| if [[ -z "${!name:-}" ]]; then | |
| echo "$name is required" | |
| missing=1 | |
| fi | |
| done | |
| exit "$missing" | |
| - name: Create signing keychain | |
| env: | |
| BONSAI_DEVELOPER_ID_CERTIFICATE_BASE64: ${{ secrets.BONSAI_DEVELOPER_ID_CERTIFICATE_BASE64 }} | |
| BONSAI_DEVELOPER_ID_CERTIFICATE_PASSWORD: ${{ secrets.BONSAI_DEVELOPER_ID_CERTIFICATE_PASSWORD }} | |
| run: | | |
| keychain_password="$(openssl rand -base64 32)" | |
| echo "::add-mask::$keychain_password" | |
| security create-keychain -p "$keychain_password" "$BONSAI_NOTARY_KEYCHAIN" | |
| security set-keychain-settings -lut 21600 "$BONSAI_NOTARY_KEYCHAIN" | |
| security unlock-keychain -p "$keychain_password" "$BONSAI_NOTARY_KEYCHAIN" | |
| security list-keychains -d user -s "$BONSAI_NOTARY_KEYCHAIN" | |
| security default-keychain -s "$BONSAI_NOTARY_KEYCHAIN" | |
| developer_id_g2_path="$RUNNER_TEMP/DeveloperIDG2CA.cer" | |
| curl --fail --show-error --silent --location \ | |
| --retry 3 \ | |
| --output "$developer_id_g2_path" \ | |
| https://www.apple.com/certificateauthority/DeveloperIDG2CA.cer | |
| security import "$developer_id_g2_path" \ | |
| -k "$BONSAI_NOTARY_KEYCHAIN" \ | |
| -T /usr/bin/codesign \ | |
| -T /usr/bin/security | |
| certificate_path="$RUNNER_TEMP/bonsai-developer-id.p12" | |
| printf '%s' "$BONSAI_DEVELOPER_ID_CERTIFICATE_BASE64" | base64 --decode > "$certificate_path" | |
| security import "$certificate_path" \ | |
| -k "$BONSAI_NOTARY_KEYCHAIN" \ | |
| -P "$BONSAI_DEVELOPER_ID_CERTIFICATE_PASSWORD" \ | |
| -T /usr/bin/codesign \ | |
| -T /usr/bin/security | |
| security set-key-partition-list \ | |
| -S apple-tool:,apple:,codesign: \ | |
| -s \ | |
| -k "$keychain_password" \ | |
| "$BONSAI_NOTARY_KEYCHAIN" | |
| rm -f "$certificate_path" "$developer_id_g2_path" | |
| - name: Store notarization credentials | |
| env: | |
| BONSAI_NOTARY_APPLE_ID: ${{ secrets.BONSAI_NOTARY_APPLE_ID }} | |
| BONSAI_NOTARY_APP_PASSWORD: ${{ secrets.BONSAI_NOTARY_APP_PASSWORD }} | |
| BONSAI_NOTARY_TEAM_ID: ${{ secrets.BONSAI_NOTARY_TEAM_ID }} | |
| run: | | |
| xcrun notarytool store-credentials "$BONSAI_NOTARY_PROFILE" \ | |
| --apple-id "$BONSAI_NOTARY_APPLE_ID" \ | |
| --team-id "$BONSAI_NOTARY_TEAM_ID" \ | |
| --password "$BONSAI_NOTARY_APP_PASSWORD" \ | |
| --keychain "$BONSAI_NOTARY_KEYCHAIN" | |
| - name: Check release credentials | |
| run: | | |
| make release-doctor | |
| make release-check-credentials | |
| - name: Build signed and notarized archive | |
| run: make release-notarize | |
| - name: Verify release artifacts | |
| run: make release-verify-artifacts | |
| - name: Upload release artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: Bonsai-${{ env.BONSAI_VERSION }}-${{ env.BONSAI_BUILD_NUMBER }} | |
| path: | | |
| dist/release/Bonsai.dmg | |
| dist/release/Bonsai.release.plist | |
| if-no-files-found: error | |
| retention-days: 30 | |
| - name: Create draft GitHub release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: make release-draft | |
| - name: Clean up signing keychain | |
| if: always() | |
| run: | | |
| if [[ -n "${BONSAI_NOTARY_KEYCHAIN:-}" && -f "$BONSAI_NOTARY_KEYCHAIN" ]]; then | |
| security delete-keychain "$BONSAI_NOTARY_KEYCHAIN" | |
| fi |