December 14, 2019 — 4 min read
GitHub Actions for Continuous Deployment
GitHub Actions are a powerful tool to create custom software development life cycle workflows from directly in your GitHub repositories. I've moved from CircleCI for my continuous deployment needs and leveraged GitHub Actions as a seamless replacement for deploying directly to Netlify every time commits are made.
I've always been a proponent of automating as many of my workflows as possible. I wrote a blog post about deploying to Netlify via CircleCI, detailing my first continuous deployment setup for this site. CircleCI has been flawless and while this site isn't huge, it's now up to just shy of 300 pages but with around 3600 Gatsby generated images which has recently been causing build timeouts on my free CircleCI plan. Luckily, around the time I started hitting these limits, GitHub opened up access to GitHub Actions.
GitHub Actions enables you to create custom software development life cycle (SDLC) workflows directly in your GitHub repository.
I've transitioned from CircleCI to Github for building and deploying to Netlify which so far has been rock solid. Similar to CircleCI and many other CI/CD platforms, GitHub Actions uses yaml
config files to create what GitHub calls Workflows. A Workflow is a configurable automated process made up of one or more jobs. For my use, I have two almost identical workflows, one for production deployments and one for deploy previews to Netlify for any pull requests on my repo.
The workflow files themselves are pretty simple, containing a single job with multiple steps to handle repo checkout, environment setup, installation of dependencies, building the Gatsby site and deploying it to Netlify.
Let's take a look at my deploy to production file which will be run anytime there are changes to master
or release.
name: Deploy
on:
push:
branches:
- master
- release/*
For preview deploys of pull requests, the only differences is changing the name
of the workflow and the on
trigger to `on: pullrequest` which tiggers the action for all pull requests on the repository._
Next we define our jobs. For my simple deployment action I only have one job called 'build'. There is some basic environment definitions to use the latest version of ubuntu and set the desired node to the latest release of version 12 which are later references in the jobs' steps.
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
Continuing on, I define the jobs' steps with the first two steps leveraging first party GitHub Actions. First, checked out the repo on the newly created environment and then set up node on that environment. Once node is setup, the next steps are to install dependencies and to create a build of the Gatsby site.
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: |
npm install
- name: Build
run: |
npm run build --if-present
Once the site is built, I automatically deploy that build to Netlify. Netlify has put together their own GitHub actions, one of which exposes all the functionality of Netlify CLI within the context of Actions. In order to deploy to Netlify, I set two secrets within the GitHub repository settings. NETLIFY_SITE_ID
can be found in the Netlify Dashboard site settings. NETLIFY_AUTH_TOKEN
is a Netlify personal access token can be created in the Netlify user dashboard
steps:
- name: Deploy to Netlify
uses: netlify/actions/cli@master
with:
args: deploy --site ${{ secrets.NETLIFY_SITE_ID }} --auth ${{ secrets.NETLIFY_AUTH_TOKEN }} --prod --dir=public
env:
CD: true
Finally, combine all the pieces and the final file workflow looks like this.
name: Deploy
on:
push:
branches:
- master
- release/*
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: |
npm install
- name: Build
run: |
npm run build --if-present
- name: Deploy to Netlify
uses: netlify/actions/cli@master
with:
args: deploy --site ${{ secrets.NETLIFY_SITE_ID }} --auth ${{ secrets.NETLIFY_AUTH_TOKEN }} --prod --dir=public
env:
CD: true
While CircleCI initially worked great for my needs, as my site has begun to grow, I quickly realized I was bound hit the usage limits of their free accounts. GitHub Actions also has usage limits but they are extremely generous even for free accounts. We'll see if those limit change as the service becomes more and more popular but only time will tell.