148 lines
5.8 KiB
YAML
148 lines
5.8 KiB
YAML
name: Desktop release
|
|
|
|
# Builds the menu-bar desktop app installers (Windows .exe + macOS .dmg) and,
|
|
# on a version tag, attaches them to the GitHub Release. Closes #318 — the
|
|
# dist:win build config already existed; this is the missing publish step.
|
|
#
|
|
# Triggers:
|
|
# - workflow_dispatch manual build (artifacts only)
|
|
# - push tags 'v*' build + attach the installers to the release
|
|
# - pull_request (desktop) build-only smoke test so the Windows build can't
|
|
# silently rot (only when desktop/CI files change)
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
push:
|
|
tags:
|
|
- 'v*'
|
|
pull_request:
|
|
paths:
|
|
- 'desktop/**'
|
|
- '.github/workflows/desktop-release.yml'
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
jobs:
|
|
build:
|
|
name: Build (${{ matrix.os }})
|
|
runs-on: ${{ matrix.os }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
# Pinned to windows-2022 (VS 2022): node-gyp can't yet parse the VS "18"
|
|
# toolset on windows-latest, which breaks the better-sqlite3 native build.
|
|
- os: windows-2022
|
|
ebArgs: --win --x64
|
|
artifact: windows-installer
|
|
glob: desktop/dist-electron/*.exe
|
|
- os: macos-latest
|
|
ebArgs: --mac --arm64
|
|
artifact: macos-dmg
|
|
glob: desktop/dist-electron/*.dmg
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '20'
|
|
|
|
- name: Install workspace dependencies
|
|
run: npm install
|
|
|
|
- name: Install desktop dependencies
|
|
run: npm --prefix desktop install
|
|
|
|
- name: Build client + desktop bundles
|
|
shell: bash
|
|
run: |
|
|
npm run build -w client
|
|
npm --prefix desktop run build:all
|
|
# Stage client/dist into desktop/ so electron-builder's extraResources
|
|
# source stays inside desktop/ (no `../`). Belt-and-suspenders with the
|
|
# root-hiding below; also makes local `desktop:dist:win` work on Windows.
|
|
npm --prefix desktop run stage:client
|
|
|
|
- name: Validate macOS signing credentials
|
|
if: matrix.os == 'macos-latest' && startsWith(github.ref, 'refs/tags/')
|
|
shell: bash
|
|
env:
|
|
CSC_LINK: ${{ secrets.MACOS_CSC_LINK }}
|
|
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
|
|
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
|
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
APPLE_KEYCHAIN_PROFILE: ${{ secrets.APPLE_KEYCHAIN_PROFILE }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [ -z "${CSC_LINK:-}" ]; then
|
|
echo "Missing MACOS_CSC_LINK secret for signed macOS release builds."
|
|
exit 1
|
|
fi
|
|
|
|
has_api_key_creds=false
|
|
if [ -n "${APPLE_API_KEY:-}" ] && [ -n "${APPLE_API_KEY_ID:-}" ] && [ -n "${APPLE_API_ISSUER:-}" ]; then
|
|
has_api_key_creds=true
|
|
fi
|
|
|
|
has_apple_id_creds=false
|
|
if [ -n "${APPLE_ID:-}" ] && [ -n "${APPLE_APP_SPECIFIC_PASSWORD:-}" ] && [ -n "${APPLE_TEAM_ID:-}" ]; then
|
|
has_apple_id_creds=true
|
|
fi
|
|
|
|
has_keychain_creds=false
|
|
if [ -n "${APPLE_KEYCHAIN_PROFILE:-}" ]; then
|
|
has_keychain_creds=true
|
|
fi
|
|
|
|
if [ "$has_api_key_creds" != true ] && [ "$has_apple_id_creds" != true ] && [ "$has_keychain_creds" != true ]; then
|
|
echo "Missing Apple notarization secrets. Provide APPLE_API_KEY/APPLE_API_KEY_ID/APPLE_API_ISSUER, APPLE_ID/APPLE_APP_SPECIFIC_PASSWORD/APPLE_TEAM_ID, or APPLE_KEYCHAIN_PROFILE."
|
|
exit 1
|
|
fi
|
|
|
|
- name: Package installer
|
|
shell: bash
|
|
env:
|
|
# Pull-request and manual artifact builds stay unsigned. Tagged macOS
|
|
# release builds must use Developer ID signing + notarization so the
|
|
# downloaded DMG opens without Gatekeeper's "damaged" quarantine block.
|
|
CSC_IDENTITY_AUTODISCOVERY: ${{ matrix.os == 'macos-latest' && startsWith(github.ref, 'refs/tags/') && 'true' || 'false' }}
|
|
CSC_LINK: ${{ secrets.MACOS_CSC_LINK }}
|
|
CSC_KEY_PASSWORD: ${{ secrets.MACOS_CSC_KEY_PASSWORD }}
|
|
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
|
|
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
|
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
APPLE_KEYCHAIN: ${{ secrets.APPLE_KEYCHAIN }}
|
|
APPLE_KEYCHAIN_PROFILE: ${{ secrets.APPLE_KEYCHAIN_PROFILE }}
|
|
run: |
|
|
set -e
|
|
# Run electron-builder with desktop/ as its own project root. Invoked
|
|
# from the monorepo root (e.g. via `npm --prefix desktop run`), it walks
|
|
# up, treats the repo root as the project, and on Windows pulls parent
|
|
# files (.dockerignore, .env.example, …) into the asar — failing with
|
|
# "<file> must be under …/desktop/". Running from desktop/ and hiding the
|
|
# root package.json (whose `workspaces` field triggers the upward scan)
|
|
# makes desktop/ the detected project root.
|
|
mv package.json "$RUNNER_TEMP/root-package.json"
|
|
cd desktop
|
|
npx --no-install electron-builder ${{ matrix.ebArgs }}
|
|
|
|
- name: Upload installer artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: ${{ matrix.artifact }}
|
|
path: ${{ matrix.glob }}
|
|
if-no-files-found: error
|
|
|
|
- name: Attach installer to release
|
|
if: startsWith(github.ref, 'refs/tags/')
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
files: ${{ matrix.glob }}
|