Most projects I’ve worked on have tried to follow semantic versioning, and it is probably one of the most-used strategies for versioning software.
It has a clear and strict specification. The problem occurs when a developer tries to follow this specification.
Semantic versioning is defined like this: MAJOR.MINOR.PATCH
- MAJOR: breaking changes
- MINOR: add functionality in a backwards-compatible manner
- PATCH: backwards-compatible bug fixes
This often means that, upon a new release, the developer must go through all changes since the last release to figure out the next version number.
This can be a difficult and time-consuming task. Often, it leads to sentimental versioning. To avoid this, we must remove all human interaction.

We can achieve that by using semantic-release.
This is a tool installed in the CI environment that examines the commit messages and, on this basis, automatically derives the next version number for the next release.
This means that all the team members must use the same standard when writing commit messages. Conventional commits is a standard that will help us achieve this.
The Conventional Commits specification is a lightweight convention on top of commit messages. It provides an easy set of rules for creating an explicit commit history, which makes it a solid base over which to write automated tools.
Since we already established that humans are not trustworthy, we will use a command line tool to generate conventional commits.
The tool will ask the developer some questions and create a commit message from these answers.
This tool is called commitizen, and it’s great for standardizing commit messages. You can install it like this:
npm install -g commitizen
After installing it, we must use git cz
instead of git commit -m "commit message"
. The procedure looks like this:
Example of other commit messages generated from these questions:
Commit message | Release type |
---|---|
fix(user): fixed correct e-mail address validation | Patch Release |
feat(user): add middlename for user | Feature Release |
perf(user): removed middlename for user.<br>BREAKING CHANGE: The middlename field has been removed. | Breaking Release |
When we have the commit messages structured in this format, we can utilize semantic-release. It is meant to be executed on the CI environment after every successful build on the release branch.
In this way, no human is directly involved in the release process and the releases are guaranteed to be unromantic and unsentimental.
Semantic-release is actually an npm package originally only made for Node projects. But by using a plugin, it can be used on all types of projects.
The plugin is called semantic-release/exec, and it provides you with the new version number and lets you execute your own custom commands.
Semantic release is installed like this:
npm install --save-dev semantic-release
To make it work in circleci, the build configuration file will look something like this:
version: 2 jobs: release: docker: - image: circleci/node:8 steps: - checkout - run: npm install - run: npx semantic-release workflows: version: 2 make_release: jobs: - release
Read more about setup for the CI environment here.
To sum it up, we now have semantic-release
installed on the build server, which analyzes the commit history.
The commit messages follow a standard called conventional commit
, with the help of commitezen
(installed on the developers computer).
This might seem a bit excessive, and for some projects, it can be just that. But for many other projects, especially those that have many humans involved, I really think this is something to consider.
Especially if you find yourself in the situation where you start growing unsure about the versioning process.
Then there is one one thing to do: remove the humans from the process.
Further reading: