DEV Community

Cover image for A Rails and PostgreSQL setup for GitHub actions (CI)
Vincent Voyer
Vincent Voyer

Posted on • Edited on

A Rails and PostgreSQL setup for GitHub actions (CI)

Since the release of GitHub actions I always wanted to setup a continuous integration using GitHub actions as described in their documentation.

Why even use GitHub actions? πŸ‘‰ The less tools I have to use to do the job (coding), the better. So if GitHub is now providing a way to not have to use external tools like Travis CI or CircleCI then I am happy with it. And later on if GitHub also starts providing cloud services, and they are good, I'll just use that too.

Table of contents:

Requirements

I currently work on a Rails 6 application using PostgreSQL so I needed a workflow that would allow me to build and test a Rails 6 application using GitHub actions. Since actions are a recent feature (released publicly on August 8, 2019), it took me a bit more time than usual to have it working completely.

I like reproducible environments and so I needed a workflow that would:

  1. Install the ruby version specified in .ruby-version, along with Bundler
  2. Install the Node.js version (for webpacker) specified in .nvmrc along with Yarn
  3. Easily allow me to have a PostgreSQL database
  4. Cache steps as much as possible (node_modules, bundler) so that I have a fast build

Full workflow example

GitHub workflows are a set of GitHub actions and are stored in your code, inside the .github/workflows directory. GitHub actions can either be from the official GitHub actions or from their actions marketplace.

The first step to testing your Rails application with GitHub actions is to create a file at .github/workflows/test.yml and paste in it the content of this gist:

.github/workflows/test.yml:

Then commit and push, here's the result:

GitHub workflow example running

Optional step: secrets as environment variables

If you are using Rails credentials then you need the content of the file master.key as a GitHub secret named RAILS_MASTER_KEY. To create secrets in GitHub, just go in your repository settings in the secret tab.

Then if you look at the previous gist, you'll see this:

      - name: Rails test
        env: # Or as an environment variable
          RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}

Which will add the RAILS_MASTER_KEY environment variable for your Rails application to decrypt Rails credentials.

GitHub secrets example

Opinions and current issues with GitHub actions

While I enjoy the fact of having a continuous integration system that is builtin into GitHub, since GitHub actions are so new, they lack the attention to detail and experience of other tools for now. I will list the main ones from my point of view and I advise you to follow their associated GitHub issues if any, if you want to follow their progress:

engines support #94

sakulstra avatar
sakulstra commented on Dec 12, 2019

Hello, It would be great if setup-node would automatically pick the correct version specified in our package.json engines property.

We're using github actions for 7 packages now and while all have an .nvmrc & specified engines still have to use the workaround provided in: https://github.com/actions/setup-node/issues/32#issuecomment-525791142

Related to: #32, #26

Support .nvmrc #32

It would be nice if setup-node understood an .nvmrc file (even if it does not use nvm under the hood, the idea is the node-version is just the contents of the file).

If GitHub Actions as a whole could read the contents of a file as part of an expression, I could do something like

uses: setup-node@v1
with:
  node-version: {{ contents(.nvmrc) }}

But I don't know where to log that type of feature request!

Perhaps '.nvmrc' could be used as a special placeholder, so that:

uses: setup-node@v1
with:
  node-version: '.nvmrc'

Instructs this action to read the contents and treat the contents as the desired version?

Support .ruby-version #31

Many ruby projects include a .ruby-version file in the root directory, containing the version of Ruby needed.

Tools such as rvm, rbenv and chruby all recognise and use this file.

