Introduction to Semantic Release posted Tuesday, April 30, 2019 by liv

(this post was originally released on the Greenkeeper Blog)

In our last blog post, we talked about SemVer and how it helps communicate changes in your software. Now we’ll have a look at taking it a step further and completely automating our software releases. We do this by using a tool called Semantic Release.

Semantic Release takes care of the entire release process for you. Why would we take this even further? Easy: Humans tend to slip up easily, so it’s easier and safer to have a computer do it! When handling things like releasing a breaking version, we want to make sure that we don’t make mistakes. By using Semantic Release, the computer takes care of the critical parts, leaving us with less worries and more time!

Using a commit message format

To make sure that we always release correct versions, we’re going to start by having our commits adhere to a standard. We’re going to be using what is known as the Angular Commit Message Conventions, although the format can be customized using plugins. A commit that adheres to this standard looks like this:

An example commit using the Angular conventions

We can break this commit message up into three distinct parts:

  • Type: This can be one of a few predefined strings, such as “feat”, “docs”, or “refactor”. It tells Semantic Release what impact the commit contents have on the next version.
  • Scope: This specifies the subsystem that our commit modifies, such as api, website or docs. If our commit modifies more than one subsystem, we can use an asterisk (*) instead.
  • Subject: A description of the change. Should be written in an imperative, present tense. So “change […]” instead of “changed […]” or “changes […]”.

Your commit message can also include an optional body. This is a more detailed description of your change, separated by an empty line. Last, a footer is sometimes inserted to describe any breaking changes, but we’ll get to that in a second.

Enforcing a commit message format

Using the Angular Commit Message Conventions is a good start, but what about the rest of your team? How do you make sure that everybody uses this standard? Enter commitizen, a command-line tool to make it easier to do that. Installing it in your project for others to use is explained here, but it boils down to running these commands:

npm i -g commitizen
npx commitizen init cz-conventional-changelog --save-dev --save-exact

This modifies your package.json file so that every developer who uses the command-line tool generates the same commits. If you want to encourage your team members to use the command-line tool, you can install it in your project:

npm i -S commitizen

Or even better, you can add an npm script in your package.json to make it even easier:

  "scripts": {
    "commit": "git-cz"

This way, generating a Git commit formatted after the Angular Commit Message Conventions is as simple as running npm run commit!

Generating a release

Now that we made sure to generate our commits in the correct fashion, let’s install Semantic Release into our repository. The easiest way to do this is by using the CLI. It’s as simple as executing this command:

npx semantic-release-cli setup

This performs a bunch of steps and even sets up integrations for Travis CI and CircleCI! Now, if you want to perform a manual release, all you have to do is to run npm run semantic-release. This will perform all the necessary steps to release your module on npm and GitHub (and, as opposed to humans, it will always perform them in the correct order):

  1. Figure out the last version you published
  2. Determine the release to publish (breaking, feature, fix)
  3. Generate release notes
  4. Update the package.json file and generate a Git tag
  5. Push the new release to npm and GitHub

As you can see, it automates the entire release process so you only need to run one single command! And all this because we formatted our commit messages in a consistent manner!

Wait, how does it determine the new version?

Semantic Release determines which version specifier to bump by analyzing your commit messages. Here’s a simple example:

A diagram explaining how version updates are constituted from commit messages

As you can see, the type of the commit message determines the version bump. When you introduce a breaking change, you add a paragraph in the commit message body that starts with BREAKING CHANGE. This way, Semantic Release can automatically figure out where to increment the version.

Generating releases automatically

Having to run npm run semantic-release every time we want to release a new version gets tedious after a while. What if we could automate this even further? Well, we can! If you used the Semantic Release CLI earlier, you should have had the chance to set up CI integration. This means that if you use Travis CI or CircleCI, Semantic Release will run every time you push a commit to your release branch.

This plays into one of the big concepts in Open Source: Release Early, Release Often. If you merge a pull request, a new version will release. If that’s too rapid, you could keep a development branch like dev and periodically merge it into master, where Semantic Release then can work its magic.

If you didn’t use the Semantic Release CLI earlier, you will have to go through some manual steps. Thankfully, the Semantic Release team has compiled guides for various common CI systems. Examples of this are Travis CI or CircleCI. More guides are listed here.

Further Resources

If you want to further configure Semantic Release, there’s a lot of options you can set either via the command line or in your package.json. For example, you can adjust the branch Semantic Release should build and release from with the branch option. A full, exhaustive list of options can be found here.

Some more interesting resources on Semantic Release:

Finally, don't forget...

Kill all humans!