Auto Version Bumps with Github Actions

Kevin Nuut
The Startup
Published in
7 min readNov 19, 2019

Automate your NodeJS package.json semver bumping on every pull request merge into master!

I originally had a B2K photo but learned Raz-B is trash. Enjoy some wholesome bumper cars by Bilby.

My problem with package bumping

Since I’ve been developing in NodeJS, one thing has always been a thorn in my side. Having to remember to bump the package.json version for our code releases. At my company, this is an essential part of a release because it helps us determine when a client needs to flush their cache against the API.

Doing it manually has always lead to a myriad of common issues:

  • If multiple people have pull requests, who wins on the conflicting bump number? What if one person starts first but finishes last?
  • When we forget to do it, it requires another pull request review just to make another change. We use GitHub Protected Branches to force us into reviewing our code, and its an Important Practice we want to keep!
  • Devs forget the bump, their peers forget to review, then we’ve released the “same version” of our app and cannot force upgrade cached clients. 🔥

These problems continue to grow with every new developer, especially as we grow into multiple teams working in the same repositories. I’ve known these kinds of things could be solved with Jenkins, but it’s always felt a bit much just to get version bumping. GitLab has solutions (fellow Medium shoutout) as well, but we’re on GitHub…

But what if we could automate the whole process? What if every time a developer approved a pull request and merged it into master, GitHub was smart enough to increment the package.json based on the severity of comments, update the changelog based on commits in the pull request, and push everything to master without human intervention! If only…

Look at all that code on Github!

GitHub Actions and TriPSs to the rescue

If you haven’t heard of it, GitHub has a new feature called Actions that lets you automate your workflow by running temporary server routines after any GitHub event (such as checkout, pull requests, pushing branches, etc).

It also has a budding community of developers who are starting to build their own actions to solve various CI/CD problems. I debated building my own Action to automate the process but a wonderful GitHub developer by the username TriPSs had already gotten to it!

Don’t let the low star count fool you. In a few elegant lines of code, conventional-changelog-action promises on our automation dream above. It checks for release severity (MAJOR, MINOR, PATCH) based on Conventional Commits, bumps the package.json version, tags the release, and creates a change log of all commits between now and last release (again using Conventional Commits).

Out of the box, the Action works almost as expected. I found the documentation a little confusing as someone new to GitHub Actions so I thought I’d outline the exact steps here.

  • If you open your repo in GitHub, you’ll see an “Actions” tab.
  • Click “New workflow” then “Set up a workflow yourself” to set up a custom flow. Searching for conventional-changelog-action seems to not render proper documentation in the toolchain, so we’ll set it up manually.
  • In the “Edit new file” section, paste the following:
name: Bump version
on:
push:
branches:
- master
paths-ignore:
- 'package.json'
- 'CHANGELOG.md'
jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
with:
token: ${{ secrets.GITHUB_TOKEN_ACTION }}
- name: Bump version and push tag
uses: TriPSs/conventional-changelog-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN_ACTION }}
git-message: 'chore(release): {version}'
preset: 'angular'
tag-prefix: ''
output-file: 'CHANGELOG.md'

Note, YML above was updated on 2020–02–29 (LEAP YEAR!) to use actions/checkout@v2 to properly get node modules then start changelog action. I will try to keep this updated anytime GitHub Actions change. Andy Nunes also noticed that you may need to replace “@master” with “@VERSION” depending on the latest TriPSs release.

The prior snippet is fairly boilerplate, but for a better explanation on Actions, I recommend reading Write Cool Code’s post on it. I’ll outline the steps:

  • We are telling GitHub to run our action when code is pushed into master. This is the use case we want to support pull requests being merged.
  • We then ask it to run the conventional-changelog-action on an ubuntu-latest snapshot and provide it the necessary configuration of our user’s GitHub token, message style of our automated git commit, our conventional commit standard (Angular), and where to save our changes.

Once you save, you should be able to commit push any new code to your master branch then watch the build kick-off. Go back to the Action tabs to monitor if any workflows have run and whether they were successful. If you don’t have any branch protections on your master branch, it should just work!

GitHub handled this feature really well!
If you don’t protect branches, the tree dies (or some metaphor I dunno).

Working with protected branches

But what if you do have protected branches? Then it gets a little annoying.

If you haven’t set up GitHub Protected Branches and you are working with multiple developers, I highly recommend doing so. It allows you to enforce peer reviews on your feature branches by preventing anyone from pushing directly to master without a peer-reviewed pull request. Overall, this is great for reducing bugs and enforcing community, but it makes GitHub Actions a little grumpy in the process.

Example of having to add a branch exception for my Admin account.

Setting up a PAT

Since it prevents people from pushing directly into master, it also means your Action cannot merge a new package.json into master. To bypass this, we will allow administrators to push to master, and set up a special token built off of one of those Administrators (note that you’ll need admin access to do this).

  • First, go to your Personal Developer Settings and create a new Personal Access Token (PAT). Name it GITHUB_TOKEN_ACTION and copy the value temporarily to be used in our next step.
  • Then go to your repo’s Settings > Secrets and Add a New Secret
  • Name it GITHUB_TOKEN_ACTION and paste in your PAT.

Avoiding infinite loops

Before I show you how we’ll use the new token, I want to bring up two odd quirks that we’ll need to avoid. By default, GitHub seems to avoid running Actions that would be caused by Actions. This seems to work by checking the GITHUB_TOKEN, but since we generated our own it’ll cause each Action push to start a new Action until you suddenly have 1000 commits.

It seems odd, but to avoid this, we’ll prevent our Action from running if the only files we see changed are the ones our Action itself would change. In this case, only package.json and CHANGELOG.md are ever updated, so we’ll use the Paths Ignore feature in GitHub configs to prevent this.

Checking out our code

The other issue with changing our token is that the repo does not check itself out on the server for us to run the Action on. I couldn’t find why this is, but to get around it, I added a step to intentionally check out the code with the new token before we run our bump step.

Updated YAML File

With those caveats out of the way, here is our new workflow YAML file.

name: Bump version
on:
push:
branches:
- master
paths-ignore:
- 'package.json'
- 'CHANGELOG.md'
jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v1
with:
token: ${{ secrets.GITHUB_TOKEN_ACTION }}
- name: Bump version and push tag
uses: TriPSs/conventional-changelog-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN_ACTION }}
git-message: 'chore(release): {version}'
preset: 'angular'
tag-prefix: ''
output-file: 'CHANGELOG.md'

To get this working on our protected branch, we’ve done the following:

  • add paths-ignore to avoid infinite loops if the only change is the two files changed in our original Action
  • Add a precursor step to check out our code with our new token (normally done by default in the conventional-changelog-action
  • change our github-token to reference our new secrets.GITHUB_TOKEN_ACTION

Now when we merge our next pull request into master, everything will work as expected even with our Branch Protections in place to keep our code safe!

Example of auto-tagging in Kraken

What next?

I’m excited to see what GitHub Actions bring as more developers add to it. I’m hoping to update this article frequently as they solve some of these issues with protected branches. I don’t feel like we are doing anything mind-blowing, but it’s nice to finally automate this nuisance away.

--

--