Files
openwork/.github/workflows/alpha-macos-aarch64.yml

235 lines
8.7 KiB
YAML

name: Alpha Channel (macOS arm64)
# Every app-related push to `dev` publishes a fresh macOS arm64 build to the
# single rolling `alpha-macos-latest` release. Each run appends
# uniquely-versioned dmg, zip, and blockmap assets, then re-uploads
# `latest-mac.yml` last so the manifest never references missing assets.
#
# Assets older than the retention window are pruned. Per-run GitHub releases
# are no longer created.
#
# See .github/workflows/release-macos-aarch64.yml for the stable channel.
on:
push:
branches:
- dev
paths:
- apps/app/**
- apps/desktop/**
- apps/server/**
- packages/docs/**
- packages/enterprise-mcp-client/**
- packages/handsfree/**
- packages/install-config/**
- packages/paths/**
- packages/types/**
- packages/ui/**
- patches/**
- scripts/release/**
- constants.json
- package.json
- pnpm-lock.yaml
- pnpm-workspace.yaml
- .github/workflows/alpha-macos-aarch64.yml
workflow_dispatch:
inputs:
publish:
description: "Publish the packaged build to the alpha channel release (leave off for build-only validation)"
required: false
type: boolean
default: false
channel_tag:
description: "Channel release tag to publish to (override for staging validation)"
required: false
type: string
default: "alpha-macos-latest"
permissions:
contents: write
concurrency:
group: alpha-macos-aarch64-${{ github.ref }}
cancel-in-progress: true
jobs:
publish-alpha-macos-aarch64:
name: Build + Publish alpha (aarch64-apple-darwin)
runs-on: macos-14
timeout-minutes: 180
env:
ALPHA_RELEASE_NAME: OpenWork Alpha (macOS arm64)
# Apple signing + notarization are required so alpha bundles install
# and launch without Gatekeeper friction. Alpha builds are served
# from GitHub Releases like stable, just from a different tag.
MACOS_NOTARIZE: ${{ vars.MACOS_NOTARIZE || 'true' }}
OPENWORK_DESKTOP_SENTRY_DSN: ${{ secrets.OPENWORK_DESKTOP_SENTRY_DSN || vars.OPENWORK_DESKTOP_SENTRY_DSN }}
OPENWORK_DESKTOP_SENTRY_TRACES_SAMPLE_RATE: ${{ vars.OPENWORK_DESKTOP_SENTRY_TRACES_SAMPLE_RATE || '0.01' }}
steps:
- name: Checkout
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
ref: ${{ github.sha }}
# Alpha versions are computed from the latest stable v* tag
# (package.json holds a permanent 0.0.0-dev placeholder).
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 24
- name: Setup pnpm
uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4
with:
version: 11.4.0
- name: Setup Bun
uses: oven-sh/setup-bun@f4d14e03ff726c06358e5557344e1da148b56cf7 # v1
with:
bun-version: "1.3.6"
- name: Get pnpm store path
id: pnpm-store
shell: bash
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
- name: Cache pnpm store
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5
continue-on-error: true
with:
path: ${{ steps.pnpm-store.outputs.path }}
key: macos-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
macos-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Resolve alpha version
id: alpha-version
shell: bash
env:
GITHUB_RUN_NUMBER: ${{ github.run_number }}
GITHUB_SHA: ${{ github.sha }}
run: |
set -euo pipefail
# Alpha builds advertise the *next* patch after the latest stable
# tag so semver comparison makes the alpha newer than the current
# stable (e.g. stable 0.11.207 < alpha 0.11.208-alpha.<run>). Once
# stable 0.11.208 ships, its semver beats the alpha prerelease tag
# and alpha users cleanly migrate forward. Tags are the version
# source of truth — package.json is a permanent placeholder.
base="$(node scripts/release/versions.mjs next --bump patch)"
run="${GITHUB_RUN_NUMBER:-0}"
sha="$(printf '%.7s' "${GITHUB_SHA:-local}")"
echo "alpha_version=${base}-alpha.${run}+${sha}" >> "$GITHUB_OUTPUT"
echo "base_version=${base}" >> "$GITHUB_OUTPUT"
- name: Write alpha Electron package version
shell: bash
env:
ALPHA_VERSION: ${{ steps.alpha-version.outputs.alpha_version }}
run: node scripts/release/stamp-version.mjs --version "$ALPHA_VERSION"
- name: Write notary API key
if: env.MACOS_NOTARIZE == 'true'
env:
APPLE_NOTARY_API_KEY_P8_BASE64: ${{ secrets.APPLE_NOTARY_API_KEY_P8_BASE64 }}
run: |
set -euo pipefail
NOTARY_KEY_PATH="$RUNNER_TEMP/AuthKey.p8"
printf '%s' "$APPLE_NOTARY_API_KEY_P8_BASE64" | base64 --decode > "$NOTARY_KEY_PATH"
chmod 600 "$NOTARY_KEY_PATH"
echo "NOTARY_KEY_PATH=$NOTARY_KEY_PATH" >> "$GITHUB_ENV"
- name: Reject unsigned Electron alpha release
if: env.MACOS_NOTARIZE != 'true'
shell: bash
run: |
echo "Electron alpha artifacts must be signed and notarized. Set MACOS_NOTARIZE=true and provide Apple signing secrets." >&2
exit 1
- name: Build Electron alpha app
if: env.MACOS_NOTARIZE == 'true'
shell: bash
env:
TARGET: aarch64-apple-darwin
run: pnpm --filter @openwork/desktop build:electron
- name: Package Electron alpha (macOS, signed + notarized)
if: env.MACOS_NOTARIZE == 'true'
env:
CSC_LINK: ${{ secrets.APPLE_CODESIGN_CERT_P12_BASE64 }}
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CODESIGN_CERT_PASSWORD }}
MACOS_NOTARIZE: true
APPLE_API_KEY: ${{ secrets.APPLE_NOTARY_API_KEY_ID }}
APPLE_API_ISSUER: ${{ secrets.APPLE_NOTARY_API_ISSUER_ID }}
APPLE_API_KEY_PATH: ${{ env.NOTARY_KEY_PATH }}
run: |
set -euo pipefail
pnpm --dir apps/desktop exec electron-builder \
--config electron-builder.yml \
--mac \
--arm64 \
--publish never
- name: Publish alpha build to rolling release
if: env.MACOS_NOTARIZE == 'true' && (github.event_name == 'push' || inputs.publish == true)
shell: bash
env:
GH_TOKEN: ${{ github.token }}
CHANNEL_TAG: ${{ inputs.channel_tag || 'alpha-macos-latest' }}
run: |
set -euo pipefail
# Alpha assets may only ever land on alpha channel releases. This
# guard makes it impossible to clobber a stable release (and its
# latest-mac.yml) via a mistyped channel_tag dispatch input.
case "$CHANNEL_TAG" in
alpha-macos-*) ;;
*)
echo "Refusing to publish alpha assets to non-alpha tag: $CHANNEL_TAG" >&2
exit 1
;;
esac
if ! gh release view "$CHANNEL_TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
gh release create "$CHANNEL_TAG" \
--repo "$GITHUB_REPOSITORY" \
--title "$ALPHA_RELEASE_NAME" \
--notes "Rolling alpha channel for OpenWork macOS arm64 builds. Each publish adds versioned updater assets and advances the channel manifest." \
--target "$GITHUB_SHA" \
--prerelease
fi
shopt -s nullglob
assets=(
apps/desktop/dist-electron/*.dmg
apps/desktop/dist-electron/*.zip
apps/desktop/dist-electron/*.blockmap
)
if [ ${#assets[@]} -eq 0 ]; then
echo "No Electron alpha assets found in apps/desktop/dist-electron" >&2
exit 1
fi
gh release upload "$CHANNEL_TAG" "${assets[@]}" \
--repo "$GITHUB_REPOSITORY" \
--clobber
# Publish the manifest last so an interrupted upload never points at missing assets.
gh release upload "$CHANNEL_TAG" apps/desktop/dist-electron/latest-mac.yml \
--repo "$GITHUB_REPOSITORY" \
--clobber
- name: Prune alpha assets beyond retention window
if: env.MACOS_NOTARIZE == 'true' && (github.event_name == 'push' || inputs.publish == true)
shell: bash
env:
GH_TOKEN: ${{ github.token }}
CHANNEL_TAG: ${{ inputs.channel_tag || 'alpha-macos-latest' }}
run: node scripts/release/prune-alpha-assets.mjs --repo "$GITHUB_REPOSITORY" --tag "$CHANNEL_TAG" --keep 100