This is not unlike the .nvmrc file often used in Node projects, and the setup-node action has a discussion on potentially using the contents of that file as the node version if no with: argument is specified. (https://github.com/actions/setup-node/issues/32)

I would suggest that setup-ruby might consider a similar approach, where if no explicit ruby version is given, look for a .ruby-version file and use the version contained within.

  • For some libraries, like ged/ruby-pg you have to apt-get install the libpq-dev package while this should be a default.

Add libpq-dev #12

swanson avatar
swanson commented on Oct 03, 2019

Tool information

  • Tool name: libpq-dev
  • Add or update? add
  • Desired version: whatever is latest
  • Approximate size:
  • If this is an add request:
    • Brief description of tool: libpq-dev is a C library for interfacing with Postgres; it is commonly needed for Ruby/Rails environments that create and interact with a database as part of test suites
    • URL for tool's homepage: https://www.postgresql.org/docs/9.5/libpq.html

Virtual environments affected

  • [ ] macOS 10.14
  • [x] Ubuntu 16.04 LTS
  • [x] Ubuntu 18.04 LTS
  • [ ] Windows Server 2016 R2
  • [ ] Windows Server 2019

Can this tool be installed during the build? Current workaround is to install manually via apt-get -- this adds 1-2 minutes to the workflow time and has to be repeated for every build

  • Actions are versionned but it would be great if there was a way to be notified of new versions easily. Or even better, to have GitHub bots opening pull requests to upgrade the versions of the actions. So that you always have the latest features available
  • no way to manually trigger workflows

πŸ”š That's it!

πŸ™ Thank you for reading.

Thanks to Benoit Daloze and Masatoshi Iwasaki for their help on Ruby and Bundler setup in GitHub workflows.

Did you enjoy this post? Any advice as for GitHub actions and Rails configuration? Add your thank you note or advice in the comments and I'll reply :)

Click below to share this post:

Cat says: ACTION!

Top comments (15)

Collapse
 
tubbo profile image
Tom Scott

no support for docker-compose

Docker Compose is definitely installed on GitHub actions, not sure what you mean by "no support".

Here's the Workflow that uses make tasks to run the docker-compose commands: github.com/weathermen/soundstorm/b...

And the Makefile, which runs them: github.com/weathermen/soundstorm/b...

Collapse
 
vvo profile image
Vincent Voyer

Thanks for that! I just removed that part. I tried to use it though and ran into issues mostly because my setup is not fully docker-compose based. I use docker-compose only for services, my Rails code runs in the ubuntu container from GitHub.

So the issue I get is this one:

initialize': Permission denied @ dir_initialize - /home/runner/work/project/project/postgres-data (Errno::EACCES)

My docker-compose.yml:

version: "3.7"
services:
  db:
    image: postgres:11.6-alpine
    ports:
      - "54320:5432"
    environment:
      POSTGRES_PASSWORD: turnshift
    volumes:
      - ./postgres-data:/var/lib/postgresql/data

The volume is mounted with a user/permission that is different from the one used when I run the rails test command. I tried to work around that without luck, if you have any idea let me know. From what I can tell I think your whole infra runs in a docker container while me I always run Ruby/Rails locally and only use compose for services (good or bad that's how I do it for now).

Thanks again!

Collapse
 
sabderemane profile image
Sarah Abd

Hi, I've found tricky solution for the manual trigger and also others completed my answer on stack overflow: stackoverflow.com/questions/589331...

Collapse
 
vvo profile image
Vincent Voyer • Edited

Oh wow that's very clever, and I read also the comment on SO from someone saying you could also limit that to the repository owner.

Do you know what it would take to update my current gist to allow for the repository owner, when they star the repo, to trigger a build?

Right now I have:

name: Test

on: [push]

jobs:

what do I need to change? I am new to the syntax :D

Collapse
 
sabderemane profile image
Sarah Abd • Edited

Alright, you can try this :

name: Test

on:
  watch
    types: [started]

jobs:
  build:
    runs-on: ubuntu-latest

    if: github.actor == github.event.repository.owner.login

    steps:
       - name: Checkout repository
         uses: actions/checkout@v2
        #  add more ...

Notice you may have to reindent but I hope it would be fine :)

Thread Thread
 
vvo profile image
Vincent Voyer

Thanks, I guess the last step is on how to combine what you propose with an already in place workflow that gets executed at push time.

For now I have:

name: Test

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
[...]

But if I change that to what you propose then my workflow is no more executed at push time.

Do you know if we can combine both manual trigger trick + usual push testing in a single or a combination of workflows maybe? Let me know!

Thread Thread
 
sabderemane profile image
Sarah Abd

Yes, I set just the beginning but you can adapt it for an existing workflow or a new one.

can combine both manual trigger trick + usual push testing in a single or a combination of workflows

Yes you can !
For your example it will be like that :

on:
  push:
  watch:
    types: [started]

jobs:
  build:
    runs-on: ubuntu-latest

    if: github.actor == github.event.repository.owner.login

    steps:
[...]

I din't try out yet this but I've already tried to setup a workflow with push event and cron, so it should be fine !

Collapse
 
abdellani profile image
Mohamed ABDELLANI • Edited

Hi,

I was working on a very similar article (Actually, I'm not sure that I'll publish it now XD).

In my workflow, I set up two tests. The first one uses Rubocop to do static analysis of the code, and the second one uses RSpec and then generate a report using SimpleCov.
You can check my yaml file here

I also noticed another issue when I was trying to use environment variable to specify the version of the operating system that will be used for the tests.

Great job, thanks for sharing.

Collapse
 
vvo profile image
Vincent Voyer

Hey there, thanks for the comment. Indeed I haven't yet setup multiple steps with dependencies in my setup. I might have to and your example will be very useful, thanks!

Collapse
 
ndrean profile image
NDREAN

Nice posts!. Don't you have in your bag a tuto on how to setup correctly a dockerized React + Rails API using Sidekiq/Redis? As a newbie, developing an app is not so difficult, but deploying it, env variables, the database config.. all these kind of things is a real nightmare.

Collapse
 
vvo profile image
Vincent Voyer

Hey there, sorry I do not have that (also, I stopped my Rails learning and went back to Node.js!).

Good luck though, thanks for your comment

Collapse
 
s4na profile image
s4na

So helpful! Thank you!

Collapse
 
leesmith profile image
Lee Smith 🍻

Awesome guide! Thanks so much!

Collapse
 
unkrass profile image
Unkrass

Do you have any experience with using environment credentials in Github actions? Or should the master.key override the test.key anyway?

Collapse
 
vvo profile image
Vincent Voyer

I have no experience but this post: stackoverflow.com/questions/614445... suggest using a test key and uploading it to GitHub I guess