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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
pull_request:
branches: [main]
push:
branches: [main]
branches: [main, 'release/**']

jobs:
check:
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: 📚 Deploy Docs to GitHub Pages
name: 📚 Deploy Docs (manual)

# Redeploys the docs site from main without a release, for docs-only fixes. Run it from the
# Actions tab. A release deploys the docs itself, as the last job of the publish workflow.

on:
push:
tags:
- 'v*'
workflow_dispatch:

permissions:
Expand Down
53 changes: 52 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
name: 📦 Publish to npm
name: 📦 Publish — npm, GitHub Release, docs

# Runs on a vX.Y.Z tag (pushed by the release workflow). Three jobs, each needing the one before:
# the full gate, then npm publish + the GitHub Release, then the docs deploy. A failed publish
# stops the docs from deploying, so the site never describes a version that is not on npm.

on:
push:
Expand Down Expand Up @@ -36,6 +40,12 @@ jobs:
- name: Build docs
run: npm run build:docs

- name: Tag matches package.json
run: |
TAG="${GITHUB_REF_NAME#v}"
PKG=$(node -p "require('./package.json').version")
if [ "$TAG" != "$PKG" ]; then echo "ERROR: tag v$TAG but package.json is $PKG" && exit 1; fi

publish:
needs: ci
runs-on: ubuntu-latest
Expand Down Expand Up @@ -68,3 +78,44 @@ jobs:
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true

deploy-docs:
needs: publish
runs-on: ubuntu-latest
permissions:
contents: read
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
concurrency:
group: 'pages'
cancel-in-progress: true
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm

- name: Install dependencies
run: npm ci

- name: Build docs
run: npm run build:docs

- name: Setup Pages
uses: actions/configure-pages@v5

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: './docs-dist'

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
72 changes: 42 additions & 30 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
name: 🚀 Release — Tag & Update Version
name: 🚀 Release — Version & Tag

# Runs when a release/* branch is merged into main.
# Reads the version from package.json, updates index.html,
# commits the change, tags main, and pushes — triggering
# the publish and deploy-docs workflows.
# Merging a release/X.Y.Z branch into main releases X.Y.Z: the version comes from the branch
# name, so nothing is bumped by hand. The workflow sets package.json to that version, dates the
# CHANGELOG heading, commits to main and pushes the tag vX.Y.Z, which runs the publish workflow
# (gate, npm, GitHub Release, docs). It can also be run from the Actions tab with a version typed in.

on:
pull_request:
types: [closed]
branches: [main]
workflow_dispatch:
inputs:
version:
description: 'Version to release, e.g. 3.0.1'
required: true

jobs:
tag:
if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/')
release:
if: >-
github.event_name == 'workflow_dispatch' ||
(github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/'))
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
- name: Checkout main
uses: actions/checkout@v4
with:
ref: main
Expand All @@ -29,40 +36,45 @@ jobs:
with:
node-version: 22

- name: Read version from package.json
- name: Version from the branch name (or the input)
id: version
env:
HEAD_REF: ${{ github.event.pull_request.head.ref }}
INPUT_VERSION: ${{ github.event.inputs.version }}
run: |
VERSION=$(node -p "require('./package.json').version")
echo "Version: $VERSION"
if [ -z "$VERSION" ]; then echo "ERROR: version is empty" && exit 1; fi
if [ -n "$INPUT_VERSION" ]; then VERSION="$INPUT_VERSION"; else VERSION="${HEAD_REF#release/}"; fi
VERSION="${VERSION#v}"
if ! echo "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then
echo "ERROR: '$VERSION' is not a version. Name the branch release/X.Y.Z." && exit 1
fi
if git ls-remote --exit-code --tags origin "v$VERSION" >/dev/null 2>&1; then
echo "ERROR: tag v$VERSION already exists" && exit 1
fi
echo "Releasing $VERSION"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"

- name: Update version in index.html
- name: Set package.json version and date the changelog
run: |
VERSION="${{ steps.version.outputs.version }}"
sed -i "s/\"softwareVersion\": \"[^\"]*\"/\"softwareVersion\": \"$VERSION\"/" index.html
npm version "$VERSION" --no-git-tag-version --allow-same-version
# the heading "## 3.0.0 (unreleased …)" or "## Unreleased" becomes "## 3.0.0 (2026-10-02)"
TODAY=$(date -u +%F) VERSION="$VERSION" perl -i -pe \
's/^## (?=.*unreleased)(?:v?\Q$ENV{VERSION}\E|\[?Unreleased\]?).*$/## $ENV{VERSION} ($ENV{TODAY})/i' CHANGELOG.md

- name: Check for changes
id: diff
run: |
if git diff --quiet; then
echo "changed=false" >> "$GITHUB_OUTPUT"
else
echo "changed=true" >> "$GITHUB_OUTPUT"
fi

- name: Commit version update
if: steps.diff.outputs.changed == 'true'
- name: Commit to main
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git remote set-url origin https://x-access-token:${{ secrets.GH_PAT }}@github.com/${{ github.repository }}
git add index.html
git commit -m "chore: update version to ${{ steps.version.outputs.version }}"
git push
if git diff --quiet; then
echo "package.json and CHANGELOG.md already at ${{ steps.version.outputs.version }}"
else
git add package.json package-lock.json CHANGELOG.md
git commit -m "release: ${{ steps.version.outputs.version }}"
git push origin main
fi

- name: Create and push tag
- name: Tag
run: |
git remote set-url origin https://x-access-token:${{ secrets.GH_PAT }}@github.com/${{ github.repository }}
git tag "v${{ steps.version.outputs.version }}"
git push origin "v${{ steps.version.outputs.version }}"
Loading