Skip to content

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

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

Release with changesets and the shared toolchain, not np#4
stefanoverna merged 3 commits into
mainfrom
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.
There is no CHANGELOG.md here at all, across 24 published versions.

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. Verified against this branch:

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

What changed

  • .changeset/ added: config.json (baseBranch: main, access: public
    which is what makes the scoped package publish publicly without a
    publishConfig) 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 was already in files — it just never existed. Now something
    writes it.
  • 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

prepublishOnly here runs npm run build && npm run test, and npm fires it
inside npm publish — so the build and the tests run a second time during a
release, after the toolchain has already gated on them. Harmless, and left alone.

https://claude.ai/code/session_01XaYAhzmiJwysZeq1XC5xrQ

RELEASE.md for this family of repos prescribed a bare `np patch` -
literally always patch, decided on release day, with no changelog coming out
of it at all. Changesets moves that decision 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. In a repo
that is one package it tags vX.Y.Z, which is what np tagged too, so the tag
history is continuous.

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/@datocms/content-link@b146e66

commit: b146e66

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 02486b9 into main Aug 31, 2026
2 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