Skip to content

Cut a release

Cut a release #39

Workflow file for this run

# Cutting a release, from the Actions tab: give it a version and it bumps
# every place the version is written, commits that to main, and tags it —
# which starts the Release workflow. docs/contributing/release.md § How a release happens
# is the narrative, including the one-time deploy-key setup this depends on.
name: Cut a release
on:
workflow_dispatch:
inputs:
version:
description: 'The version to release — major.minor.patch, no leading v'
required: true
permissions:
contents: read
jobs:
cut:
name: Bump, commit, tag
runs-on: ubuntu-24.04
steps:
# The pushes go over SSH with a deploy key rather than GITHUB_TOKEN,
# for two reasons: rulesets can grant bypass to deploy keys but never
# to the built-in Actions app, and a deploy-key push triggers the
# Release workflow where a GITHUB_TOKEN push would be swallowed by
# GitHub's recursion guard.
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
ref: main
ssh-key: ${{ secrets.RELEASE_DEPLOY_KEY }}
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 26
cache: pnpm
- run: pnpm install --frozen-lockfile
# A re-run converges rather than refuses: a tree already at the version
# skips the bump, a commit already on main skips the push, an existing
# tag is reused — so a run that failed halfway is fixed by pressing Run
# again, not by cleaning up.
- name: Bump every version together
env:
VERSION: ${{ inputs.version }}
run: |
if [ "$(node -p "require('./package.json').version")" = "$VERSION" ]; then
echo "the tree is already at $VERSION"
else
node scripts/release-bump.mjs "$VERSION"
pnpm install --lockfile-only
fi
node scripts/release-check.mjs --tag "v$VERSION"
- name: Commit and tag
env:
VERSION: ${{ inputs.version }}
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git diff --quiet || git commit -am "chore(release): v$VERSION"
git rev-parse -q --verify "refs/tags/v$VERSION" >/dev/null || git tag "v$VERSION"
git push origin HEAD:main
git push origin "v$VERSION"