Constraint: Local Apple Silicon Docker/Wine builds are not stable for Windows packaging Rejected: Keep auto-bumping build versions at packaging time | website and artifact versions drifted Confidence: medium Scope-risk: moderate Directive: Keep package.json, generated download links, and packaged artifact versions identical for every public release Tested: typecheck, lint, workspace typecheck, unit tests, integration tests, e2e smoke locally Not-tested: GitHub-hosted Windows/Linux runner outputs before workflow execution
235 lines
7.8 KiB
YAML
235 lines
7.8 KiB
YAML
name: Build & Release
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- 'v*'
|
|
workflow_dispatch:
|
|
inputs:
|
|
publish:
|
|
description: 'Publish to GitHub Releases'
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
|
|
concurrency:
|
|
group: build-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
PNPM_VERSION: '10.24.0'
|
|
NODE_VERSION: '22'
|
|
|
|
jobs:
|
|
# ─────────────────────────────────────────────
|
|
# Stage 1: Lint & Typecheck (fast feedback)
|
|
# ─────────────────────────────────────────────
|
|
check:
|
|
name: Lint & Typecheck
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: pnpm/action-setup@v4
|
|
with:
|
|
version: ${{ env.PNPM_VERSION }}
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
cache: pnpm
|
|
- run: pnpm install --frozen-lockfile
|
|
- run: pnpm typecheck
|
|
- run: pnpm lint
|
|
- run: pnpm typecheck:all
|
|
|
|
# ─────────────────────────────────────────────
|
|
# Stage 2: Unit Tests
|
|
# ─────────────────────────────────────────────
|
|
test:
|
|
name: Unit Tests
|
|
runs-on: ubuntu-latest
|
|
needs: check
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: pnpm/action-setup@v4
|
|
with:
|
|
version: ${{ env.PNPM_VERSION }}
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
cache: pnpm
|
|
- run: pnpm install --frozen-lockfile
|
|
- run: pnpm test:unit
|
|
- run: pnpm test:integration
|
|
|
|
# ─────────────────────────────────────────────
|
|
# Stage 3: Build matrix (parallel per platform)
|
|
# ─────────────────────────────────────────────
|
|
|
|
build-macos:
|
|
name: macOS (${{ matrix.arch }})
|
|
runs-on: ${{ matrix.runner }}
|
|
needs: test
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- arch: arm64
|
|
runner: macos-14
|
|
builder_args: --mac --arm64
|
|
- arch: x64
|
|
runner: macos-15
|
|
builder_args: --mac --x64
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: pnpm/action-setup@v4
|
|
with:
|
|
version: ${{ env.PNPM_VERSION }}
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
cache: pnpm
|
|
- run: pnpm install --frozen-lockfile
|
|
- name: Decode signing certificate
|
|
if: env.CERT_B64 != ''
|
|
env:
|
|
CERT_B64: ${{ secrets.MAC_CERTIFICATE_P12_BASE64 }}
|
|
run: echo "$CERT_B64" | base64 --decode > /tmp/cert.p12
|
|
- name: Build electron-vite
|
|
run: pnpm exec electron-vite build
|
|
- name: Package & sign
|
|
run: pnpm exec electron-builder ${{ matrix.builder_args }} --config electron-builder.yml --publish never
|
|
env:
|
|
CSC_LINK: ${{ secrets.MAC_CERTIFICATE_P12_BASE64 != '' && '/tmp/cert.p12' || '' }}
|
|
CSC_KEY_PASSWORD: ${{ secrets.MAC_CERTIFICATE_PASSWORD }}
|
|
CSC_IDENTITY_AUTO_DISCOVERY: ${{ secrets.MAC_CERTIFICATE_P12_BASE64 != '' && 'true' || 'false' }}
|
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
- uses: actions/upload-artifact@v4
|
|
with:
|
|
name: macos-${{ matrix.arch }}
|
|
path: |
|
|
build/release/*.dmg
|
|
build/release/*.zip
|
|
build/release/*.blockmap
|
|
build/release/latest-mac.yml
|
|
if-no-files-found: error
|
|
|
|
build-windows:
|
|
name: Windows (${{ matrix.arch }})
|
|
runs-on: windows-latest
|
|
needs: test
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- arch: x64-ia32
|
|
builder_args: --win --x64 --ia32
|
|
- arch: arm64
|
|
builder_args: --win --arm64
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: pnpm/action-setup@v4
|
|
with:
|
|
version: ${{ env.PNPM_VERSION }}
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
cache: pnpm
|
|
- run: pnpm install --frozen-lockfile
|
|
- name: Build electron-vite
|
|
run: pnpm exec electron-vite build
|
|
- name: Package
|
|
run: pnpm exec electron-builder ${{ matrix.builder_args }} --config electron-builder.yml --publish never
|
|
env:
|
|
CSC_LINK: ${{ secrets.WIN_CERTIFICATE_P12_BASE64 }}
|
|
CSC_KEY_PASSWORD: ${{ secrets.WIN_CERTIFICATE_PASSWORD }}
|
|
- uses: actions/upload-artifact@v4
|
|
with:
|
|
name: windows-${{ matrix.arch }}
|
|
path: |
|
|
build/release/*.exe
|
|
build/release/*.blockmap
|
|
build/release/latest.yml
|
|
if-no-files-found: error
|
|
|
|
build-linux:
|
|
name: Linux (${{ matrix.arch }})
|
|
runs-on: ubuntu-latest
|
|
needs: test
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- arch: x64
|
|
builder_args: --linux --x64
|
|
- arch: arm64
|
|
builder_args: --linux --arm64
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: pnpm/action-setup@v4
|
|
with:
|
|
version: ${{ env.PNPM_VERSION }}
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
cache: pnpm
|
|
- run: pnpm install --frozen-lockfile
|
|
- name: Install snapcraft (x64 only)
|
|
if: matrix.arch == 'x64'
|
|
run: sudo snap install snapcraft --classic
|
|
- name: Build electron-vite
|
|
run: pnpm exec electron-vite build
|
|
- name: Package
|
|
run: pnpm exec electron-builder ${{ matrix.builder_args }} --config electron-builder.yml --publish never
|
|
- uses: actions/upload-artifact@v4
|
|
with:
|
|
name: linux-${{ matrix.arch }}
|
|
path: |
|
|
build/release/*.AppImage
|
|
build/release/*.deb
|
|
build/release/*.rpm
|
|
build/release/*.snap
|
|
build/release/*.blockmap
|
|
build/release/latest-linux.yml
|
|
if-no-files-found: warn
|
|
|
|
# ─────────────────────────────────────────────
|
|
# Stage 4: Publish to GitHub Releases
|
|
# ─────────────────────────────────────────────
|
|
release:
|
|
name: Publish Release
|
|
runs-on: ubuntu-latest
|
|
needs: [build-macos, build-windows, build-linux]
|
|
if: startsWith(github.ref, 'refs/tags/v') || github.event.inputs.publish == 'true'
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Download all artifacts
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
path: artifacts
|
|
merge-multiple: false
|
|
|
|
- name: Collect release files
|
|
run: |
|
|
mkdir -p release-files
|
|
find artifacts -type f \( \
|
|
-name "*.dmg" -o -name "*.zip" -o -name "*.exe" \
|
|
-o -name "*.AppImage" -o -name "*.deb" -o -name "*.rpm" \
|
|
-o -name "*.snap" -o -name "*.blockmap" \
|
|
-o -name "latest*.yml" \
|
|
\) -exec cp {} release-files/ \;
|
|
ls -lh release-files/
|
|
|
|
- name: Create GitHub Release
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
draft: true
|
|
generate_release_notes: true
|
|
files: release-files/*
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|