Github Actions with Ruby on Rails

Set up continuous integration with GitHub action for ruby on rails application.

Rohit Lingayat
6 min readMay 10, 2021
Continuous integration with GitHub Actions

Continuous integration(CI) allowed you to test your code automatically whenever there is any commit towards the feature/main branch or any pull request comes in. This is great because sometimes you forgot to run tests cases locally before pushing the changes.

To set up GitHub Actions for our project we’ll need a workflow file. Workflows are made up of one or more jobs and can be scheduled or triggered by an event. The workflow can be used to build, test, package, release, or deploy a project on GitHub. You can read more about GitHub Actions here. In this tutorial, we’re going to use a workflow to merge PR only when all test cases get passed.

To set up a github action workflow, in your project folder create a new directory .github/workflows/. Within the newly created workflows directory create a new workflow file ci.yml .

When you create a YAML file, you will see the default template. To understand the syntax of YAML you can read here. By default, the branch is set to master, which means that any push/pull will execute the job against the master branch.

name: Continuous integrationon:
push:
branches: [master]
pull_request:
branches: [master]

you can configure for multiple branches as well e.g

on:
push:
branches: [master, develop, staging]
pull_request:
branches: [master, develop, staging]

if you remember we are targeting if all the test cases get passed then the only PR should get merge, for this, we need to set up a test environment to execute the test case in the container. To do so we need to set up some services before executing the test cases i.e Postgres database. To get more details about the Postgresql container you can read it here

services:
postgres:
image: postgres:11
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports: ['5432:5432']
options:
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5

Now your database container is ready to use, now to execute your test cases we need to prepare a ruby container

Setup the version of Ruby

steps:
- uses: actions/checkout@v2
- name: Setup Ruby
uses: actions/setup-ruby@v1
with:
ruby-version: 2.6.7

in this workflow we are targeting the ruby version 2.6.7 . If you target other versions of ruby and those versions are not available then you need to prepare your own container. We will see in our next blog how to set up the custom ruby container.

Setup the test env and execute the test case

Now all the required services are set up and ready to use. To do so we need to add one more step to execute the test cases

- name: Build and run test
run: |
sudo apt-get -yqq install libpq-dev
gem install bundler:1.17.3
bundle install --jobs 4 --retry 3
bundle exec rails db:create
bundle exec rails db:migrate
RAILS_ENV=test bundle exec rake

there are a few dependence which we need to execute before the RAILS_ENV=test bundle exec rake .

now we have workflow is ready with us

name: Continuse integrationon:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
test:
runs-on: ubuntu-latest

services:
postgres:
image: postgres:11
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports: ['5432:5432']
options:
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v2
- name: Setup Ruby
uses: actions/setup-ruby@v1
with:
ruby-version: 2.6.7
- name: Build and run test
run: |
sudo apt-get -yqq install libpq-dev
gem install bundler:1.17.3
bundle install --jobs 4 --retry 3
bundle exec rails db:create
bundle exec rails db:migrate
RAILS_ENV=test bundle exec rake

when the workflow is executed and according to the current code it will through an error, lets understand why it is not executed.

Github Action build

this error occurs because when we execute the rake db:create it tries to connect with the Postgres and to connect Postgres service is expecting a password which we are not set up correctly, to set up this configuration correctly we need to make some configuration changes in your rails application as well as your workflow YAML file.

In the YAML file add evn variables to use the Postgres credentials

- name: Build and run test
env:
DATABASE_URL: postgres://postgres:@localhost:5432/test
RAILS_ENV: test
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
run: |
sudo apt-get -yqq install libpq-dev
gem install bundler:1.17.3
bundle install --jobs 4 --retry 3
bundle exec rails db:create
bundle exec rails db:migrate
RAILS_ENV=test bundle exec rake

Now in your rails application database.yml

default: &default
adapter: postgresql
host: localhost
encoding: unicode
username: <%= ENV["POSTGRES_USER"] %>
password: <%= ENV["POSTGRES_PASSWORD"] %>
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
timeout: 5000

once you add this you will execute your workflow without any errors. Now your ci.yml will look like this

name: Continuous integrationon:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
test:
runs-on: ubuntu-latest

services:
postgres:
image: postgres:11
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports: ['5432:5432']
options:
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v2
- name: Setup Ruby
uses: actions/setup-ruby@v1
with:
ruby-version: 2.6.7
- name: Build and run test
env:
DATABASE_URL: postgres://postgres:@localhost:5432/test
RAILS_ENV: test
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
run: |
sudo apt-get -yqq install libpq-dev
gem install bundler:1.17.3
bundle install --jobs 4 --retry 3
bundle exec rails db:create
bundle exec rails db:migrate
RAILS_ENV=test bundle exec rake

Our target is that if any pr is raised against any specified branch, then before merging our test caseS should get execute. To do so we need to add a branch protection rule. This protection rule will make sure we can not merge anything into a certain branch unless tests are passing.

To add branch protection rule we need to go settings > branches > add rule

github setting page
Github repository branches

in this setting, we are making sure that our master branch requires status checks to pass before merging. Please see the above screenshot for the configuration.

To test the setting is working properly or not, you can forcefully fail any test case in your rails application by adding a small snippet in one of the test cases. I added into the application_controller_test.rb .

require "test_helper"class ApplicationControllerTest < ActionDispatch::SystemTestCase
test "this test fails" do
raise "this is my failure message"
end
end

Add when you commit this code and raise pr against the master branch, the workflow will execute the job.

Github actions error logs
Github Pull Request

you will be able to see the all checks are failed and say required statues must pass before merging. To fix this issue we need to first fix the broken test case. Below is a screenshot after fix the test cases and job is executed succefully.

GitHub Action successfully

Cheers! 🍻 we successfully implemented the Github action for Rails application. Hope it will help you to quick start with the Github Actions.

References

--

--

Rohit Lingayat
Rohit Lingayat

Written by Rohit Lingayat

Ruby on Rails | React | AWS | Solr | JQuery | Nodejs | Typescript