OSS Project Release Notes
Someone recently asked me what I considered to be the gold standard for release notes for an OSS project. Turns out I'm unreasonably picky, so rather than a simple answer you all get to enjoy (one hopes) a full blog post on the subject.
Opinions are my own, this is aspirational rather than some sort of natural law, I don't always follow all of these and yes I feel bad about that, etc. Onto the interesting part!
For release notes:
- concise feature / fix / other sections with breaking changes / security implications called out, with security issues described alongside their priorities / links to CVEs / etc
- new usage patterns and "how to update" explained precisely
- changes are linked back to the relevant code / change request / etc
- all release details should exist in repo, though they may be duplicated elsewhere for ease-of-use
For the changelog:
- full changelog must be accessible from somewhere obvious (root of repo, linked in description, etc)
- past releases should include a date directly in the changelog
- for projects with slow release cycles, a WIP list of unreleased changes
Your first step should always be in your repo, preparing the changelog prior to making a new release. Automated tools such as clog-cli can be great for this: you should be hand-updating these when it comes to release time, but using automation to ensure each changeset is listed out to be able to maintain a list of unreleased changes will make the release that much easier.
Any sort of automation you can enable to make sure this "unreleased changes" section doesn't require human work is great; using a specified format for your commit messages such as the conventional commits style can make this virtually trivial, since there are a mass number of tools which can generate changelogs, news files, etc out of the consistent format. More generally -- and out of scope of this post -- having a consistent commit style just plain makes it easier to find things in your history and to track down any newly introduced bugs.
Once you want to cut a release from this changelog, you'll want to declare your new version and clean up the contents. Specifically: add a new heading with your new version (following semver, ideally -- it's completely useless to your users to have the release number be "2021.07.23" since that doesn't tell us anything new about your release!), the current date, and long-form descriptions of each relevant change. The long-form descriptions should include all categories of changes (with breaking and security changes being loudest, then features and bugfixes broken out from any other changes, with any further categorization being icing on top), each with a clear description and a link back to the relevant changeset.
That might look something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
This changelog should be updated in your mainline branch of your source tree
along with any other changes required to push your release (ie. bumping the
version number elsewhere in code, but separately from any feature work related
to that release!).
./CHANGELOG.md is a great place for your changelog, since
it's very visible and used commonly enough for people to check there, but
something similar such as
./RELEASE.rst or such is also fine.
Technically, I'd suppose having this changelog file be visible in the repo and linked to from your README and other docs would be the zeroeth step. Sadly, my backspace key appears to be acting up.
The changeset with the above changes (which I'll refer to as your "release
commit") should be pushed to your remote along with an annotated tag
containing the above release notes (note: this chunk is
git specific, but if
you haven't yet drunk the koolaid that is
git, there are almost certainly
equivalents in your VCS of choice).
Why an annotated tag in particular? Well, roughly, a "normal" git tag is just a lightweight pointer whereas an annotated tag can include additional things like, oh, I don't know, release notes. Additionally, git provides some nice facilities for viewing annotated tag messages and for showing only annotated tags without lightweight ones.
Using annotated tags also gives you a couple nice freebies elsewhere: for example, you can use
git describeto find the latest annotated tag and to show how much has changed since then. That makes it fantastic for describing the state of eg. nightly releases as compared to your latest stable release:
1 2 3
$ git describe v1.2.3-2-g977ec16 # HEAD points to 977ec16, which is two commits after release v1.2.3
git tag -a v1.2.3 is a nice easy way to do this. That'll open up your editor,
where you can paste in the same release notes you typed above. Feel free to
omit the version and date, since that's already obvious from the tag metadata.
The tag is also a good place to include anything specific to the update flow;
for example, you may want to add something like:
1 2 3 4 5 6 7 8
Ideally, this tag is the source of truth; eg. the act of pushing that tag should cause your CI system to release the new version to your package registry and any other release / post-release tasks. Though automation isn't a requirement for having good release notes, avoiding cases where your tags are out of sync with reality (say, in cases where a release fails and needs to be retried after a fix) will make everyone's life easier.
Finally, you should consider duplicating this release data for the specifics of your environment. For example, if you're on Github you'll find that "Releases" are not automatically created for your tags, annotated or otherwise, so you'll want to explicitly click the button once you've pushed the tag. It may or may not succeed at properly parsing your release notes from the tag, so doing a manual check and cleanup might be nice as well. Similarly, if you have an external site for the project, you may want to update a "News" page there.
Does this lead to a bit of duplication? Absolutely! Is that better than folks being unable to track down changes when they need to from whatever context they happen to be in? Most definitely. Keep in mind that some folks will be accessing your changelog by pulling your repo, some will see it via your repo host's web portal, some might read it in their RSS feeds, etc. As much as I'd love to live a life where all those systems read from a single source of truth, it just ain't the case. Make your changelog loud and visible, save the world.
Hall of Fame
To illustrate some of my above points, I'd like to call out a few projects which do some of the above quite well.
SpaCy's update diffs: SpaCy includes a verbose "What's New" page for each release. Especially wonderful is their explicit callouts for places where their changes will require client code changes and exactly how to go about doing so. See "No preloaded vocab" on that page, which includes the following:
Redis' upgrade urgencies: Redis assigns all changes with an upgrade urgency level and is careful to call out why a user might want / need to upgrade. Security implications are explicitly called out and the urgency is described conditionally on impact. See version "6.0.15" on that page, which includes the following:
1 2 3 4 5 6 7 8 9 10 11
Renovate's automation: All Renovate changes auto-generate the relevant changelogs including links back to the change requests which led to those changes and the commits once they hit the mainline tree. Additionally, their bot automatically comments on each change request included in a given release to make it even easier to track down when a given change was released.