chore: automate canary and stable releases

This commit is contained in:
Dotta
2026-03-17 14:08:55 -05:00
parent 7b9718cbaa
commit 21c1235277
18 changed files with 1536 additions and 1260 deletions

10
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1,10 @@
# Replace @dotta if a different maintainer or team should own release infrastructure.
.github/workflows/release-*.yml @dotta
scripts/release*.sh @dotta
scripts/release-*.mjs @dotta
scripts/create-github-release.sh @dotta
scripts/rollback-latest.sh @dotta
doc/RELEASING.md @dotta
doc/PUBLISHING.md @dotta
doc/RELEASE-AUTOMATION-SETUP.md @dotta

94
.github/workflows/release-canary.yml vendored Normal file
View File

@@ -0,0 +1,94 @@
name: Release Canary
on:
push:
branches:
- master
concurrency:
group: release-canary-master
cancel-in-progress: false
jobs:
verify:
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9.15.4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
- name: Typecheck
run: pnpm -r typecheck
- name: Run tests
run: pnpm test:run
- name: Build
run: pnpm build
publish:
needs: verify
runs-on: ubuntu-latest
timeout-minutes: 45
environment: npm-canary
permissions:
contents: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9.15.4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
- name: Configure git author
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Publish canary
env:
GITHUB_ACTIONS: "true"
run: ./scripts/release.sh canary --skip-verify
- name: Push canary tag
run: |
tag="$(git tag --points-at HEAD | grep '^canary/v' | head -1)"
if [ -z "$tag" ]; then
echo "Error: no canary tag points at HEAD after release." >&2
exit 1
fi
git push origin "refs/tags/${tag}"

View File

@@ -1,38 +1,29 @@
name: Release
name: Release Stable
on:
workflow_dispatch:
inputs:
channel:
description: Release channel
source_ref:
description: Commit SHA, branch, or tag to publish as stable
required: true
type: choice
default: canary
options:
- canary
- stable
bump:
description: Semantic version bump
required: true
type: choice
default: patch
options:
- patch
- minor
- major
type: string
default: master
stable_date:
description: Stable release date in UTC (YYYY-MM-DD). Defaults to today.
required: false
type: string
dry_run:
description: Preview the release without publishing
description: Preview the stable release without publishing
required: true
type: boolean
default: true
default: false
concurrency:
group: release-${{ github.ref }}
group: release-stable
cancel-in-progress: false
jobs:
verify:
if: startsWith(github.ref, 'refs/heads/release/')
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
@@ -43,6 +34,7 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ inputs.source_ref }}
- name: Setup pnpm
uses: pnpm/action-setup@v4
@@ -56,7 +48,7 @@ jobs:
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
run: pnpm install --no-frozen-lockfile
- name: Typecheck
run: pnpm -r typecheck
@@ -67,21 +59,20 @@ jobs:
- name: Build
run: pnpm build
publish:
if: startsWith(github.ref, 'refs/heads/release/')
preview:
if: inputs.dry_run
needs: verify
runs-on: ubuntu-latest
timeout-minutes: 45
environment: npm-release
permissions:
contents: write
id-token: write
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ inputs.source_ref }}
- name: Setup pnpm
uses: pnpm/action-setup@v4
@@ -95,32 +86,74 @@ jobs:
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
run: pnpm install --no-frozen-lockfile
- name: Dry-run stable release
env:
GITHUB_ACTIONS: "true"
run: |
args=(stable --skip-verify --dry-run)
if [ -n "${{ inputs.stable_date }}" ]; then
args+=(--date "${{ inputs.stable_date }}")
fi
./scripts/release.sh "${args[@]}"
publish:
if: ${{ !inputs.dry_run }}
needs: verify
runs-on: ubuntu-latest
timeout-minutes: 45
environment: npm-stable
permissions:
contents: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ inputs.source_ref }}
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9.15.4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
- name: Configure git author
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Run release script
- name: Publish stable
env:
GITHUB_ACTIONS: "true"
run: |
args=("${{ inputs.bump }}")
if [ "${{ inputs.channel }}" = "canary" ]; then
args+=("--canary")
fi
if [ "${{ inputs.dry_run }}" = "true" ]; then
args+=("--dry-run")
args=(stable --skip-verify)
if [ -n "${{ inputs.stable_date }}" ]; then
args+=(--date "${{ inputs.stable_date }}")
fi
./scripts/release.sh "${args[@]}"
- name: Push stable release branch commit and tag
if: inputs.channel == 'stable' && !inputs.dry_run
run: git push origin "HEAD:${GITHUB_REF_NAME}" --follow-tags
- name: Push stable tag
run: |
tag="$(git tag --points-at HEAD | grep '^v' | head -1)"
if [ -z "$tag" ]; then
echo "Error: no stable tag points at HEAD after release." >&2
exit 1
fi
git push origin "refs/tags/${tag}"
- name: Create GitHub Release
if: inputs.channel == 'stable' && !inputs.dry_run
env:
GH_TOKEN: ${{ github.token }}
run: |