You’ve been a model developer. You’ve placed your source code under version control and posted it to GitHub. You’ve got a suite of tests, and they run green. You’ve deployed your software to production.
That’s a lot of work. You deserve a break. Let’s automate these tasks. The goal is to only deploy changes that pass the tests that you have defined. The good news is that GitHub actions makes this easy.
To get started, place the following in .github/workflows/ci-cd.yml
:
name: CI_CD
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- run: rake test:all
deploy:
runs-on: ubuntu-latest
needs: test
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v3
- uses: superfly/flyctl-actions/setup-flyctl@master
- run: flyctl deploy --remote-only
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
In a few short lines, what the above says is:
On every put and every pull request:
check out your source, setup ruby, and run all your tests
if the tests pass, and the branch is
main
:- check out your source, setup flyctl, and deploy
Note: the above assumes that your main branch is named main
. Some older GitHub repositories use master
. Adjust the github.ref
check as needed.
The bad news is that if you try this with pretty much the simplest Rails application, it will fail:
rails new todolist
cd todolist
bin/rails generate scaffold Todo item
bin/rails db:migrate
There are two reasons for the failures. The first is an obscure bug in Ruby. At the moment, Rails 7.1’s fix is to remove the debug gem. This will eventually work itself out.
For the moment, if you are on Ruby 3.2 or don’t actively use the debug gem, the workaround is to run the following command to do the same with your project:
bundle remove debug
The second problem is that Rails system tests launch a browser, which by default need a display, and the GitHub servers don’t have one. So the solution is to change :chrome
to :headless_chrome
in one file:
require "test_helper"
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
- driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
+ driven_by :selenium, using: :headless_chrome, screen_size: [1400, 1400]
end
The next step is to provide your flyctl access token to Github as a secret.
Start by running the following command:
flyctl auth token
Now you have a token you need to make it available to GitHub Actions that run against your repository. For that, there’s secrets in the repository’s settings. GitHub provides four combinations: Environment and Repository, and Secrets and Variables. Click on the green “New repository secret” button in the top left, pop our secret under the FLY_API_TOKEN
name, and we are ready.
All that is left is for you to commit your changes and…
git push
This is just a taste of what GitHub actions can do for your application.
The one thing we haven’t covered is testing your Dockerfile itself.
While this can be done using docker/setup-buildx-action@v2
, health checks already do this and more.