← Back to Blog

Auto-generated release notes and the naming fix

·5 min read

The last job in the publish workflow creates the GitHub Release. It uses a third-party action, auto-generates the notes from the commit history, and (after a brief naming saga) titles the release with nothing but the tag name.

The action

- name: Create GitHub Release
  uses: softprops/action-gh-release@v2
  with:
    generate_release_notes: true
    prerelease: ${{ contains(github.ref_name, '-') }}
    make_latest: ${{ !contains(github.ref_name, '-') }}
    name: ${{ github.ref_name }}

generate_release_notes: true delegates the notes to GitHub's own release-notes generator, which groups merged PRs by conventional-commit categories, Features, Bug Fixes, Documentation. That is why the repo's PR titles follow the convention: they are the release notes, written at merge time instead of release time.

The naming saga

The original template read name: pyRPC ${ github.ref_name }, producing releases titled "pyRPC v0.12.0". A naming cleanup renamed every existing release to its bare tag and changed the template so future releases match. The change was trivial and the motivation was consistency: the tag is the canonical identifier everywhere else (changelog, docs, npm, PyPI), so the release title now says exactly one thing.

The tiny diff with a review path

The fix itself was a one-line workflow change. But main is protected (no direct pushes) so even this diff went through a PR, passed the test workflow, and merged like any other change. This is a small-scale example of the repo's rule: everything lands through review, including CI and release machinery. The release pipeline is itself released.

What make_latest means downstream

make_latest: true on the stable tag makes the new release the highlighted "latest" on the releases page. Prereleases opt out automatically. Combined with the auto-notes, the release page becomes: title = tag, body = the PR log, latest = the newest stable, assembled with zero manual content entry.

The takeaway

Release notes are an information channel, and the cheapest reliable source of that information is the commit history you already write. Generating notes from PRs, naming releases by tag, and deriving prerelease state from the version string keeps the whole release artifact derivable from facts the repo already knows, nothing to remember, nothing to type.