Releasing¶
For maintainers. Packages are versioned by hand and published to npm by hand with pnpm, one package at a time. The release workflow in GitHub Actions does not publish; it runs only when started by hand.
Versions¶
- The repository is tagged
vX.Y.Zfor each release. Release notes and the changelog are per repository. - Packages are versioned independently. Bump only the packages that
changed; a release can move
@plexusone/shellto 0.2.3 while the others stay at 0.2.1. Internal ranges areworkspace:^, which pnpm publishes as a caret range on the version in the workspace. - While the major version is 0, a change a consumer must react to is a new minor version; fixes are patch versions.
- A published version cannot be replaced. Fix forward with a new version, and deprecate the broken one.
1. Prepare the release¶
- Set
versionin each changed package'spackage.json. - Add the release to
CHANGELOG.jsonwith each change's commit, then generate the changelog:
schangelog validate CHANGELOG.json
schangelog generate CHANGELOG.json -o CHANGELOG.md
cp CHANGELOG.md docs/changelog.md
- Add
docs/releases/vX.Y.Z.mdand list it inmkdocs.yml. - Check locally what CI checks:
pnpm install --frozen-lockfile
pnpm build # ends by loading every package entry point
pnpm test
pnpm lint
pnpm format:check
pnpm build runs scripts/check-exports.mjs, which imports and requires
every entry point each package exports. It fails when an export names a
file the build does not write, which once shipped a @plexusone/ui that
could not load.
2. Push, then tag¶
- Push
mainand wait for CI to pass. - Tag the commit CI passed on, and push the tag:
3. Publish¶
Publish from main at the tagged commit. pnpm publish refuses a detached
HEAD (ERR_PNPM_GIT_UNKNOWN_BRANCH), so check out main, not the tag:
git checkout main
git pull --ff-only
git rev-parse --short HEAD # must be the tagged commit
pnpm install --frozen-lockfile
pnpm build
Sign in right before publishing: tokens from npm login are short-lived, and
an expired one makes publish fail with E404 on PUT. If npm whoami
fails, run npm login again.
Then publish each changed package with its own command, in
dependency order: ui and auth before tenant, and all three before
shell; auth before pages.
npm login
npm whoami # grokify
pnpm --filter @plexusone/ui publish --access public
pnpm --filter @plexusone/auth publish --access public
pnpm --filter @plexusone/tenant publish --access public
pnpm --filter @plexusone/shell publish --access public
Do not use pnpm -r publish. It decides what to publish by asking the
registry, which can lag behind a version just published or staged; it then
publishes that version again, npm answers E409 Cannot publish over
previously staged version, and the run stops before the remaining
packages.
A new package goes through staging¶
Until it is approved, the version cannot be installed, and the registry may take a few minutes to show it after approval. Check Staged Packages before concluding a publish failed.
The first version of a package that is not yet on npm is staged: npm
publishes a public 0.0.0-stage placeholder and holds the real version
until a maintainer approves it. Approve it in Staged Packages on
npmjs.com, with two-factor authentication, before publishing a package
that depends on it. With npm 11.15 or later, npm stage list and
npm stage approve <id> do the same from the terminal.
When publishing fails¶
| Error | Cause | What to do |
|---|---|---|
ERR_PNPM_GIT_UNKNOWN_BRANCH |
HEAD is detached, as after checking out a tag | Check out main at the tagged commit |
E404 on PUT |
Not signed in, or the token expired (sign-in tokens are short-lived) | npm login, then npm whoami |
E409 Cannot publish over previously staged version |
That version is already published or staged | Skip it; publish the next package |
E402 |
Publishing a scoped package as restricted | Every package sets publishConfig.access: public; pass --access public |
4. Verify¶
The registry can take a minute to show a new version. Then install the published packages into an empty project and load them, which is what a consumer does:
mkdir /tmp/check && cd /tmp/check && npm init -y >/dev/null
npm install react@19 react-dom@19 @plexusone/shell @plexusone/auth @plexusone/tenant @plexusone/ui
node --input-type=module -e "await import('@plexusone/shell'); console.log('import ok')"
node -e "require('@plexusone/shell'); console.log('require ok')"
If a published version is broken, publish a fixed version and deprecate the broken one: