Automating continuous deployment and rollback with Github releases and actions
June 22, 2020
I’ve been using Github Releases a lot lately - to manage CI and CD. Github lets you create a release just by using the UI. You can also create a release by using an action or via the api.
When a release is created for an application, I usually want to deploy this release. This is a common usecase for github actions and looks something like this:
on:
release:
types: [published]
name: Deploy
jobs:
deploy_release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install deps
run: yarn
- name: Build
run: yarn build
- name: Deploy
run: ./deploy.sh
However what if we released something that broke our app and wasn’t caught by tests or review - We’ll need to roll back. The most common pattern I see software teams use for rolling back a change is to revert the commit(s) which often results in confusion. You know what I’m talking about if you’ve ever seen a Revert the revert
pull request. It becomes even more fun when the revert of the revert gets reverted again.
Anyway, rather than reverting a commit to roll back a release, what we’ll do is delete a release. This is something that Github also lets you do via it’s UI or API. Our github action can trigger when a release is deleted and instead of just deploying the commit referenced in the event, we can use an action to fetch the latest release. With some modifications, we can update the above action to do both rollback and deploy for us in one go.
on:
release:
types: [published, deleted]
First we update the event to trigger for both published
and deleted
events.
name: Deploy or Rollback
jobs:
deploy_release:
runs-on: ubuntu-latest
steps:
- id: latest
uses: thebritican/fetch-latest-release@v1.0.3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
Then we use an action to fetch the latest release, I’m using thebritican/fetch-latest-release@v1.0.3 . Note that we need to pass github_token
in order for this to work and assign an id.
- uses: actions/checkout@v2
with:
ref: ${{ steps.latest.outputs.tag_name }}
Next we reference the output of our latest
step with our checkout
action, so we checkout the code for the right tag.
- name: Install deps
run: yarn
- name: Build
run: yarn build
- name: Deploy
run: ./deploy.sh
Then we build and deploy as we did before.
Now you have a simple github acitons based work-flow for deploying and rolling back releases. For reference, here’s the entire workflow
name: Deploy or Rollback
jobs:
deploy_release:
runs-on: ubuntu-latest
steps:
- id: latest
uses: thebritican/fetch-latest-release@v1.0.3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v2
with:
ref: ${{ steps.latest.outputs.tag_name }}
- name: Install deps
run: yarn
- name: Build
run: yarn build
- name: Deploy
run: ./deploy.sh
Bear in mind that this project is using yarn for package management, however you can replace those with a package manager/language of your choice, the concept remains the same.