Continuous Integration: Getting rid of Manual Release Management

Dec 16, 2019 • 5 min

A proper release is a lot of work and a lot of steps. To ensure that the work is done well and quickly, it is a good idea to automate as many of them as possible.

Let’s talk about two steps in particular: the (automatic) numbering of the next version, and the generation of its changelog.

After having worked on a rather wide range of applications and libraries, our feedback is clear: Automating the release process pays off!  When this process is automatic (or simply requires less work), you can do it more often. Hence you can release new functionalities (or fixes/patches) faster. And everybody wins.

The problem

Here we will use the semver numbering convention, which you may know.

As a reminder, with semver, a version number comes in the form X.Y.Z, or major.minor.patch. This system allows you to know at a glance if a library update introduces changes that require you to modify your code or not: minor or patch level updates preserve compatibility, but not major level ones.

Some dependency managers (like npm, pip, and many others) allow you to describe the compatibility of an application with specific versions of its dependencies, and in passing to ensure updates without " blowing everything up “ :P

Semantic versioning is good in theory, but in practice, you are not immune to trollish discussions when the time comes to release a new version. You often get a sentimental view of this famous X.Y.Z … Yet for an alternative point of view on the issue, you can read the sentimental versioning manifesto! (in English).

In short, choosing a version number is sometimes like an ordeal: multiple contributors (dev, product owner, …), waiting for a collaborator with the rights, lack of visibility on the content …

I faced this kind of problem and, after doing some research, I thought that we could automate all this.

How to automate

Continuous integration is one of the key elements when it comes to automating code delivery: one simple action on git triggers the production of an artifact (a container or a package for instance), launches a battery of tests, and produces a return. This return can contain: a success or error code, a test report, a code quality report, etc.

The question is: can we add to all this an automatic decision about whether to release or not a new version of the application, with its ad-hoc numbering (using semver), and why not a detailed changelog?

The answer is: yes, for instance by using semantic-release. There are other options, like semantic-delivery, but unfortunately I haven’t (yet) had the opportunity to test them all. Most of these systems work on the same principle.

The human management of the release is replaced by a tool that :

  • inspects the history of commits since the previous version
  • concludes a new version number following the semver rules
  • generates a changelog for this new version
  • applies the corresponding git tag
  • creates a release in your advanced code manager (for example gitlab)
  • optionally, launches a new continuous integration or deployment pipeline to take advantage of all this information.

Now let’s see a concrete example.

Using GitLab

At Enix, we use GitLab a lot internally. So my example will be based on this platform and on the usual .gitlab-ci.yaml file. Several strategies are possible:

  • triggering when a merge is done on a defined branch (like master)
  • triggering manually by pressing a button somewhere
  • … other, depending on your needs and your decision organisation

We will show here the first technique. To do this, we create a dedicated job in the IC, which will be triggered when we want to update the application.

This is what the job used by the website looks like when the master branch is updated. After having generated the site (with Lektor) and tested its W3C compliance, we launch semantic-release:

  stage: release
  image: enix/semantic-release:gitlab
    - npx semantic-release --ci
    - master
    - tags

In the example below, the tool analyzes the commits since the last version and concludes that the next version will be 1.30.0, ” yeah baby “: semantic-release output

So you note that the machine works for you:

  • The release type for the commit is minor
  • The release type for the commit is patch
  • Created tag v1.30.0
  • Completed step "generateNotes" ...

Then a deployment pipeline starts for this new version, until it lands in production on our Kubernetes cluster: pipeline gitlab

With as a bonus, the automatic creation of a GitLab release and its attached changelog : release gitlab

How far to automate and what are the limits

The functionalities listed above are available for most code managers, sometimes through plugins (GitHub) or sometimes with limitations (BitBucket). There are a good bunch of extensions here.

  • No restrictions on your branch merge strategies as the tool only interprets commits since the last tag! But make sure you run the tests before triggering an automatic decision.

It’s not magic

Since semantic-release uses messages linked to the commits to determine the type of change, you have to follow a very specific convention for these messages.

By default, we use the Angular commit message convention. At a minimum, the first line of the commit must follow this formalism:

feat(blog): an article about semantic-release

Or else:

fix(blog): reword introduction

You have to make sure that the people who commit in git stick to it, otherwise … no new version triggered!

But it is enough to follow this convention to not have to worry about the numbering and the release of the versions.

To conclude

Once the automation is in place, and by following a (relatively simple) convention in your commit messages, you no longer need to perform a release by hand, with the various manual operations this implies.

More precisely: the final decision to change the version is broken down into multiple small decisions that took place very early before it (when the code was being produced).

All this will allow you to make your releases more often, in a reliable way, and thus in fine to deliver code faster without sacrificing its quality!

Do not miss our latest DevOps and Cloud Native blogposts! Follow Enix on Twitter!