Skip to content

Release with changesets and the shared toolchain, not np - #122

Merged
stefanoverna merged 3 commits into
masterfrom
release-toolchain
Aug 31, 2026
Merged

Release with changesets and the shared toolchain, not np#122
stefanoverna merged 3 commits into
masterfrom
release-toolchain

Conversation

@stefanoverna

@stefanoverna stefanoverna commented Aug 31, 2026

Copy link
Copy Markdown
Member

This repo released with np, via a two-line SDKs/RELEASE.md that
prescribed a bare np patch — literally always patch, decided on release day.
The changelog shows what that costs: its last entry is 7.2.0, and the package
is at 8.1.1.

Changesets moves the bump level into the PR that makes the change, and writes
the changelog from it. The release script is
@datocms/release-toolchain
the same one the four DatoCMS monorepos now run, installed from its repository
by git tag and never published to npm.

The tags do not change. In a repo that is one package, changesets tags
vX.Y.Z, which is exactly what np tagged, so git describe and the existing
tag history carry on unbroken. The release branch, which this repo spells
master, is read from .changeset/config.jsonbaseBranch rather than
hard-coded — verified against this branch:

==> Preflight (release-toolchain v1.2.0)
Aborted: you are not on master. Use --tag to publish a prerelease from a branch.

This is the last of the eleven repos to move, and deliberately so: it is the
highest-traffic one, and by the time it lands the toolchain will have cut real
prereleases in six others.

What changed

  • .changeset/ added: config.json (baseBranch: master, access: public) and
    the standard README.md explaining the bump levels.
  • @changesets/cli and @datocms/release-toolchain added; np removed — it
    was pinned at five different versions across these seven repos, with zero
    configuration anywhere, so nothing is lost.
  • changeset, release and release:next scripts. The release script must not
    be called publish: this repo's root is the published package, so
    changeset publishnpm publish would run a publish script and the
    release would re-enter itself.
  • CHANGELOG.md added to files, so the changelog ships with the package.
  • CHANGELOG.md loses its keep-a-changelog preamble. Changesets inserts new
    entries after line 1, so the boilerplate would have ended up below the newest
    entry and sunk further with every release. Line 1 is now the package name.
  • A Releasing section in the README.

How to try it

The first release should be a prerelease, which is real in every way except the
dist-tag:

npx changeset pre enter next
npm run release:next        # publishes X.Y.Z-next.0 under `next`, tags, GitHub release
npx changeset pre exit

latest is untouched and the GitHub release is marked as a prerelease.

One thing worth knowing

prepare here runs npm run test && npm run build, and npm fires prepare
again inside npm publish, so the tests run twice during a release (and on every
ordinary npm install). Not a blocker and not changed here — moving them to
prepack is a reasonable follow-up.

https://claude.ai/code/session_01XaYAhzmiJwysZeq1XC5xrQ

@netlify

netlify Bot commented Aug 31, 2026

Copy link
Copy Markdown

Deploy Preview for react-datocms-example canceled.

Name Link
🔨 Latest commit 2cd0b71
🔍 Latest deploy log https://app.netlify.com/projects/react-datocms-example/deploys/6a9558ece6d4950008bd3f6d

RELEASE.md for this family of repos prescribed a bare `np patch` -
literally always patch, decided on release day. The changelog here shows what
that costs: the last entry is 7.2.0, and the package is at 8.1.1.

Changesets moves the bump level into the PR that makes the change, and writes
the changelog from it. The release script is @datocms/release-toolchain, the
same one the four monorepos run, installed by git tag and never published to
npm. It reads the release branch from .changeset/config.json, so 'master'
here needs no special case, and in a repo that is one package it tags vX.Y.Z,
which is what np tagged too.

CHANGELOG.md loses its keep-a-changelog preamble first: changesets inserts
new entries after line 1, so the boilerplate would have ended up below the
newest entry and sunk further with every release.

Claude-Session: https://claude.ai/code/session_01XaYAhzmiJwysZeq1XC5xrQ
@pkg-pr-new

pkg-pr-new Bot commented Aug 31, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/react-datocms@2cd0b71

commit: 2cd0b71

Stefano Verna added 2 commits August 31, 2026 12:26
Rehearsing the resume against a real registry and a real GitHub repo turned
up a bug that every copy of the old script had: killed between
'changeset publish' and 'git push', the next run reads an empty plan - the
packages are on the registry and their tags are local, which is all
changesets looks at - and aborts with 'there is nothing to release', leaving
the commit unpushed and no GitHub release. v1.1.0 finishes that release.

Claude-Session: https://claude.ai/code/session_01XaYAhzmiJwysZeq1XC5xrQ
This repo's root is the published package, so 'npm publish' typed at the
repo root reaches the registry: it skips the tests, the changelog, the tag
and the GitHub release, and npm takes it whenever the working tree carries a
version the registry has not seen. Today a clean checkout carries the version
already published, so the registry answers 403 - a side effect, not a
decision, and it stops holding the moment somebody bumps by hand.

prepublishOnly now runs 'release-toolchain --assert-release', which passes
only while the release script is the one publishing. 'npm pack' runs prepack
instead, so reading a tarball still works and the pkg-pr-new previews, which
pack rather than publish, are untouched.

Also moves the toolchain pin to v1.2.0. The lockfile is the substantive half
of that: changing the spec alone left the previous SHA resolved, so 'npm ci'
kept installing v1.0.0 while package.json claimed otherwise.

Claude-Session: https://claude.ai/code/session_01XaYAhzmiJwysZeq1XC5xrQ
@stefanoverna

Copy link
Copy Markdown
Member Author

One more commit: npm publish typed by hand is now refused

Renaming the script to release means npm run publish fails with npm's
Missing script error. Safe, though npm's suggestion is npm unpublish and it
does not mention release.

npm publish without run is the one that reaches the registry. It skips the
tests, the changelog, the tag and the GitHub release, and npm takes it whenever
the working tree carries a version the registry has not seen. Today a clean
checkout carries the version already published, so the registry answers 403.
That is a side effect of how the toolchain bumps versions, not a decision, and
it stops holding the moment somebody bumps by hand.

So prepublishOnly now runs release-toolchain --assert-release, which passes
only while the release script is the one publishing:

$ npm publish --dry-run
> prepublishOnly
> release-toolchain --assert-release

Aborted: this package is published by 'npm run release'.
  A bare `npm publish` skips the tests, the changelog, the tag and the
  GitHub release, so it is refused here.
  To inspect the tarball without publishing, run 'npm pack'.

npm pack runs prepack rather than prepublishOnly, so reading a tarball
still works, and the pkg-pr-new previews are untouched: it shells out to
npm pack --json, not to npm publish.

The four workspace repos do not get this. Their root package.json is private,
so the same slip at the repo root publishes nothing.

@stefanoverna
stefanoverna merged commit 18d64e0 into master Aug 31, 2026
12 checks passed
@stefanoverna
stefanoverna deleted the release-toolchain branch August 31, 2026 10:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant