Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .den/commit-style.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Commit message style for the Generate Commit Message button. {{diff}} marks where the changes go. -->
Write ONE commit message for the diff below.

Format: <summary>
- summary: ≤ 72 chars, imperative, capitalized, no period
- After a blank line, add a short body saying what changed and why
- Describe what the change does, not how the code looks
- Don't invent context not in the diff
- Write in the same language as this repository's recent commit messages
- Output only the message, nothing else

DIFF:
{{diff}}
51 changes: 51 additions & 0 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Everything a runner needs before `pnpm app` or `pnpm release` can start, per
# OS — shared by the CI and release workflows so the two cannot drift. The
# scripts find the rest themselves: Visual Studio's bundled CMake on Windows,
# Xcode's toolchain on macOS, and on Linux they name any missing apt package.
name: Set up the Plectrify toolchain
description: Node, pnpm, the root tooling and the per-OS build dependencies.

inputs:
native:
description: Install the native build dependencies (false for jobs that build nothing)
default: 'true'

runs:
using: composite
steps:
- uses: pnpm/action-setup@v4
with:
version: 12.15.0

- uses: actions/setup-node@v4
with:
node-version: 24

- name: Linux build dependencies
if: runner.os == 'Linux' && inputs.native == 'true'
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
cmake ninja-build pkg-config build-essential unzip \
libwebkit2gtk-4.1-dev libgtk-3-dev libasound2-dev libjack-jackd2-dev \
libcurl4-openssl-dev libfreetype-dev libfontconfig-dev \
libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxext-dev \
libxcomposite-dev libgl-dev

- name: macOS build dependencies
if: runner.os == 'macOS' && inputs.native == 'true'
shell: bash
run: brew install ninja || true

# Git identity for the tag the Windows release step creates and the site
# commit promotion pushes. Harmless everywhere else.
- name: Git identity
shell: bash
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"

- name: Root tooling
shell: bash
run: pnpm install --frozen-lockfile
47 changes: 47 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Build and test on every platform Plectrify ships for, on every push to main and
# every pull request. Runs the same gate a developer runs locally —
# `pnpm app --dist --no-run`: UI format/check/test/build, the native app, every
# CTest target — so CI and the dev loop cannot disagree about what "green" means.
# Publishes nothing and needs no secrets.
name: CI

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
build:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
timeout-minutes: 90
strategy:
fail-fast: false
matrix:
include:
- name: Windows
os: windows-2022
- name: macOS
os: macos-15
- name: Linux
os: ubuntu-24.04
steps:
# Windows runners check out with core.autocrlf=true, and Prettier (like
# every other tool here) expects the LF the repository stores.
- name: Keep LF line endings
run: git config --global core.autocrlf false

- uses: actions/checkout@v4

- uses: ./.github/actions/setup

- name: Build and test
run: pnpm app --dist --no-run
63 changes: 63 additions & 0 deletions .github/workflows/promote.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Step 3 of a release (RELEASING.md): flip the verified pre-release to latest and
# point plectrify.com at it. Started by hand, and only after someone has
# installed every platform's build from the pre-release and played through it —
# this is the sign-off, and it is irreversible: a promoted version is immutable.
#
# The script refuses a release still missing its macOS or Linux artifact. It
# then rewrites site/src/lib/site.ts, commits and pushes that to the branch this
# runs on (run it from main), and deploys the site. The deploy needs the
# CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID repository secrets; without
# them, or with "Deploy the site" unticked, the release is promoted and the site
# left alone (`pnpm --dir site run deploy` from anywhere with credentials).
name: Promote

on:
workflow_dispatch:
inputs:
version:
description: Version to promote — must equal the VERSION file (e.g. 0.2.0)
required: true
site:
description: Deploy the site
type: boolean
default: true

concurrency:
group: release
cancel-in-progress: false

permissions:
contents: write

jobs:
promote:
name: Promote to latest
# release.windows.ts owns promotion; it needs nothing Windows-specific to do
# it, but runs only there.
runs-on: windows-2022
timeout-minutes: 30
env:
GH_TOKEN: ${{ github.token }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
steps:
# Windows runners check out with core.autocrlf=true, and Prettier (like
# every other tool here) expects the LF the repository stores.
- name: Keep LF line endings
run: git config --global core.autocrlf false

- uses: actions/checkout@v4

- uses: ./.github/actions/setup
with:
native: false

- name: Promote
shell: bash
run: |
flags=(--promote --version "${{ inputs.version }}")
if [ "${{ inputs.site }}" != "true" ] || [ -z "$CLOUDFLARE_API_TOKEN" ]; then
echo "::warning::Not deploying the site (unticked, or no CLOUDFLARE_API_TOKEN secret)."
flags+=(--no-site)
fi
pnpm release "${flags[@]}"
126 changes: 126 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Steps 1 and 2 of a release (RELEASING.md), on GitHub's runners instead of
# three machines. Started by hand with the version from VERSION, which the
# scripts check against the file — this can confirm the version, never set it.
#
# windows pnpm release builds the installer, tags vX.Y.Z, creates the
# GitHub pre-release with the source archive
# macos pnpm release builds the pkg at that tag and uploads it
# linux pnpm release builds the .deb at that tag and uploads it
#
# The Mac and Linux jobs check out the tag the Windows job pushed, and their
# scripts refuse to upload unless it names the commit they built — the same gate
# that held when this was three machines. Promotion stays a separate, manual
# workflow (promote.yml): it is the sign-off that someone installed the build
# and played through it. This is the only way a release is built: `pnpm
# release` refuses to run outside GitHub Actions.
#
# Needs no secrets beyond the built-in GITHUB_TOKEN: everything published here
# goes to this repository's GitHub release. Release notes are the commit bullets
# (the claude CLI that drafts them locally is not on the runners); edit them on
# GitHub before promoting. Each job also keeps its artifacts on the run for a
# while, for installing before promotion.
name: Release

on:
workflow_dispatch:
inputs:
version:
description: Version to release — must equal the VERSION file (e.g. 0.2.0)
required: true

concurrency:
group: release
cancel-in-progress: false

permissions:
contents: write

env:
GH_TOKEN: ${{ github.token }}

jobs:
windows:
name: Windows — installer + pre-release
runs-on: windows-2022
timeout-minutes: 120
steps:
# Windows runners check out with core.autocrlf=true, and Prettier (like
# every other tool here) expects the LF the repository stores.
- name: Keep LF line endings
run: git config --global core.autocrlf false

- uses: actions/checkout@v4
with:
fetch-depth: 0 # the notes are built from the commits since the last tag

- uses: ./.github/actions/setup

- name: Release
run: pnpm release --version ${{ inputs.version }}

- uses: actions/upload-artifact@v4
if: always()
with:
name: windows
path: artifacts/
if-no-files-found: ignore

macos:
name: macOS — pkg
needs: windows
runs-on: macos-15
timeout-minutes: 120
steps:
# Windows runners check out with core.autocrlf=true, and Prettier (like
# every other tool here) expects the LF the repository stores.
- name: Keep LF line endings
run: git config --global core.autocrlf false

- uses: actions/checkout@v4
with:
ref: v${{ inputs.version }}

- uses: ./.github/actions/setup

- name: Release
run: pnpm release --version ${{ inputs.version }}

- uses: actions/upload-artifact@v4
if: always()
with:
name: macos
path: |
artifacts/*.pkg
artifacts/*.sha256
artifacts/*.json
if-no-files-found: ignore

linux:
name: Linux — .deb
needs: windows
runs-on: ubuntu-24.04
timeout-minutes: 120
steps:
# Windows runners check out with core.autocrlf=true, and Prettier (like
# every other tool here) expects the LF the repository stores.
- name: Keep LF line endings
run: git config --global core.autocrlf false

- uses: actions/checkout@v4
with:
ref: v${{ inputs.version }}

- uses: ./.github/actions/setup

- name: Release
run: pnpm release --version ${{ inputs.version }}

- uses: actions/upload-artifact@v4
if: always()
with:
name: linux
path: |
artifacts/*.deb
artifacts/*.sha256
artifacts/*.json
if-no-files-found: ignore
Loading
Loading