Skip to content

Build and Release

Build and Release #20

Workflow file for this run

name: Build and Release
on:
push:
branches:
- main
permissions:
contents: write
concurrency:
group: release
cancel-in-progress: false
jobs:
# Bump the version once (on Ubuntu) and push it, so every matrix job builds the
# same version. [skip ci] keeps it from re-triggering.
version:
if: "!contains(github.event.head_commit.message, '[skip ci]')"
runs-on: ubuntu-latest
outputs:
version: ${{ steps.bump.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Bump patch version
id: bump
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
npm version patch --no-git-tag-version
VERSION=$(node -p "require('./package.json').version")
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
git add package.json package-lock.json
git commit -m "chore: bump version to $VERSION [skip ci]"
git push
# Build + publish per-OS natively (native modules + platform binaries differ).
build:
needs: version
strategy:
fail-fast: false
matrix:
# windows-2022 = VS 2022 toolchain; windows-latest ships VS 18 (2026)
# which node-gyp 11 can't parse, breaking native-module compiles.
os: [macos-latest, windows-2022]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
ref: main # the just-bumped commit
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
# node-gyp (better-sqlite3-multiple-ciphers) fails on Python 3.13+; pin 3.12.
- uses: actions/setup-python@v5
if: runner.os == 'Windows'
with:
python-version: '3.12'
- name: Install dependencies
run: npm ci
# Windows needs win64 native runner binaries (the repo ships macOS ones).
- name: Fetch Windows binaries
if: runner.os == 'Windows'
shell: pwsh
run: ./scripts/fetch-win-binaries.ps1
# macOS signing identity (no-op if the secret is absent → unsigned build).
- name: Import Apple signing certificate
if: runner.os == 'macOS' && env.CSC_LINK != ''
env:
CSC_LINK: ${{ secrets.CSC_LINK }}
run: echo "Signing cert provided via CSC_LINK"
- name: Build (typecheck + bundle)
run: npm run build
- name: Package & publish (macOS)
if: runner.os == 'macOS'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CSC_LINK: ${{ secrets.CSC_LINK }}
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
APPLE_API_KEY_CONTENT: ${{ secrets.APPLE_API_KEY }}
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: |
# notarytool needs the API key as a file; write it from the secret.
printf '%s' "$APPLE_API_KEY_CONTENT" > "$RUNNER_TEMP/AuthKey.p8"
export APPLE_API_KEY="$RUNNER_TEMP/AuthKey.p8"
npx electron-builder --mac --publish always
- name: Package & publish (Windows)
if: runner.os == 'Windows'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Optional Windows code signing (no-op if absent → unsigned, SmartScreen warns)
CSC_LINK: ${{ secrets.WIN_CSC_LINK }}
CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }}
run: npx electron-builder --win --publish always
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: dist-${{ matrix.os }}
path: |
dist/*.dmg
dist/*.exe
dist/*.zip
if-no-files-found: ignore