openpencil/.github/workflows/build.yml
Danila Poyarkov 1aa10a4fed
build(tools): group tools by role and gate them like the rest of the repo (#791)
Tools live under tools/<role>/<domain> (checks, generate, release, ci, dev), every tool is a workspace named @open-pencil/<domain>-tools, a shared tools/tsconfig.json backs the new check:tools gate that fixed 55 latent type errors, test:tools runs through bun --filter, the placement check is its own checks/test-homes package, and every tool resolves the repository through resolveWorkspaceRoot. Bun, Node, and mdast types live in a tools-root workspace so they never reach the app program.
2026-09-30 05:00:31 +04:00

255 lines
9 KiB
YAML

name: Build
on:
workflow_dispatch:
inputs:
tag:
description: Existing stable release tag to rebuild without moving it (vX.Y.Z).
required: true
type: string
push:
tags:
- 'v*'
permissions:
contents: read
concurrency:
group: release-${{ inputs.tag || github.ref_name }}
cancel-in-progress: false
env:
WORKFLOW_COMMIT: ${{ github.workflow_sha }}
jobs:
plan:
runs-on: ubuntu-latest
timeout-minutes: 10
outputs:
tag: ${{ steps.release.outputs.tag }}
version: ${{ steps.release.outputs.version }}
source: ${{ steps.release.outputs.source }}
matrix: ${{ steps.release.outputs.matrix }}
steps:
- uses: actions/checkout@v7
with:
ref: ${{ github.workflow_sha }}
fetch-depth: 0
persist-credentials: false
- uses: ./.github/actions/setup-bun
- id: release
name: Resolve immutable source and native matrix
env:
RELEASE_TAG: ${{ inputs.tag || github.ref_name }}
run: bun tools/release/release-packages/src/native/resolve.ts
frontend:
needs: plan
runs-on: ubuntu-latest
timeout-minutes: 20
outputs:
sha256: ${{ steps.frontend.outputs.sha256 }}
steps:
- uses: actions/checkout@v7
with:
ref: ${{ needs.plan.outputs.source }}
persist-credentials: false
- uses: actions/checkout@v7
with:
ref: ${{ github.workflow_sha }}
path: .pipeline
persist-credentials: false
- uses: actions/setup-node@v7
with:
node-version: 24.x
- uses: ./.pipeline/.github/actions/setup-bun
with:
cache-scope: desktop
- name: Install pinned workflow tooling
run: bun install --cwd .pipeline --frozen-lockfile
- name: Build shared desktop frontend and package outputs
run: |
bun run generate:icons --target desktop
bun run generate:tauri-menu
bun run build
- name: Prepare and validate npm tarballs
run: |
bun .pipeline/tools/release/release-packages/src/cli.ts prepare
bun .pipeline/tools/release/release-packages/src/cli.ts pack
- name: Extract exact release notes
env:
RELEASE_VERSION: ${{ needs.plan.outputs.version }}
run: bun .pipeline/tools/release/release-packages/src/extract-release-notes.ts "$RELEASE_VERSION" release-notes.md
- name: Archive platform-independent native inputs
id: frontend
run: |
tar -cf frontend.tar dist desktop/icons desktop/generated
echo "sha256=$(sha256sum frontend.tar | cut -d ' ' -f 1)" >> "$GITHUB_OUTPUT"
- uses: actions/upload-artifact@v7
with:
name: release-frontend
path: |
frontend.tar
release-notes.md
if-no-files-found: error
compression-level: 0
- uses: actions/upload-artifact@v7
with:
name: release-npm
path: .npm-packages/*.tgz
include-hidden-files: true
if-no-files-found: error
compression-level: 0
native:
needs: [plan, frontend]
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.plan.outputs.matrix) }}
runs-on: ${{ matrix.platform }}
timeout-minutes: 40
env:
RELEASE_TAG: ${{ needs.plan.outputs.tag }}
SOURCE_COMMIT: ${{ needs.plan.outputs.source }}
FRONTEND_SHA256: ${{ needs.frontend.outputs.sha256 }}
RELEASE_TARGET: ${{ matrix.target }}
steps:
- uses: actions/checkout@v7
with:
ref: ${{ needs.plan.outputs.source }}
persist-credentials: false
- uses: actions/checkout@v7
with:
ref: ${{ github.workflow_sha }}
path: .pipeline
persist-credentials: false
- uses: actions/setup-node@v7
with:
node-version: 24.x
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
with:
workspaces: desktop -> target
key: ${{ matrix.target }}
- name: Install native dependencies on Linux
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
- uses: ./.pipeline/.github/actions/setup-bun
with:
cache-scope: desktop
cache-save: ${{ matrix.saveBunCache && runner.os != 'Linux' }}
- name: Install pinned workflow tooling
run: bun install --cwd .pipeline --frozen-lockfile
- uses: actions/download-artifact@v8
with:
name: release-frontend
- name: Verify shared inputs and disable only the redundant build hook
run: bun .pipeline/tools/release/release-packages/src/native/frontend.ts
- name: Extract shared frontend, icons and menu
run: tar -xf frontend.tar
- name: Verify Node and Tauri startup
timeout-minutes: 1
run: |
node --version
node node_modules/@tauri-apps/cli/tauri.js --version
- name: Build and sign native bundles (no release uploads)
id: tauri
timeout-minutes: 30
uses: tauri-apps/tauri-action@v0
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD || '' }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
with:
tauriScript: node node_modules/@tauri-apps/cli/tauri.js
args: --target ${{ matrix.target }} --config "${{ github.workspace }}/release-build-config.json" --verbose
retryAttempts: 0
- name: Collect only reported bundles and signatures
env:
TAURI_ARTIFACT_PATHS: ${{ steps.tauri.outputs.artifactPaths }}
run: bun .pipeline/tools/release/release-packages/src/native/collect.ts
- uses: actions/upload-artifact@v7
with:
name: native-${{ matrix.target }}
path: native-output/*
if-no-files-found: error
compression-level: 0
publish:
needs: [plan, frontend, native]
runs-on: ubuntu-latest
timeout-minutes: 25
permissions:
contents: write
id-token: write
attestations: write
env:
RELEASE_TAG: ${{ needs.plan.outputs.tag }}
SOURCE_COMMIT: ${{ needs.plan.outputs.source }}
FRONTEND_SHA256: ${{ needs.frontend.outputs.sha256 }}
GH_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@v7
with:
ref: ${{ needs.plan.outputs.source }}
persist-credentials: false
- uses: actions/checkout@v7
with:
ref: ${{ github.workflow_sha }}
path: .pipeline
persist-credentials: false
- uses: actions/setup-node@v7
with:
node-version: 24.x
registry-url: https://registry.npmjs.org/
- uses: ./.pipeline/.github/actions/setup-bun
with:
cache-scope: desktop
cache-save: 'false'
- name: Install pinned workflow tooling
run: bun install --cwd .pipeline --frozen-lockfile
- uses: actions/download-artifact@v8
with:
name: release-frontend
- uses: actions/download-artifact@v8
with:
name: release-npm
path: .npm-packages
- uses: actions/download-artifact@v8
with:
pattern: native-*
path: native-artifacts
- name: Install signature verifier
run: sudo apt-get update && sudo apt-get install -y minisign
- name: Verify all targets, digests and updater signatures
run: bun .pipeline/tools/release/release-packages/src/native/assemble.ts
- name: Refuse published releases or moved tags
run: bun .pipeline/tools/release/release-packages/src/native/publish.ts check
- name: Attest the complete binary set and source/workflow manifest
id: provenance
uses: actions/attest@v4
with:
subject-path: release-output/*
- name: Verify attestations against the pinned workflow
env:
ATTESTATION_BUNDLE: ${{ steps.provenance.outputs.bundle-path }}
run: |
for artifact in release-output/*; do
gh attestation verify "$artifact" --bundle "$ATTESTATION_BUNDLE" \
--repo "$GITHUB_REPOSITORY" \
--signer-workflow "$GITHUB_REPOSITORY/.github/workflows/build.yml" \
--signer-digest "$WORKFLOW_COMMIT" --deny-self-hosted-runners
done
- name: Publish verified npm artifacts with provenance
run: bun .pipeline/tools/release/release-packages/src/cli.ts publish
- name: Replace and verify the entire draft asset set
run: bun .pipeline/tools/release/release-packages/src/native/publish.ts upload