Automate your DevOps flow with conventional-commits

A smooth introduction to versioning and release notes automation using Git.

Icons made by Pixel perfect and DinosoftLabs from Flaticon.

Introduction

Since the start of 2020, I’ve been involved in a project to create a whole new RESTful API using Bitbucket as our version control tool. Since the beginning, my team and I have been obsessed with continuous integration so we decided that on each merge on the main branch, we would generate a new version and release notes in the same repository.

  • CHANGELOG.md: This is a file that most open-source projects have to keep track of everything that is being done in the project. Take a look at this project.
  • Conventional-commits: I could do a complete article about them but people that know much more than me already did it 😂. The only thing you need to know is that if you prefix your commit messages with keywords, you can enrich them with extra information. Examples of commit messages that follow conventional-commits are
"feat: I develop an important feature"
"fix: I saved the day!"
"break: endpoint deprecated"

Let’s grab the ingredients

Big picture of what we are trying to achieve.
After a pull request is merged, the commits are all squashed in the merge commit and prefixed with a * symbol.
  • Date: Second line of the merge commit.
  • Information about the work done in the pull request. Note that every commit coming from that pull request is prefixed with the * symbol and they are following conventional-commits.
newVersion.date = new Date();  // THAT WAS EASY :) ...
newVersion.branch = child.execSync(`git status`)
.toString("utf-8")
.split("\n")[0]
.replace("On branch ", "")
.trim();
const lines = child.execSync("git log -1 --format=full")
.toString("utf-8")
.split("\n");
newVersion.commit = lines[0].split(" ")[1];
newVersion.author = lines[1].replace("Author: ", "").trim();
newVersion.changes = getChanges(lines);
let previousVersion = "0.0.0.0";
if (fs.existsSync(versionFile)) {
previousVersion = JSON.parse(fs.readFileSync(versionFile));
}
newVersion.version = getUpdatedVersion(previousVersion, newVersion.changes);
fs.writeFileSync(versionFile, JSON.stringify({
current: newVersion.version
}, null, 4));
updateChangelogFile(newVersion);
child.execSync(`git add ${versionFile}`);
child.execSync(`git add ${changelogFile}`);
child.execSync(`git commit -m "[SKIP CI] Bump to version ${newVersion.version}"`);
child.execSync(`git tag -a -m "Tag for version ${newVersion.version}" ${newVersion.version}`);
child.execSync(`git push --follow-tags`);

Conclusions

We’ve seen a (simplified) approach that allows my team and me to extract semantic information from the merge commit once a pull request is merged. The requirements to make this script work are:

  • The merge strategy configured in your repository must be squash-and-merge. That way, all the commits in the pull request will be stored in the merge commit message.
  • Define a pipeline that will trigger the generate-version-and-release-notes.js script after a (merge) commit is created in your main branch.

Proud teacher-volunteer at Migracode and Cloud-engineer at Ohpen where I keep pushing my AWS+Serverless knowledge every day.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store