Automating Releases of @apollo/client
This post is about the steps I took to automate @apollo/client
's release process with a tool called Changesets. Hopefully it will save someone else implementing a similar workflow a few minutes in the future :)
Changesets
After comparing several options, Changesets stood out as the library that would allow our team to adapt our existing manual workflow seamlessly.
Some of its features include:
- changelog entries written in Markdown at the time code is committed so both changelog and release notes can contain formatted code blocks, links, and other rich contextual information related to the change
- an API for handling prereleases in long-running integration branches
- a simple mechanism for batching changes into releases (changesets
.md
files themselves) - many other nice to haves, including snapshot releases
IMO, the prerelease workflow is more interesting to discuss since its API may undergo significant changes in v3 and it took a bit of experimentation before landing on the current approach, so let's take a look at the more straightforward release workflow first.
Releases
The basic premise of Changesets is that each change to your library (or libraries—it was designed with monorepos in mind) is represented by a markdown file generated via npx changeset
.
The CLI prompts you with two questions: whether your change represents a new patch/minor/major version, and for a description of the change. Once this info is entered, the CLI uses it to generate a new file inside of .changeset
.
Here's an example of a recent Apollo Client changeset, .changeset/gorgeous-buses-laugh.md
:
In a monorepo, more than one package can be specified in the frontmatter block at the top. Once the PR containing the relevant change + changeset is merged to main
the release workflow kicks off.
Here's an abridged + commented version of Apollo Client's release workflow:
The first time this is run after merging a PR, changesets detects the new changeset file and opens a "Versions Packages" PR.
Every time the release workflow runs on push events to the main
branch, any unreleased changeset files are incorportated into the "Version Packages" PR and Changesets is smart enough to increment the package(s) version number(s) to the correct version.
By that I mean: if you have two unreleased changesets, one a minor
change and one a patch
, that results in a new minor version 🎉 The automated "Version Packages" PR will update CHANGELOG.md
listing minor/patch changes in separate sections, increment the version in package.json
and lockfile, as well as removing the changeset markdown files for changes in the new release.
Merging this "Version Packages" PR is what will trigger the changesets/action
to generate a new release 🥳
Prereleases
Prereleases work fairly similarly, but took some experimentation since entering "prerelease mode" generates a pre.json
file that Changesets uses to track alpha releases.
Here's an example pre.json
from Apollo Client's current release-3.8
branch:
In other simpler prerelease workflows I've seen in the wild, pre.json
is repeatedly added and removed from the default branch, but that seemed like a nonstarter for Apollo Client with its many forks. I wanted to avoid ever committing pre.json
to main
.
Instead, Apollo Client:
- enters pre mode on all
release-x
branches by default - each new commit with a changeset opens a "Version Packages (alpha)" PR that functions the same as regular releases,
- but the version is monotonically increased, ie
3.8.0-alpha.0
,3.8.0-alpha.1
, and so on - and only npm releases are generated (not GitHub releases)
Apollo Client's prerelease.yml
looks like this:
Exiting pre mode has its own workflow that does two things: removes pre.json
and reverts the package number in package.json
to the last released version in main
, and a separate workflow check-prerelease.yml
makes sure pre.json
will never be accidentally merged to main.
Conclusion
Working with Changesets has been a breath of fresh air! It's taken a lot of tedious and repetitive tasks out of the release process, and allowed us to focus on the fixes and features on our roadmap. Many thanks to the team that builds and maintains it 🙌