Skip to content

Publish packages

Publish packages #2

Workflow file for this run

name: Publish packages
# Publishes every workspace package to npm at a single shared version, with
# internal dependencies pinned to that same version.
#
# Two ways to release:
#
# 1. Manual (recommended) — run this workflow from the Actions tab and pick a
# bump type. The workflow computes the next version from the current one
# (root package.json), publishes, and — for a STABLE release — commits the
# version bump back to the branch and creates a `v<version>` git tag.
#
# * patch / minor / major -> stable release, dist-tag "latest"
# * prepatch / preminor / premajor / prerelease + a pre-id
# (beta | rc | alpha | canary | next) -> pre-release, e.g. 21.1.0-beta.0,
# published under the matching dist-tag (npm i <pkg>@beta). Pre-releases
# are NOT committed back and do NOT move the "latest" tag.
#
# 2. GitHub Release — publishing a Release with a tag like `v21.1.0`
# (or `v21.1.0-rc.1`) publishes exactly that version. The dist-tag is
# derived from the tag (stable -> latest, pre-release -> its identifier).
#
# Requires repository secret NPM_TOKEN (an npm automation token with publish
# rights). Commit-back uses the built-in GITHUB_TOKEN.
on:
release:
types: [published]
workflow_dispatch:
inputs:
release_type:
description: "Version bump"
type: choice
required: true
default: patch
options:
- patch
- minor
- major
- prerelease
- prepatch
- preminor
- premajor
preid:
description: "Pre-release identifier (only used for pre* bumps)"
type: choice
required: false
default: beta
options:
- beta
- rc
- alpha
- canary
- next
dry_run:
description: "Dry run: build + npm publish --dry-run, no real publish, no git changes"
type: boolean
required: false
default: false
concurrency:
group: publish-${{ github.ref }}
cancel-in-progress: false
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: write # needed to commit the version bump and push the tag
steps:
- uses: actions/checkout@v4
with:
# full history + a writable token so we can push the release commit/tag
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-node@v4
with:
node-version: 22
registry-url: "https://registry.npmjs.org"
cache: npm
- name: Install (single workspace install)
run: npm ci
- name: Resolve version and dist-tag
id: meta
run: |
set -euo pipefail
if [ "${{ github.event_name }}" = "release" ]; then
RESULT=$(node scripts/release-version.mjs tag "${{ github.event.release.tag_name }}")
IS_DISPATCH=false
else
RESULT=$(node scripts/release-version.mjs bump "${{ inputs.release_type }}" "${{ inputs.preid }}")
IS_DISPATCH=true
fi
echo "result: $RESULT"
VERSION=$(echo "$RESULT" | node -e "process.stdin.on('data',d=>console.log(JSON.parse(d).next))")
DIST_TAG=$(echo "$RESULT" | node -e "process.stdin.on('data',d=>console.log(JSON.parse(d).distTag))")
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "dist_tag=$DIST_TAG" >> "$GITHUB_OUTPUT"
echo "is_dispatch=$IS_DISPATCH" >> "$GITHUB_OUTPUT"
[ "$DIST_TAG" = "latest" ] && echo "prerelease=false" >> "$GITHUB_OUTPUT" || echo "prerelease=true" >> "$GITHUB_OUTPUT"
echo "Publishing $VERSION under dist-tag '$DIST_TAG'"
- name: Set shared version and pin internal deps
run: node scripts/set-version.mjs "${{ steps.meta.outputs.version }}"
- name: Build all packages (topological order)
run: npm run build
- name: Publish to npm
run: |
node scripts/publish.mjs \
--access public \
--tag "${{ steps.meta.outputs.dist_tag }}" \
${{ inputs.dry_run == true && '--dry-run' || '' }}
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Commit version bump and tag (stable manual releases only)
if: >-
steps.meta.outputs.is_dispatch == 'true' &&
steps.meta.outputs.prerelease == 'false' &&
inputs.dry_run == false
run: |
set -euo pipefail
VERSION="${{ steps.meta.outputs.version }}"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
# Persist ONLY the root package.json — it is the single source of truth
# for the current released version. Workspace packages intentionally
# stay at the "0.0.0" placeholder in source (with wildcard internal
# deps); set-version.mjs stamps the real version into them only at
# build/publish time, so we deliberately do NOT commit those changes.
git checkout -- '*/package.json'
git add package.json
git commit -m "chore(release): v${VERSION}"
git tag -a "v${VERSION}" -m "Release v${VERSION}"
git push origin "HEAD:${GITHUB_REF_NAME}" --follow-tags
- name: Summary
if: always()
run: |
echo "### Publish result" >> "$GITHUB_STEP_SUMMARY"
echo "- version: \`${{ steps.meta.outputs.version }}\`" >> "$GITHUB_STEP_SUMMARY"
echo "- dist-tag: \`${{ steps.meta.outputs.dist_tag }}\`" >> "$GITHUB_STEP_SUMMARY"
echo "- dry run: \`${{ inputs.dry_run || false }}\`" >> "$GITHUB_STEP_SUMMARY"