We started off using a commit message based workflow, but have just finished the migrating to a GitHub Label based workflow that is less workload on individual contributors. This post will cover how, and why.
We started using semantic-release to handle commit message based deploys. The way semantic-release works
is you would add a specially formatted commit that included a version prefix indicating you wanted a deploy. For
[PATCH artwork] Fix safari mail issue would mean that by merging a PR with this commit into master
should trigger a patch release.
This is their ideal flow, but the reality for us is that a lot of people would forget to do this, or write commits
[PATCH] bumpity bump. Even worse, these kind of commits were the perfect reason for pushing to master and
skipping code review to speed things up.
We could have added a pre-commit hooks that enforced the messaging on commits, but that's not very Minimum Viable Process - where we try to map new tool/process improvements to existing behavior instead of regimenting new behavior when possible.
The problem felt like the idea of declaring your version changes at commit time felt like a disconnect from how people thought about deploys. The code unit for a review is a Pull Request, not per-commit. To try improve on our deployment, we re-grouped and discussed what could be a better mapping to our existing workflow. Our answer was: PR Label based deploys.
The idea is: You write a PR exactly as you used to, when you create a new PR then you apply a label saying whether it is a major, minor, patch or trivial PR and when it is merged then deploy could be made for you.
To match our existing behavior completely, we would automatically add the "patch" label to any PR which doesn't declare what type of deployment it is up-front.
I summarized our ideal state, and turned it into an RFC on our Reaction repo: "Change rules around automatic deploys, and add a CHANGELOG" .
We started building this infrastructure inside our app Reaction. Our implementation was a PR that lasted a few months. It was a hard project to prioritize, and didn't really seem to have an end in sight. This changed last week when we discovered the work going on over at auto-release by the team at Intuit.
The team at Intuit had taken the same problem and worked to apply it generically, making it a useful tool for everyone rather than just for one type of project. Perfect.
To try it out, I set it up on our upcoming CLI for the Artsy Omakase JS stack - which is a Lerna mono-repo. This means it's a single repo for many JS packages, which makes it a bit more complex than a normal repo for a node project.
Auto-release handled this setup out-of-the-box,
10/10 - so it was likely to handle our simpler repos. In the
process we made a bunch of PRs back and were quickly iterating on making it work well for Artsy also. Collaborating
on projects like this is our bread and butter, it means we don't have to build tools from scratch and
can improve upon great work by others.
To use it, we needed to set up two environment variables:
NPM_TOKEN- used to deploy your package to NPM
GH_TOKEN- used to create GitHub releases
and you need to make sure your CI has write access to your repo, so it can push tags and the CHANGELOG entries back to your repo.
Downsides to Continuous Deployment
Both the commit message and PR label based continuous deployment structure comes with one annoying flaw, if you're merging many PRs at once - then you can get into trouble with versioning. We've been discussing ideas around this in the [auto-release issues][ar_iss]. We already had this flaw, so it just propagated to the new technique. We've been wondering if deploying via GitHub actions may fix this.
With auto-release you can have set an option to treat having no release label on your PR as a being a "patch" release. This is a great setting, but an ideal workflow for us is to showcase what is happening every time. This makes the understanding of our deployments explicit, and is a good reminder to highlight that you might want to change the type of deployment. You can see this happening to me in this PR.
We're currently at
9.1.59 - meaning 58 patches in a row, so it's pretty rare for a minor or major. By making it
obvious how to change that during the PR (by highlighting that it's classed as a patch each time) we can maybe make
the version number change a bit closer to some form of "semantic reality".
We wanted to first roll this out on one repo, so we scoped our Artsy Peril changes to just the
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
The simplest implementation for adding the label is this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
This will dynamically add your label if it doesn't exist on the repo yet. Our production implementation is a bit more complicated because it will create all of the different labels too. This means as we roll out the PR Label based workflow to other repos, the labels will be consistent.
Introducing auto-release meant introducing our first automatically generated changelog (something I'm not sold on, I see changelogs as consumer-facing. Most PR title/descriptions aren't aimed at downstream consumers, but I'm open to giving this a shot as today the consumers are also contributors to the repo) which broke one of our global Peril rules. This rule would detect a if a repo has a changelog, and ask you to update it if you've made any app changes. We amended that rule to detect auto-release on the repo first.
So, how do I get this set up?
For the automatic deployment:
- Install auto:
yarn add -D auto-release-cli
yarn auto initand go through the questions
- Add a
releasescript to your
"release": "auto shipit"
- In your CI, set both
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrcto "log in" to NPM in our deploy steps
- In your deployment phase run:
For the Peril rule:
"pull_request.opened": "artsy/peril-settings@repos/reaction/addPatchLabel.ts"to your
This is a little bit risky, because we can change our implementation anytime. If that's an issue, implement it yourself in your settings repo. You got this.
To wrap this up, I specifically want to call out @hipstersmoothie for their great work on auto-release (and jimp.) It's been really easy to get started and already covered nearly all the cases we needed. You did great work here.