Topic 8.3
Release Automation: Versions, Changelogs & Release Trains
In one line
Releasing should be a button (or nothing at all). Conventional commits and tools like semantic-release or release-please compute the next version, generate changelogs, tag, and publish, whether you ship continuously or on a release train.
Think of it like this
A newspaper press. Articles (commits) are written all day; at press time the paper is assembled, numbered, and printed automatically with a table of contents (changelog). Nobody hand-writes the index at midnight.
Key ideas
- 01
CONVENTIONAL COMMITS:
feat: add wishlist(minor),fix: rounding in totals(patch),feat!: remove v1 APIor aBREAKING CHANGE:footer (major),chore:/docs:(no release). Enforce with a commit-msg hook or PR-title check (Git course, commit messages). - 02
RELEASE TOOLS read the commits since the last tag: SEMANTIC-RELEASE (fully automatic on merge to main: compute version, tag, changelog, GitHub release, publish packages), RELEASE-PLEASE (opens a 'release PR' with the next version and changelog that you merge when ready), and Changesets (for JS monorepos). The version and notes stop depending on someone remembering.
- 03
For deployable services, the immutable artifact identifier (Git SHA image tag) is what's promoted between environments (Phase 5, versioning and promotion); a human-friendly SemVer tag or date version can be added for release notes. For libraries and APIs consumed by others, SemVer is essential (DevOps guide, twelve-factor).
- 04
RELEASE CADENCES: continuous deployment (every merge ships, possibly behind feature flags), scheduled release TRAINS (e.g. weekly cut from main to a release branch, stabilise, ship; common for mobile apps and regulated environments), and hotfix paths (branch from the release tag, fix, cherry-pick back to main: Git course, cherry-pick).
Code & diagrams
name: release
on:
push: { branches: [main] }
permissions: { contents: write, pull-requests: write }
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: googleapis/release-please-action@v4
id: rp
with: { release-type: maven }
- if: ${{ steps.rp.outputs.release_created }}
run: echo "Released ${{ steps.rp.outputs.tag_name }}" # build + publish the tagged artifact herev1.4.2 (last tag)
fix: handle empty cart totals → patch
feat: add wishlist endpoint → minor
docs: update README → no release
=> next version v1.5.0, changelog grouped by Features / Bug FixesExplain it without notes
Why generate versions from commit messages instead of choosing them manually?
Practice
A mobile team wants predictable weekly releases while developers merge continuously. Design the flow.
Trade-offs
- ↔
Fully automatic releases maximise flow but need strong tests and flags; release PRs or trains add a human checkpoint and predictability at the cost of latency.
Done when you can
I can set up automated versioning and changelogs
I can choose between continuous releases and release trains