mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 08:02:28 +00:00
The Windows matrix defaults to pwsh, so assert-github-release-is-draft.mjs received an empty argv and failed with "tag is required" after the signed installer was already uploaded. Force bash, interpolate the tag in YAML, and fall back to env TAG.
198 lines
8.2 KiB
YAML
198 lines
8.2 KiB
YAML
name: Release macOS Build
|
|
|
|
run-name: Mac release build ${{ inputs.tag }} (${{ inputs.release_run_id }})
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
tag:
|
|
description: Release tag whose draft should receive macOS artifacts
|
|
required: true
|
|
type: string
|
|
release_run_id:
|
|
description: release-cut workflow run that requested this build
|
|
required: true
|
|
type: string
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
concurrency:
|
|
group: release-mac-build-${{ inputs.tag }}
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
build-mac:
|
|
if: github.repository == 'stablyai/orca'
|
|
# Why: this workflow is outside the SignPath signing run, so Blacksmith
|
|
# cannot enter Windows artifact provenance while mac notarization gets the
|
|
# faster runner.
|
|
runs-on: blacksmith-6vcpu-macos-15
|
|
timeout-minutes: 60
|
|
env:
|
|
NODE_OPTIONS: --max-old-space-size=4096
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v6
|
|
with:
|
|
ref: refs/tags/${{ inputs.tag }}
|
|
|
|
- name: Restore draft-publish scripts from the workflow ref
|
|
env:
|
|
WORKFLOW_SHA: ${{ github.workflow_sha }}
|
|
run: |
|
|
set -euo pipefail
|
|
git fetch --no-tags --depth=1 origin "$WORKFLOW_SHA"
|
|
git checkout "$WORKFLOW_SHA" -- config/scripts/assert-github-release-is-draft.mjs
|
|
|
|
- name: Setup pnpm
|
|
uses: pnpm/setup@v2
|
|
with:
|
|
install: false
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v6
|
|
with:
|
|
node-version-file: package.json
|
|
cache: pnpm
|
|
cache-dependency-path: |
|
|
pnpm-lock.yaml
|
|
mobile/pnpm-lock.yaml
|
|
|
|
# Cache the Electron binary + electron-builder tool downloads (notarytool,
|
|
# winCodeSign, nsis, squirrel, AppImage). Saves ~30-90s per job, incl. mac.
|
|
- name: Cache electron-builder downloads
|
|
uses: actions/cache@v5
|
|
with:
|
|
path: |
|
|
~/Library/Caches/electron
|
|
~/Library/Caches/electron-builder
|
|
key: electron-builder-mac-${{ hashFiles('pnpm-lock.yaml') }}
|
|
restore-keys: |
|
|
electron-builder-mac-
|
|
|
|
# Why: pnpm install triggers electron's postinstall, which downloads the
|
|
# Electron binary from GitHub release assets. GitHub's download CDN
|
|
# occasionally returns 504s that fail the whole release. Retry on
|
|
# failure so transient network errors don't require a manual re-run.
|
|
# Why both CPUs: the mac config packages x64 and arm64 from this arm64
|
|
# runner, so the install must carry both variants of the native optional deps.
|
|
- name: Install dependencies
|
|
uses: nick-fields/retry@v4
|
|
with:
|
|
timeout_minutes: 10
|
|
max_attempts: 3
|
|
retry_wait_seconds: 30
|
|
command: pnpm install --frozen-lockfile --cpu=current,x64,arm64
|
|
|
|
# Why here: electron-builder's beforePack requires out/mobile-web, and the bundle
|
|
# build resolves React Native and Expo from mobile/node_modules.
|
|
- uses: ./.github/actions/install-mobile-dependencies
|
|
|
|
- name: Verify macOS signing environment
|
|
run: node config/scripts/verify-macos-release-env.mjs
|
|
env:
|
|
CSC_LINK: ${{ secrets.MAC_CERTS }}
|
|
CSC_KEY_PASSWORD: ${{ secrets.MAC_CERTS_PASSWORD }}
|
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
|
|
# Why: `plutil -lint` accepts duplicate plist keys, but `codesign`
|
|
# rejects duplicate entitlements after the expensive app build.
|
|
- name: Verify macOS entitlements
|
|
run: pnpm verify:macos-entitlements
|
|
|
|
# Why: telemetry's transport gate (`src/main/telemetry/client.ts:IS_OFFICIAL_BUILD`)
|
|
# requires the build identity to be the literal string `stable` or `rc`,
|
|
# substituted by electron-vite's `define` block at build time.
|
|
- name: Classify release tag for telemetry build identity
|
|
id: tag-classify
|
|
shell: bash
|
|
env:
|
|
TAG: ${{ inputs.tag }}
|
|
run: |
|
|
set -euo pipefail
|
|
# Why the optional trailing identifier: suffixed side-branch RCs
|
|
# (vX.Y.Z-rc.N.perf) are rc-channel prerelease builds — same telemetry
|
|
# identity as plain RCs.
|
|
if [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+(\.[0-9A-Za-z]+)?$ ]]; then
|
|
identity=rc
|
|
elif [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
identity=stable
|
|
else
|
|
echo "::error::Tag $TAG does not match stable or rc pattern; refusing to build official artifact"
|
|
exit 1
|
|
fi
|
|
echo "identity=$identity" >>"$GITHUB_OUTPUT"
|
|
echo "Classified $TAG as $identity"
|
|
|
|
- name: Build app
|
|
run: pnpm build:release
|
|
env:
|
|
# Why: Vite's web build crossed Node's default old-space ceiling on
|
|
# the macOS release runner, leaving v1.4.2-rc.8 as an incomplete draft.
|
|
NODE_OPTIONS: --max-old-space-size=4096
|
|
ORCA_BUILD_IDENTITY: ${{ steps.tag-classify.outputs.identity }}
|
|
ORCA_DIAGNOSTICS_TOKEN_URL: https://www.onorca.dev/diagnostics/token
|
|
ORCA_POSTHOG_WRITE_KEY: ${{ secrets.ORCA_POSTHOG_WRITE_KEY }}
|
|
|
|
- name: Gate runtime file-watcher process isolation
|
|
run: |
|
|
# Why: #8212 is a native-process crash contract. Prove both the Node
|
|
# host and the exact Electron runtime survive SIGSEGV before packaging.
|
|
node config/scripts/runtime-file-watcher-fault-harness.mjs
|
|
ELECTRON_RUN_AS_NODE=1 pnpm exec electron config/scripts/runtime-file-watcher-fault-harness.mjs
|
|
|
|
- name: Gate SSH relay watcher process isolation
|
|
run: |
|
|
# Why: the remote native watcher shares a daemon with live PTYs.
|
|
# Kill only its child and require both PTY and watch recovery before packaging.
|
|
node config/scripts/relay-watcher-fault-harness.mjs
|
|
|
|
- name: Abort if the parent release-cut run was cancelled
|
|
# Why: this workflow is dispatched separately, so cancelling release-cut
|
|
# does not stop mac `--publish always`. A cancelled parent left v1.4.206
|
|
# public with only a partial mac upload.
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
PARENT_RUN: ${{ inputs.release_run_id }}
|
|
run: |
|
|
set -euo pipefail
|
|
conclusion="$(gh api "repos/$GITHUB_REPOSITORY/actions/runs/$PARENT_RUN" --jq '.conclusion // empty')"
|
|
if [[ "$conclusion" == "cancelled" || "$conclusion" == "failure" || "$conclusion" == "timed_out" ]]; then
|
|
echo "::error::Parent release-cut run $PARENT_RUN is $conclusion; refusing to publish mac artifacts."
|
|
exit 1
|
|
fi
|
|
|
|
- name: Publish release artifacts (macOS)
|
|
uses: nick-fields/retry@v4
|
|
with:
|
|
timeout_minutes: 45
|
|
max_attempts: 3
|
|
retry_wait_seconds: 30
|
|
command: node config/scripts/ensure-native-runtime.mjs --runtime=electron && ORCA_MAC_RELEASE=1 pnpm exec electron-builder --config config/electron-builder.config.cjs --mac --publish always -c.publish.releaseType=draft
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
CSC_LINK: ${{ secrets.MAC_CERTS }}
|
|
CSC_KEY_PASSWORD: ${{ secrets.MAC_CERTS_PASSWORD }}
|
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
|
|
- name: Verify release remains draft after artifact upload
|
|
# Why: re-draft immediately if electron-builder flipped the GitHub
|
|
# release public, then fail. Checking without restoring leaves
|
|
# /releases/latest serving a missing Windows exe.
|
|
shell: bash
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
TAG: ${{ inputs.tag }}
|
|
run: node config/scripts/assert-github-release-is-draft.mjs "${{ inputs.tag }}"
|
|
|
|
# Why post-publish for macOS: electron-builder packs and uploads in a
|
|
# single `--publish always` invocation, so there is no cheap insertion
|
|
# point between pack and upload without splitting those steps.
|
|
- name: Verify telemetry constants present in app.asar
|
|
run: node config/scripts/verify-telemetry-constants.mjs
|