Skip to content

Merge pull request #7 from engineio/docs/agent-reference #14

Merge pull request #7 from engineio/docs/agent-reference

Merge pull request #7 from engineio/docs/agent-reference #14

Workflow file for this run

name: release
# Every push to main releases, if the commits since the last tag warrant one.
# No release PR, no approval step: semantic-release reads the conventional
# commits, works out the next version, tags it, writes the GitHub release notes
# and publishes to npm in a single run.
#
# A push with nothing releasable in it (docs:, chore:, ci:) is a no-op. That is
# the behaviour to expect rather than a failure — see .releaserc.json for which
# commit types earn which bump.
#
# PUBLISHES TO npmjs, PUBLICLY, WITH NO TOKEN. Authentication is npm trusted
# publishing: GitHub Actions mints a short-lived OIDC token, npm verifies it
# against the Trusted Publisher configured on the package, and no long-lived
# secret exists to leak or expire. `id-token: write` below is what makes that
# possible, and @semantic-release/npm@13 detects the OIDC context and skips its
# token check.
#
# Every release goes to BOTH registries: npmjs first (canonical), then mirrored
# to GitHub Packages. npm is what the consumer repos install from, because
# GitHub Packages requires an access token to install even for public packages —
# per GitHub's own docs — which would put a PAT back in every developer's
# ~/.npmrc and every CI job. The mirror exists for the org-internal listing, not
# for consumption.
#
# npm provenance is generated automatically under trusted publishing, so the
# published package carries a verifiable link back to this repo and this
# workflow run. It requires a public repo and a public package; both hold.
#
# ONE-TIME SETUP ON npmjs, which cannot be done from here:
# npmjs.com -> @engineio/ui -> Settings -> Trusted Publisher
# Organization or user: engineio
# Repository: ui
# Workflow filename: release.yml
# Until that exists the publish step fails with an auth error, which is correct
# — it means nothing can publish under this name without going through here.
#
# WHAT THIS DELIBERATELY DOES NOT DO: write anything back to main. The usual
# semantic-release setup adds @semantic-release/changelog and
# @semantic-release/git so the version bump and CHANGELOG land as a commit on
# the release branch. Both are omitted, because main requires pull requests and
# a bot pushing straight to it would need a bypass nobody should hand a CI job.
# So package.json's version stays the placeholder 0.0.0-development — tags are
# the source of truth, and the real version is written in the runner just
# before publishing — and the GitHub release notes are the changelog.
on:
push:
branches: [main]
workflow_dispatch:
concurrency:
group: release
cancel-in-progress: false
permissions:
contents: write # create tags and releases
id-token: write # mint the OIDC token for npm trusted publishing
packages: write # mirror the release to GitHub Packages
issues: write # semantic-release/github verifies these even with
pull-requests: write # comments switched off
jobs:
release:
runs-on: ubuntu-latest
steps:
# fetch-depth: 0 is required, not tidiness — semantic-release works out
# the next version by reading every commit since the last tag, and a
# shallow clone has neither the tags nor the history to do it.
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.14
# Node 22.14+ is the floor for trusted publishing. registry-url points
# npm at npmjs and writes the .npmrc it reads; there is no token to put
# in it.
- uses: actions/setup-node@v6
with:
node-version: "22.14"
registry-url: https://registry.npmjs.org
# Node 22 bundles npm 10.x, and trusted publishing needs npm >= 11.5.1.
# Without this the publish fails asking for credentials, which looks like
# a misconfigured Trusted Publisher rather than an old CLI.
- name: Ensure npm supports trusted publishing
run: |
npm install -g npm@^11
npm --version
- run: bun install --frozen-lockfile
# Gate the release on the same checks CI runs. A broken build must not
# become a published version — once a version exists on the registry it
# cannot be replaced, only superseded.
- name: Verify before releasing
run: |
bun run check
bun run build
- name: Release
run: bunx semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Bootstrap escape hatch, and normally empty.
#
# npm's docs do not say whether a Trusted Publisher can be registered
# for a package name that does not exist yet, and a Trusted Publisher
# is configured in a package's settings — which a package needs to
# exist to have. If pre-registering turns out to be impossible, add an
# npm automation token as the NPM_TOKEN secret, let the first publish
# use it, then configure the Trusted Publisher and DELETE the secret.
#
# Passing it unconditionally is safe either way: an unset secret
# arrives as an empty string, @semantic-release/npm only writes an
# authToken when the value is truthy, and with nothing written it
# falls through to the OIDC path. So this line needs no edit when the
# secret is added or removed.
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
# BOTH names are required, and leaving this one out is why five
# release attempts failed with `401 GET /-/whoami`.
#
# `setup-node` with `registry-url` writes its own user-level .npmrc
# containing `//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}`
# and points NPM_CONFIG_USERCONFIG at it. With NODE_AUTH_TOKEN unset,
# npm expands it to an empty string and every registry call is
# unauthenticated — the same shadowing bug that an empty
# ${NODE_AUTH_TOKEN} in a project .npmrc causes locally, except
# inflicted by the action rather than by a checked-in file.
#
# NPM_TOKEN is what @semantic-release/npm reads; NODE_AUTH_TOKEN is
# what setup-node's .npmrc dereferences. Both point at the same
# secret. Under trusted publishing this whole block becomes
# unnecessary and can go.
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
# npm is the CANONICAL registry — it is what both consumer repos install
# from, and the only one that needs no credential. This mirrors the same
# version to GitHub Packages for the org-internal package listing and for
# anything still pointed there. If the two ever disagree, npm is right.
#
# Runs only when semantic-release actually released: its npm plugin writes
# the real version into package.json in the workspace during prepare, so a
# version other than the placeholder is the signal. A push with nothing
# releasable leaves the placeholder and this no-ops.
#
# --registry overrides publishConfig.registry on the command line, which
# is why package.json stays pinned to npmjs. GITHUB_TOKEN suffices —
# GitHub Packages accepts it for a same-repo publish, so there is no extra
# secret. Note this does NOT make GitHub Packages installable without a
# token: that is a GitHub restriction on reads, not on publishing.
- name: Mirror to GitHub Packages
run: |
set -euo pipefail
version=$(node -p "require('./package.json').version")
if [ "$version" = "0.0.0-development" ]; then
echo "no release this run — nothing to mirror"
exit 0
fi
# A DEDICATED npmrc, because setup-node's one only carries auth for
# registry.npmjs.org. Publishing with --registry=npm.pkg.github.com
# against it fails ENEEDAUTH: npm finds no credential for that host
# and does not fall back. NPM_CONFIG_USERCONFIG also means the
# runner's ~/.npmrc is ignored, so appending there does nothing.
rc=$(mktemp)
printf '//npm.pkg.github.com/:_authToken=%s\n' "$NODE_AUTH_TOKEN" > "$rc"
echo "mirroring @engineio/ui@$version to GitHub Packages"
# A version already present on the mirror is success, not failure —
# it means a previous run got this far. Anything else is a real error.
if NPM_CONFIG_USERCONFIG="$rc" npm publish \
--registry=https://npm.pkg.github.com \
--ignore-scripts --tag latest 2>&1 | tee /tmp/mirror.log; then
echo "mirrored"
elif grep -qE 'EPUBLISHCONFLICT|cannot publish over|already exists' /tmp/mirror.log; then
echo "$version already on GitHub Packages — nothing to do"
else
echo "::error::mirror to GitHub Packages failed"
exit 1
fi
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}