Automated Semantic Versions for all projects with semantic-release and Gitlab CI!
Tags: gitlab, devops, automation
Published: 2019-10-10 16:25:57

## Introduction

When software projects start to mature, there usually comes a time when you need to start versioning your releases and publishing Changelogs.

Most programmers have ways to tackle this issue either by doing things manually and maybe keeping track of a `version` file in the project or by using ad-hoc scripts that never quite work.

At least this has been the case for me. This is why I started searching for solutions that would be agnostic to the type of project and language used and that could be easily added to my CI pipelines.

After some browsing and experimenting I've found a robust solution with
[semantic-release][sem] and [Gitlab CI][ci] that can be used with any project.

The rest of this post describes this solution.

## Semantic Release

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/o0lyitpgdtieq4pzjwf0.png)

Semantic-release is an `npm` tool that automates the process of
generating a new [semantic version][version] and Changelog for your project. All you have to do is adapt your commit messages to follow the [angular commits convention.][angular]

The tool works by scanning your commits history from the most recent tag
and increments the version number based on the commits:

- a `fix` commit increments the *patch* number of the version (the rightmost
  number).

- a `feat` commit increments the *minor* number of the version (the middle
  number).

- a `BREAKING CHANGE` commits increments the *major* number of the version (the
  leftmost number).

For example, suppose that your latest semantic version is `2.1.0` and you had to push a bugfix twith the commit message `fix: div by zero`. Your next release would be tagged `2.1.1`.

Since the tool is simply looking at your commits history, this means that we can use it with any project that uses Git. There are no restrictions on languages or frameworks. Moreover, there are plugins both for GitHub and Gitlab that simplify the process of committing and pushing new tags to the repository of the project as we will see next.

## Gitlab CI

I'm a big fan of Gitlab's integrated CI pipelines. All you need to do to
automate your workflow is to create a new project on Gitlab and add a
`.gitlab-ci.yml` file to the root of your project. Gitlab's own runners will then do its magic.

Thanks to the Gitlab plugin for semantic-release, creating a CI job for
releasing new tags is as simple as:
```
stages:
 - tag

semantic_release:
  stage: tag
  image: node:8
  variables:
      GITLAB_TOKEN: $ACCESS_TOKEN
  before_script:
      - npm install -g semantic-release @semantic-release/gitlab-config
      - cat $SEM_RELEASE_OPTIONS > .releaserc.yml
  script:
      - semantic-release -e @semantic-release/gitlab-config
  only:
      - master
```

After this there are only two things left to do:

1. You will need to create a personal access token and add it to the CI/CD Variables of your project. For this go to `Settings > CI/CD > Variables` and create a new variable named `ACCESS_TOKEN`. In the value field put your access token.

2. Semantic-release has configurable options that the tool can use. These can be set in a `package.json` file or a `releaserc.yml` file at the root of the project.

I've opted for the second option with a tweak. Rather than keeping the file in my project under version control, I created another `CI/CD` variable and pasted the options there.

To do this copy the below file into a `SEM_RELEASE_OPTIONS` variable of type `File` in your `CI/CD` variables on Gitlab.

```
branch: master
publish: ['@semantic-release/gitlab']
verifyConditions: ['@semantic-release/gitlab']
```

With this, Gitlab will use `semantic-release` to publish a new version every time a new commit lands on the `master` branch of your project and you can sit back and relax!


Happy coding!

[sem]: <https://github.com/semantic-release/semantic-release>
[version]: <https://semver.org>
[ci]: <https://docs.gitlab.com/ee/ci/>
[angular]: <https://gist.github.com/stephenparish/9941e89d80e2bc58a15>