Hew:

Automatically manage changelogs and release notes by compiling and transforming version-controlled plaintext documents with a specification and example reference implementations

📄 Read the background blog post for more about the development and philosophy behind Hew.

🏁 Get Started

Ready to try automating your changelogs? Hew supports both greenfield and existing projects.

New Projects

  • Commit files to your repository either in the same commit as the code changes they describe or near those commits (as long as changelog files appear before the tag they should be included within, they'll appear in the right place). They should look like this:
    $ cat changelogs.d/fixes/file-removal.md
    Do not call `rm -rf /` any more.
  • Continue developing and tagging normally.
  • When you want to compile a changelog or release notes, call a standalone tool that implements the Hew specification to build a changelog document, call a Hew-compatible library in your language and render a document according to your preference, or consume the data for other use cases like notes for a code forge release. See the Hew repository for a current list of available library and standalone tool options.

Existing Projects

You're likely either tracking changelogs and release notes in a file like CHANGELOG.md or a feature for releases in your code forge of choice. In this mode of operation, one approach could be:

  • Keep your static CHANGELOG.md file.
  • Start tracking changes destined for a changelog using the approach for New Projects.
  • When you'd like to update your CHANGELOG.md file, use a Hew library or command-line tool to aggregate the changelogs for your new version and update your CHANGELOG.md file with the changelog assembled for your new version.

This approach avoids the need to backport existing release notes and lets you immediately start using changelog files for tracking code changes (and avoids the constant noise and churn of updating CHANGELOG.md frequently).

Q&A

Why not use commit messages?

Lots of existing tools today rely on a workflow like this:

  • Write commit messages that adhere to a standardized format
  • Walk these commits messages when collecting changelogs or release notes
  • Format them into the appropriate plaintext format

Why is this strategy suboptimal?

  • Immutability. Changelogs work best when they're treated as first-class documents well-suited for editing, improvement, and rich formatting like emphasis, code syntax, and images. The immutability and lack of formatting for commit messages preclude the ability to iteratively improve documentation beyond simple strings.
  • Broader change impact. A commit message is usually focused on the effects a change will have on the parts of the codebase it touches. However, the target audience for a commit message is usually a developer and not an end user. For example, changing how a score for a system is weighted may mention algorithm details in a commit message, but end users are likely more interested in how they should update their settings in observation of new behavior.

With patterns like those defined in the Hew specification, we can retain the convenience of association through version control history but improve the ergonomics of writing changelogs.

Why not continue to maintain CHANGELOG documents?

Maybe this approach works well for you! Here are some reasons why you might consider an alternative:

  • Churn. Performing a release often entails extraneous repository activity like assembling the final set of release notes, creating an empty "Unreleased" header, and more. Compiling release notes once on demand in response to a production tag automates the entire process.
  • Flexibility. Document-based changelogs in a single markup file lack sufficient granularity for other use cases like RSS feeds or adaptation into full documentation sites rather than fields in the release section of a code forge. Capturing the output of a changelog compilation step for a documentation generation step with tools like Sphinx can keep your authoritative changelogs in one place but represented in many different forms.
  • Automation. Maintainers can enforce changelog documentation as part of test validation with a simple CI step such as "assert a new file in changelogs.d". Contributors don't need to concern themselves with formatting a CHANGELOG.md file or puzzling out the right version for their change in.
Why not use a large language model (LLM) to turn version control changes into release notes?

There are plenty of use cases where this approach may work well. Here are some reasons why a specification-based strategy paired with written documents may work better for you:

  • Human context. Today's LLMs and models in the future may become very adept at explaining the intent and effects of code changes, but project authors are uniquely well-suited to synthesizing the effects of software changes over the lifetime of a project's changes and how they may impact users. For example, an LLM may accurately infer that a code change alters the field type of a database table, but a maintainer is best-suited to include examples explaining how to safely perform migrations or address potential conflicts for users with large sets of existing data.
  • Determinism. Clearly communicating the impact of code changes makes a big difference to your users. Writing version-controlled documents lets editors and authors collaborate on how best to get the point across in a repeatable way that everyone can provide feedback on and avoid missing important points an LLM may overlook from one prompt to another.
  • Coverage. Exhorting a model to be thorough may be fairly reliable, but committing changelogs in the same merge as a code change ensures that the change is definitively documented and can't be missed. Committing changelogs explicitly also ensures that authors avoid noise that might otherwise creep in from over-eager models.
Why focus on writing a specification and many implementations?

Adhering to a specification may seem overly-rigid and writing more than one implementation seems like excessive repitition! Yet there is method to the madness:

  • A specification ensures that Hew isn't the only way to make use of your changelogs. As long as a tool observes the specification's format, actual Hew programs may end up being the least important part of the Hew project. Maybe your code forge of choice implements the specification and your changelogs show up naturally when a new tag lands and over time the hew CLI fades into history. A specification also ensures that your changelogs are dealt with consistently across any Hew language implementation.
  • Paired with a lightweight specification, implementations across languages can integrate tightly with existing documentation ecosystems. For example, Jekyll drives many static page generation systems. A Ruby Hew implementation can bridge the specification with a native plugin to easily inject compiled changelogs into a release notes page with rich, native types for tags, commits, and timestamps without going through translation layers serialized into formats like JSON.
  • Great effort has been put into ensuring that the Hew specification is both succinct (to the extent a specification can be) and complete to facilitate use with code generation tools like large language models (LLMs). With an adequately detailed specification that doesn't eat too many tokens of context, sufficiently-sophisticated models could conceivably build a concrete implementation for your language and framework of choice with little or no effort on the part of a software developer. The specification serves as ground truth for a code generation tool to derive concrete implementations no matter how obscure the target langauge or framework.
Why did you name it "Hew"?

Hew (hewed, hewed, hewn, hewing):

  1. to make, shape, smooth, etc., with cutting blows.
  2. to uphold, follow closely, or conform (usually followed by to).

Hew is all about cutting up logs (well, changelogs) against closely-followed rules (or a specification).

The word is short, easy to turn into various technology-friendly forms (call your implementing class a Hewer, call the executable hew or hewctl), and I felt terribly clever about it.