155 lines
6.1 KiB
YAML
155 lines
6.1 KiB
YAML
# Desktop release builds — macOS (.dmg, arm64 + Intel) and Windows (.msi + NSIS .exe).
|
|
#
|
|
# CI calls the SAME scripts developers run locally (platform/packaging/build_dmg.sh and
|
|
# build_windows.ps1); this file only provisions the toolchain (Node, Rust, a Python venv at
|
|
# platform/.venv with PyInstaller) and publishes the results.
|
|
#
|
|
# Triggers:
|
|
# - tag push `v*` → builds all targets and attaches them to a DRAFT GitHub Release
|
|
# (review, then publish by hand).
|
|
# - manual run → builds and uploads workflow artifacts only (no release).
|
|
#
|
|
# Each installer is uploaded twice: once with its versioned name (archive) and once with a
|
|
# stable name (OpenCoworker-macos-arm64.dmg, …) so the website can link to
|
|
# github.com/<repo>/releases/latest/download/<stable-name>
|
|
# and never need updating.
|
|
#
|
|
# macOS signing + notarization: Tauri's bundler handles both during `tauri build` when the
|
|
# APPLE_* env vars are present (import cert → sign app + sidecar with hardened runtime →
|
|
# notarize via notarytool → staple). Driven by repo secrets:
|
|
# APPLE_CERTIFICATE base64 .p12 (Developer ID Application cert + key)
|
|
# APPLE_CERTIFICATE_PASSWORD the .p12 export password
|
|
# APPLE_SIGNING_IDENTITY e.g. "Developer ID Application: Name (TEAMID)"
|
|
# APPLE_API_KEY_CONTENT base64 App Store Connect API .p8 (notarytool)
|
|
# APPLE_API_KEY the API key id
|
|
# APPLE_API_ISSUER the API issuer id
|
|
# When the secrets are absent (forks, scratch runs) the build degrades to unsigned —
|
|
# installable via `xattr -cr`. Windows remains unsigned (Authenticode is a later step).
|
|
|
|
name: Release
|
|
|
|
on:
|
|
push:
|
|
tags: ["v*", "app-v*"]
|
|
workflow_dispatch:
|
|
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
|
|
jobs:
|
|
build:
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
# No Intel macOS target: macos-13 (the last Intel runner image) is deprecated and
|
|
# its queue waits run to hours, which blocks the release job. Intel Macs are
|
|
# 2020-and-earlier hardware — revisit only if beta users actually ask.
|
|
- os: macos-latest # Apple Silicon
|
|
slug: macos-arm64
|
|
- os: windows-latest
|
|
slug: windows
|
|
runs-on: ${{ matrix.os }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 20
|
|
cache: npm
|
|
cache-dependency-path: platform/surfaces/gui/package-lock.json
|
|
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
workspaces: platform/surfaces/gui/src-tauri
|
|
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: "3.12"
|
|
|
|
- name: Set up the sidecar venv (platform/.venv)
|
|
# The build scripts expect a venv at platform/.venv with the package + PyInstaller.
|
|
# typer/tzdata are build-time-only (PyInstaller walks mcp.cli, which needs typer;
|
|
# tzdata ships zoneinfo for Windows). The .pth puts the repo-root `aisuite` package
|
|
# on the venv's path (it isn't pip-installed — same as local dev).
|
|
run: |
|
|
python -m venv platform/.venv
|
|
if [ "$RUNNER_OS" = "Windows" ]; then VPY=platform/.venv/Scripts/python; else VPY=platform/.venv/bin/python; fi
|
|
"$VPY" -m pip install --upgrade pip
|
|
"$VPY" -m pip install -e platform pyinstaller typer tzdata
|
|
"$VPY" -c "import sysconfig, pathlib; pathlib.Path(sysconfig.get_paths()['purelib'], 'aisuite-repo.pth').write_text(str(pathlib.Path('.').resolve()))"
|
|
"$VPY" -c "import aisuite, coworker" # fail fast if either import breaks
|
|
|
|
- name: npm ci
|
|
working-directory: platform/surfaces/gui
|
|
run: npm ci
|
|
|
|
- name: Build .dmg (macOS)
|
|
if: runner.os == 'macOS'
|
|
env:
|
|
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
|
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
|
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
|
APPLE_API_KEY_CONTENT: ${{ secrets.APPLE_API_KEY_CONTENT }}
|
|
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
|
|
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
|
run: |
|
|
# Unset empty APPLE_* vars so runs without secrets stay cleanly unsigned
|
|
# (Tauri treats a present-but-empty var as a config error).
|
|
for v in APPLE_CERTIFICATE APPLE_CERTIFICATE_PASSWORD APPLE_SIGNING_IDENTITY APPLE_API_KEY APPLE_API_ISSUER; do
|
|
[ -n "$(eval echo "\${$v:-}")" ] || unset "$v"
|
|
done
|
|
if [ -n "${APPLE_API_KEY_CONTENT:-}" ]; then
|
|
echo "$APPLE_API_KEY_CONTENT" | base64 -d > "$RUNNER_TEMP/AuthKey.p8"
|
|
export APPLE_API_KEY_PATH="$RUNNER_TEMP/AuthKey.p8"
|
|
fi
|
|
unset APPLE_API_KEY_CONTENT
|
|
bash platform/packaging/build_dmg.sh
|
|
|
|
- name: Build .msi + NSIS .exe (Windows)
|
|
if: runner.os == 'Windows'
|
|
shell: pwsh
|
|
run: ./platform/packaging/build_windows.ps1
|
|
|
|
- name: Stage artifacts (versioned + stable names)
|
|
run: |
|
|
mkdir -p out
|
|
BUNDLE=platform/surfaces/gui/src-tauri/target/release/bundle
|
|
if [ "$RUNNER_OS" = "Windows" ]; then
|
|
cp "$BUNDLE"/nsis/*.exe out/
|
|
cp "$BUNDLE"/nsis/*.exe out/OpenCoworker-windows-setup.exe
|
|
cp "$BUNDLE"/msi/*.msi out/
|
|
cp "$BUNDLE"/msi/*.msi out/OpenCoworker-windows.msi
|
|
else
|
|
cp "$BUNDLE"/dmg/*.dmg out/
|
|
cp "$BUNDLE"/dmg/*.dmg out/OpenCoworker-${{ matrix.slug }}.dmg
|
|
fi
|
|
ls -la out
|
|
|
|
- uses: actions/upload-artifact@v4
|
|
with:
|
|
name: ${{ matrix.slug }}
|
|
path: out/*
|
|
if-no-files-found: error
|
|
|
|
release:
|
|
if: startsWith(github.ref, 'refs/tags/v')
|
|
needs: build
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- uses: actions/download-artifact@v4
|
|
with:
|
|
path: dist
|
|
merge-multiple: true
|
|
|
|
- uses: softprops/action-gh-release@v2
|
|
with:
|
|
draft: true
|
|
files: dist/*
|
|
generate_release_notes: true
|