Letting Robots Do the Work
Writing a CHANGELOG.md file manually is tedious and error-prone. Developers forget to update it, write vague entries like "various fixes," or update it inconsistently. The result is a changelog nobody trusts.
If you strictly follow SemVer and Conventional Commits, you can automate the entire release process — version calculation, changelog generation, git tagging, and package publishing — with zero human judgment required.
The Automated Pipeline Workflow:
Commits pushed to main
│
▼
Tool analyzes commits since last tag
│
├── Any BREAKING CHANGE? → bump MAJOR
├── Any feat:? → bump MINOR
└── Any fix:? → bump PATCH (if no higher bump)
│
▼
New version calculated (e.g., 1.4.2 → 1.5.0)
│
▼
CHANGELOG.md generated and committed
│
▼
Git tag created (v1.5.0)
│
▼
Package published (npm, PyPI, GitHub Releases, etc.)
semantic-release is the most widely used tool for this workflow in the JavaScript/Node.js ecosystem. It runs as a CI step and performs all of the above automatically, assembled from a small pipeline of plugins: one that analyzes commits, one that generates release notes, one that writes the changelog, and one each that publishes the package and pushes the git changes back.
python-semantic-release provides equivalent functionality for Python projects. release-please (from Google) is a popular alternative that works by opening a Pull Request with the proposed version bump and changelog, giving teams a human review step before the release is finalized.
What a generated CHANGELOG.md looks like:
## [1.5.0] - 2024-03-15
### Features
- **auth:** add OAuth2 login support (#142)
- **payments:** add support for SEPA bank transfers (#138)
### Bug Fixes
- **api:** handle null response from payment gateway (#145)
- **auth:** prevent session token from expiring prematurely (#141)
## [1.4.2] - 2024-03-01
### Bug Fixes
- **cache:** resolve memory leak on high-throughput requests (#133)
The entries are generated directly from commit messages. The PR/issue numbers are linked automatically. The grouping by type is automatic. You never have to decide "Is this a 2.0 or 1.9?" again — the commits decide for you.
The failure mode to know: Automation is only as good as your commit discipline. One developer who writes fix: stuff or bypasses the commit format breaks the signal. Teams that adopt Conventional Commits typically enforce it with a commit-msg Git hook (using a tool like commitlint) that rejects non-conforming messages before they ever reach the remote.
A common interview question is: "How do you manage releases in your team?" A weak answer describes a manual process. A strong answer describes the full automated pipeline: Conventional Commits enforced by commitlint in a pre-commit hook, semantic-release (or equivalent) running in CI on merge to main, automatic version calculation, changelog generation, git tagging, and package publishing — all without a human deciding the version number. Be ready to explain why this is better: it removes subjectivity, creates an auditable history, and makes releases a non-event rather than a stressful manual process.