6bf8bebf51
CI / Test and Build (push) Failing after 1s
CI / Migrate Dev DB (push) Has been skipped
CI / Migrate DB (push) Has been skipped
CodeQL / Analyze actions (push) Has been cancelled
CodeQL / Analyze javascript-typescript (push) Has been cancelled
CI / Detect Version (push) Has been cancelled
CI / Detect Desktop Changes (push) Has been cancelled
CI / Build AMD64 (blacksmith-2vcpu-ubuntu-2404, ./docker/cron.Dockerfile, ubuntu-latest, ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Build AMD64 (blacksmith-2vcpu-ubuntu-2404, ./docker/db.Dockerfile, ECR_MIGRATIONS, ubuntu-latest, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (blacksmith-4vcpu-ubuntu-2404, ./docker/pii.Dockerfile, ECR_PII, ubuntu-latest, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (blacksmith-4vcpu-ubuntu-2404, ./docker/realtime.Dockerfile, ECR_REALTIME, ubuntu-latest, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build AMD64 (blacksmith-8vcpu-ubuntu-2404, ./docker/app.Dockerfile, ECR_APP, linux-x64-8-core, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/cron.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/db.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/pii.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/realtime.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-8vcpu-ubuntu-2404-arm, ./docker/app.Dockerfile, linux-arm64-8-core, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
Helm Chart / Lint, test, and validate chart (push) Has been cancelled
Helm Chart / Chart version bumped (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
CI / Build Dev ECR (blacksmith-8vcpu-ubuntu-2404, ./docker/app.Dockerfile, ECR_APP, linux-x64-8-core) (push) Has been cancelled
CI / Promote Images (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-2vcpu-ubuntu-2404, ./docker/db.Dockerfile, ECR_MIGRATIONS, ubuntu-latest) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-4vcpu-ubuntu-2404, ./docker/pii.Dockerfile, ECR_PII, ubuntu-latest) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-4vcpu-ubuntu-2404, ./docker/realtime.Dockerfile, ECR_REALTIME, ubuntu-latest) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Check Desktop Signing Secrets (push) Has been cancelled
CI / Desktop Release (push) Has been cancelled
CI / Create Desktop Prerelease (push) Has been cancelled
CI / Desktop Prerelease Build (push) Has been cancelled
CI / Publish Desktop Prerelease (push) Has been cancelled
CI / Prune Desktop Prereleases (push) Has been cancelled
Helm Chart / Install on kind and run helm test (push) Has been cancelled
213 lines
7.9 KiB
YAML
213 lines
7.9 KiB
YAML
name: Desktop Release (macOS)
|
|
|
|
# Builds, signs, notarizes, and uploads the desktop app to an existing GitHub
|
|
# release. Ordering is load-bearing: scripts/create-single-release.ts skips
|
|
# creation when the tag already exists, so this workflow must never create the
|
|
# release itself — it only uploads assets after create-release ran (wired via
|
|
# workflow_call from ci.yml with needs: [create-release]).
|
|
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
version:
|
|
description: Release tag (vX.Y.Z) to attach desktop artifacts to
|
|
required: true
|
|
type: string
|
|
publish:
|
|
description: Upload artifacts to the GitHub release
|
|
required: false
|
|
type: boolean
|
|
default: true
|
|
sign:
|
|
description: Sign and notarize with the Apple Developer identity. When
|
|
false (prerelease testing before the signing secrets exist) the build
|
|
is packaged unsigned; installed shells detect this and offer manual
|
|
downloads instead of Squirrel installs.
|
|
required: false
|
|
type: boolean
|
|
default: true
|
|
workflow_dispatch:
|
|
inputs:
|
|
version:
|
|
description: Release tag (vX.Y.Z) to attach desktop artifacts to
|
|
required: true
|
|
type: string
|
|
publish:
|
|
description: Upload artifacts to the GitHub release
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
sign:
|
|
description: Sign and notarize with the Apple Developer identity
|
|
required: false
|
|
type: boolean
|
|
default: true
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
jobs:
|
|
build-sign-notarize:
|
|
name: Build, Sign, Notarize
|
|
runs-on: macos-14
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
|
|
- name: Setup Bun
|
|
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
|
with:
|
|
bun-version: 1.3.14
|
|
|
|
- name: Setup Node
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
|
|
- name: Cache Electron binaries
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/Library/Caches/electron
|
|
~/Library/Caches/electron-builder
|
|
key: electron-cache-${{ runner.os }}-${{ hashFiles('apps/desktop/package.json') }}
|
|
|
|
- name: Install dependencies
|
|
run: bun install --frozen-lockfile
|
|
|
|
- name: Inject release version
|
|
env:
|
|
VERSION: ${{ inputs.version }}
|
|
run: |
|
|
SEMVER="${VERSION#v}"
|
|
if ! [[ "$SEMVER" =~ ^[0-9]+\.[0-9]+\.[0-9]+([-.].+)?$ ]]; then
|
|
echo "Refusing to build: '$VERSION' is not a vX.Y.Z release tag" >&2
|
|
exit 1
|
|
fi
|
|
npm pkg set version="$SEMVER" --prefix apps/desktop
|
|
INJECTED="$(node -p "require('./apps/desktop/package.json').version")"
|
|
if [ "$INJECTED" != "$SEMVER" ]; then
|
|
echo "Version injection mismatch: wanted $SEMVER got $INJECTED" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Prerelease versions carry their environment in the tag: -alpha.N is a
|
|
# dev build, -beta.N a staging build. The channel decides the app's
|
|
# identity (name/bundle id — a separate app per environment, installable
|
|
# side by side) and the default origin baked into the bundle, which in
|
|
# turn selects the update feed the installed app polls.
|
|
- name: Resolve channel identity
|
|
id: channel
|
|
env:
|
|
VERSION: ${{ inputs.version }}
|
|
run: |
|
|
case "$VERSION" in
|
|
*-alpha.*)
|
|
NAME='Sim Dev'; APP_ID=ai.sim.desktop.dev; ORIGIN=https://www.dev.sim.ai ;;
|
|
*-beta.*)
|
|
NAME='Sim Staging'; APP_ID=ai.sim.desktop.staging; ORIGIN=https://www.staging.sim.ai ;;
|
|
*)
|
|
NAME='Sim'; APP_ID=ai.sim.desktop; ORIGIN='' ;;
|
|
esac
|
|
{
|
|
echo "name=$NAME"
|
|
echo "app_id=$APP_ID"
|
|
echo "origin=$ORIGIN"
|
|
} >> "$GITHUB_OUTPUT"
|
|
echo "Building $NAME ($APP_ID) default origin: ${ORIGIN:-production}"
|
|
|
|
- name: Bundle main and preload
|
|
working-directory: apps/desktop
|
|
env:
|
|
SIM_DESKTOP_DEFAULT_ORIGIN: ${{ steps.channel.outputs.origin }}
|
|
run: bun run build
|
|
|
|
- name: Write App Store Connect API key
|
|
if: ${{ inputs.sign }}
|
|
env:
|
|
APPLE_API_KEY_P8: ${{ secrets.APPLE_API_KEY_P8 }}
|
|
run: |
|
|
mkdir -p "$RUNNER_TEMP/appstoreconnect"
|
|
printf '%s' "$APPLE_API_KEY_P8" > "$RUNNER_TEMP/appstoreconnect/AuthKey.p8"
|
|
chmod 600 "$RUNNER_TEMP/appstoreconnect/AuthKey.p8"
|
|
|
|
- name: Package, sign, and notarize
|
|
if: ${{ inputs.sign }}
|
|
working-directory: apps/desktop
|
|
env:
|
|
CSC_LINK: ${{ secrets.CSC_LINK }}
|
|
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
|
|
# Absolute path — @electron/notarize reads this via Node fs, which
|
|
# does not expand a leading '~'.
|
|
APPLE_API_KEY: ${{ runner.temp }}/appstoreconnect/AuthKey.p8
|
|
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
|
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
PRODUCT_NAME: ${{ steps.channel.outputs.name }}
|
|
APP_ID: ${{ steps.channel.outputs.app_id }}
|
|
run: >
|
|
bunx electron-builder --mac --publish never
|
|
-c.productName="$PRODUCT_NAME" -c.appId="$APP_ID"
|
|
|
|
# Unsigned prerelease path: no Developer ID, no notarization. The
|
|
# binaries end up ad-hoc/linker-signed, which runs locally but gets
|
|
# quarantined when downloaded — fine for testing the update pipeline.
|
|
- name: Package unsigned
|
|
if: ${{ !inputs.sign }}
|
|
working-directory: apps/desktop
|
|
env:
|
|
CSC_IDENTITY_AUTO_DISCOVERY: 'false'
|
|
PRODUCT_NAME: ${{ steps.channel.outputs.name }}
|
|
APP_ID: ${{ steps.channel.outputs.app_id }}
|
|
run: >
|
|
bunx electron-builder --mac --publish never -c.mac.notarize=false
|
|
-c.productName="$PRODUCT_NAME" -c.appId="$APP_ID"
|
|
|
|
- name: Validate signature and notarization
|
|
if: ${{ inputs.sign }}
|
|
run: |
|
|
DMG="$(ls apps/desktop/release/*.dmg | head -1)"
|
|
xcrun stapler validate "$DMG"
|
|
hdiutil attach "$DMG" -mountpoint /tmp/sim-dmg -nobrowse -quiet
|
|
spctl --assess --type execute --verbose /tmp/sim-dmg/*.app
|
|
codesign --verify --deep --strict /tmp/sim-dmg/*.app
|
|
hdiutil detach /tmp/sim-dmg -quiet
|
|
|
|
- name: Upload artifacts to the release
|
|
if: ${{ inputs.publish }}
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
VERSION: ${{ inputs.version }}
|
|
run: |
|
|
# electron-builder's GitHub provider always names the manifest
|
|
# latest-mac.yml (channels are a generic-provider concept), and the
|
|
# update feed expects exactly that asset name on every release —
|
|
# normalize defensively in case a config change ever produces a
|
|
# channel-named manifest.
|
|
YML="$(find apps/desktop/release -maxdepth 1 -name '*-mac.yml' | head -1)"
|
|
if [ -z "$YML" ]; then
|
|
echo "::error::No *-mac.yml updater manifest found in apps/desktop/release"
|
|
exit 1
|
|
fi
|
|
if [ "$(basename "$YML")" != "latest-mac.yml" ]; then
|
|
mv "$YML" apps/desktop/release/latest-mac.yml
|
|
fi
|
|
gh release upload "$VERSION" \
|
|
apps/desktop/release/*.dmg \
|
|
apps/desktop/release/*.zip \
|
|
apps/desktop/release/*.blockmap \
|
|
apps/desktop/release/latest-mac.yml \
|
|
--clobber
|
|
|
|
- name: Upload artifacts to the workflow run
|
|
if: ${{ !inputs.publish }}
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: sim-desktop-${{ inputs.version }}
|
|
path: |
|
|
apps/desktop/release/*.dmg
|
|
apps/desktop/release/*.zip
|
|
apps/desktop/release/*.blockmap
|
|
apps/desktop/release/*-mac.yml
|
|
retention-days: 7
|