Automate Semantic Versioning with Conventional Commits

jsilvax
3 min readMar 21, 2019

The Conventional Commits Standard makes it easy to automate Semantic Versioning. This allows your CI Pipeline to automate the versioning of an application by bumping version numbers in the package.json & CHANGELOG based on the structured commit messages of developers. Adding conventional commits allows contributors to exclusively focus on the changes they introduced to the code base through their descriptive commits (fix, feat, etc.), as opposed to what version they’re in when it relates to the updates and commits of others.

For more info see: Conventional Commits

How does this relate to SemVer?

The Conventional Commits Standard has the following ways to indicate version bumps:

fix — to indicate a bug fix (PATCH) ex . v0.0.1

feat — to indicate a new feature (MINOR) ex. v0.1.0

chore — for updates that do not require a version bump (.gitignore, comments, etc.)

docs — for updates to the documentation

BREAKING CHANGE — regardless of type, indicates a Major release (MAJOR) ex. v1.0.0

Let’s get a feel for these by seeing some sample commits:

git commit -m "fix: JIRA-1234 Fixed bug on foo"
git commit -m "feat: JIRA-2345 Adds new Widget"
git commit -m "chore: JIRA-3456 Updated README"
git commit -m 'feat: JIRA-4567 Added new theme>>> BREAKING CHANGE: Site redesign'

Enforcing properly formatted commit messages

yarn add husky @commitlint/cli @commitlint/config-conventional --dev

Now that we have our dev dependencies, we can begin to configure.

Let’s start off with Husky, which runs a pre-commit hook to lint our commit message.

In your package.json

"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}

For husky, we add a commit-msg hook.

Next, we need to configure the commit linting:

"commitlint": {
"extends": ["@commitlint/config-conventional"],
"rules": {
"subject-case": [2, "never", ["start-case", "pascal-case"]]
}
}

commitlint needs to extend @commitlint/config-conventional which has the configuration rules to enforce the conventional commits standard.

The “rules” section is optional. In my case, I want to override the subject-case rule to allow me to add a JIRA ticket number at the beginning of the commit message, like so:

git commit -m "feat: JIRA-1234 Implements Widget ABC"

So now if you attempt to commit without a properly formatted commit message, the commit will fail.

Doing so with feat, fix, chore will result in a successful commit

Updating the package.json and CHANGELOG based on the commit history

Before configuring the updates, you need to make sure that your package.json version begins at “0.0.0” like:

{ 
"name" : "your-app-name",
"version" : "0.0.0"
}

We want a clean slate when starting, so, when you add your first feature, conventional commits will bump and tag it to the correct v0.1.0.

Based on your requirements, the two options I recommend are semantic-release or standard-version.

If you need to publish to NPM and GitHub/Bitbucket, then semantic-release automates this all for you. This option is great for OSS if you’re developing a library or package.

If you need Semantic Versioning for a client application, where you have no need to go through NPM then standard-version is right for you.

Let’s add standard-version

yarn add standard-version --dev

Then add a release script to the package.json

"scripts" : { 
"release" : "standard-version"
}

Based on your versioning strategy, you might want to have pre-releases. You can enable this by adding the prerelease flag, like so:

yarn release --prerelease beta

When configuring your CI pipeline, you’ll also need to add an additional step after “release” to PUSH your changes up to your repo.

git push --follow-tags origin $(git branch)

Overall

The Conventional Commits Standard makes semantic versioning a breeze. It allows your team to be more productive by focusing on the code they’re writing instead of repetitive actions, like versioning, which is better suited for🤖.

--

--

jsilvax

Senior Software Engineer @Netflix Prev. @NBCUniversal. #000 Coffee Addict. #webperf enthusiast