go-changelog
go-changelog is a library and a set of binaries for working with changelog
generation, written in Go.
The underlying strategy is to have a directory committed as part of the git
repo you're generating a changelog for--by convention, .changelog
is used,
but the tool doesn't care what it's called or where it is. Inside that
directory, each unit of change--almost always a pull request--has a file named
after the unit of change. For example, a PR would include a .changelog/PR#.txt
file, where PR#
is the unique ID for the PR.
Because each PR or unit of change has its own file, you should never encounter
merge conflicts for changelog entries.
The tool then takes two commits for the repository--specified by any valid git
reference--and compiles a list of the files present in the later commit that
aren't present in the earlier commit. These are assumed to accurately reflect
the changes that have been added between the two commits.
Installation
Binaries
To run the command line binaries, use Go to build the commands. For example:
$ go install github.com/hashicorp/go-changelog/cmd/changelog-pr-body-check@latest
Docker
A Dockerfile is provided that will build an image containing the binaries. You
can either run this container directly, or you can build an image sourced from
it that specifies the environment variables and entrypoint. In the future, when
go-changelog has config files, this will be how you can add your config files.
FROM hashicorpdev/go-changelog
ENV GITHUB_REPO=myrepo
ENV GITHUB_OWNER=myorg
# Maybe leave this one out and specify it with -e
ENV GITHUB_TOKEN=foo123abc
ENTRYPOINT ["/go-changelog/changelog-pr-body-check"]
Usage
For using the go-changelog
library, please see go.dev.
For using the specific binaries, please see the README files in their
directories.
The files in your directory describe the changes that will be used to generate
the changelog. Their contents should have the following formatting:
```release-note:TYPE
ENTRY
```
Where TYPE
is the type of release note entry this is. This is usually "bug",
"enhancement", etc. The tool does not prescribe a list of types to choose from;
whatever you enter will be available to you when generating the changelog.
ENTRY
is the body of the changelog entry, and should describe the changes
that were made. This is used as free-text input and will be returned to you as
it is entered when generating the changelog.
Sometimes PRs have multiple changelog entries associated with them. In this
case, use multiple blocks.
```release-note:deprecation
Deprecated the `foo` interface, please use the `bar` interface instead.
```
```release-note:enhancement
Added the `bar` interface.
```
Best Practices
Keep changelog entries with code change commits
This system works under the assumption that changelog entries will always be
kept with the code they're describing changes to. So it works best if the code
and its changelog entry appear in the same commit. This means cherry-picks that
move the code around will make sure to bring the changelog entries with it and
will keep the changelog correct.
Using squash merges makes this easier.
Lean on automation
A sample changelog-check
binary is included in the cmd
directory to show
how a GitHub PR can be checked to ensure that a changelog entry is attached to
the PR. Lean on automation to guard against forgetting changelog entries when
submitting PRs.
You can also have bots generate these files from PR bodies--when a PR body is
updated, have a bot push a commit updating the changelog entry as well. The
markdown code blocks can be easily parsed out of the PR body using the
NotesFromEntry
function in the changelog
package, and re-formatted into a
file for the commit. This means users don't need to mess with git to update
changelog entries.
Shortcomings
Immutable changelog entries
Once a changelog entry is merged, it's hard to mutate it and make sure the
commit updating it stays with the code. It's not impossible--you just need
to remember to always cherrypick both commits--but it is harder. It is
recommended that you use automation and PR review to make sure you're happy
with the changelog entry before merging, as much as possible, to keep these
situations limited.
Silent failure when no changelog entry is set
If a change forgets to include a changelog entry at all, the tool will ignore
it completely. PR-based tools can shout loudly that a PR did not include a
change, but this system does not have that capability without expecting every
commit to have a changelog entry associated with it, which seems unreasonable.
It is recommended to use automation to prevent changes without changelog
entries before they're merged, to ensure every change gets an entry.
Why
Changelogs are an important interface for helping users be aware of development
efforts and behavioral changes in software. Writing good changelogs is tricky.
- Writing changelogs by hand inevitably leads to people forgetting to include
things in the changelog.
- Basing changelog entries on commit messages conflates two audiences; commit
messages are for developers and maintainers and should be directed towards
them, changelog entries are directed towards users and should be written in
the terminology they understand and use.
- Writing changelogs in PR bodies is quick, easy, and allows them to be part
of the PR review process, but PR bodies aren't stored in the repository
itself (meaning they can't be easily backed up, etc.) and makes it harder
to keep changelogs with the code they describe as that code is cherry-picked,
backported, and merged across branches.
go-changelog
prioritises making it easy to generate correct changelogs no
matter what shenanigans you engaged in to build the branch you're releasing
from. It also prioritises flexibility around workflows and changelog
formatting.
Prior Art
This package is based on a bunch of experiments with the Google Cloud Platform
Terraform provider
and the lessons learned while generating it. It is also based on prior art in
the community: