skip navigation
"Software developer with a kaizen mindset"

Release Strategy

Saturday Nov 27, 2021

A while back I was trying to figure out how to automate releasing and versioning for one of my sideprojects. It is an api designed for use in jamstack and is written in golang. Here I’ll describe where I’ve ended up now.

I already had my gitlab ci/cd pipeline setup and really just needed something to track versions and to release that version to production. The easy step would have been to start using the merge commits to main as versions and release on merge to master. It however lacked good versioning as the commit hash is hard to read and has no chronological component built in.

Semantic versioning

semver.org

So to tackle that first requirement I looked into semantic versioning. It allows for ordering and has a clearly defined way to increase versions. It’s also easy to read at a glance and should not give any confusion when comparing the source to whats deployed.

I’m not sure I strictly meet all semver requirements yet but it’s definitely a good starting point.

Tags

git tag

Next I needed a place to store the version. In other side projects I opted for a version file in the repo itself. However that got really messy with commits and was also hard to use from a version control point of view.

Git tags however lets me easily go back to a previous version of the code base. Ties the version to a specific set of the codebase. And gitlab allows me to trigger my ci/cd pipeline by adding new tags.

So my pipeline now automatically builds a release version and deploys it to production when adding a tag with a semver syntax. You could easily adapt it to have it release to a staging environment instead with a manual trigger for production.

See below for the gitlab-ci rule:

publish:
  ...
  rules:
    - if: '$CI_COMMIT_TAG =~ /^[0-9]{1,99}\.[0-9]{1,99}\.[0-9]{1,99}$/'

Conventional commits

conventionalcommits.org

Now that my build, deploy and versioning strategy were taken care of I wanted a way to keep track of what kind of changes I had done. Primarily to see if I need to make a patch, minor or major version upgrade.

For this I decided to go with conventional commits. I like it for being lightweight and it happens close to when I make the change. Ie on the commit itself.

For now I’ve selected the following tags myself:

  • feat:
  • fix:
  • chore:
  • docs:

And using !: as a way to denote a breaking change, e.g. feat!:.

Tying it together

Now I have all the parts to easily release my project and I’ll probably use this template for most projects that require a strict version number.

However it is still a bit tedious to make a release. I have to:

  • Get the last tag
  • Check changes since the last tag
    • Check if any breaking changes -> then major version
    • Check if any new features -> then minor version
    • Any code changes at all -> then patch version
  • Tag sources and push that to the remote repository

Luckily with all the above conventions we can easily script all that with a few commands and some greping.

See the full script on github

Changelog

The changelog is still something that will need some tweaking. For now just outputting all commit messages into a CHANGELOG.md file with headers from the tag annotation suits my needs.

I may go to squashing commits and use those commit messages as a way to do release notes too. We’ll see what the future brings.

Share on:
Support: