C.I. with Github Actions- 6 mins
Continuous Integration is key in the delivery of any software. Now, “continuous integration” has had many definitions over the years. Some say it has to do with bringing code from different branches, “integrating” them into a delivery beanch. Some day it’s the introduction of automated tests into your pipeline. Others, as primitive as me, say it’s CircleCI and TrravisCI. Wherever you fall on this spectrum, you may have the belief that continuous integration makes it easier to ship code.
There are many continuous integration tools. Most of these tools handle running tests for a particular changeset of your sourcecode. This helps you validate that the new changeset both meets its requirements (written in tests) and does not break the hitherto realized requirements of the system. Previously, I have depended on CircleCI to get this done. But with the recent Github Actions, one could do anything which could be done with a repo based on some Github events like push, and pull-request. With this new capability, I sought to wean myself from CircleCI and other CI pipelines. Since code is hosted on GitHub, I thought it best to localize the delivery of the code on Github.
- A new Hanami project. Hanami comes with RSpec as a default testing framework.
- Github Actions
This defines the action, and creates a reference through your workflow
name: Run Tha CI
Actions run on specific events in the Github ecosystem. Push and Pull Request are two popular events Actions could be run on. For a more comprehensive list, read Events that trigger workflows
We would want to “Run Tha CI” on every push event.
This list is an array. If you want this workflow to trigger for more than one event, add the event to the array separated by commas. Another way of writing this could be
on: - push
This bit defines the action itself.
Actions is pretty new, and I don’t know my way around it that well yet. But at this point, I like keeping my jobs to just one job in a workflow. It must be possible to have more than one job per workflow.
Here we define the job: giving it a name, and telling it the machine to run on. If you are familiar with Dockerfiles, this is akin to the FROM keyword in a Dockerfile which provides a base for your image to be run on. This “runs-on” attribute defines the machine (or set of machines) your jons would run on.
jobs: run_tha_ci: name: build runs-on: ubuntu-latest
Now we have to define dependent services we would need to run the job. In this case, I need a database to run my tests.
jobs # ... snipped for brevity ... services: database: images: postgres:11.5-alpine env: POSTGRES_USER: runner POSTGRSE_DB: project_test POSTGRES_PASSWORD: '' ports: [5432:5432]
Notice that the PostgreSQL user here is set to
runner. I had originally set this to a random name since I thought the name of the DB user would be irrelevant. While testing, however, I realized Hanami required the DB user be “runner”.
These steps are commands run in your environment to carry out the job.
Here, we would like to
- Checkout the sourcecode
- Setup Ruby with version 2.6.3
- Install dependencies: libraries, and gems
- Setup our database
- Run the specs.
Thankfully, there are some actions which we would need to use over and over again. With Github Actions, you can abstract this into a repository and reference it anytime you need. A good example is the checkout action. This has been abstracted into the actions/checkout repository.
steps: - uses: actions/[email protected] - name: Setup Ruby uses: actions/[email protected] with: ruby-version: 2.6.3 - name: Install Dependencies run: | sudo apt-get update sudo apt-get -yqq install \ postgresql \ postgresql-contrib \ libpq-dev \ chromium-chromedriver gem install bundler bundle install --without development production - name: Setup Database env: HANAMI_ENV: test PGHOST: localhost PGUSER: runner run: | hanami db prepare - name: Run Specs run: bundle exec rspec
Notice two new keywords in this snippet
usesreferences an action in a repository
rundefines commands to run in the box
With the Yaml file below, every push gets run these steps run against the changeset. If any step in your workflow returns with a non-zero code, that step is marked as a failed step. If any steps in your workflow fails, the action “fails”.
With this, we have our continuous integration baked right within Github.
p.s: Getting this up for Rails shouldn’t be much different.
name: Run Tha CI on: [push] jobs: run_tha_ci: name: build runs-on: ubuntu-latest services: database: image: postgres:11.5-alpine env: POSTGRES_USER: runner POSTGRSE_DB: catalyst_test POSTGRES_PASSWORD: "" ports: - 5432:5432 options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - uses: actions/[email protected] - name: Setup Ruby uses: actions/[email protected] with: ruby-version: 2.6.3 - name: Install Dependencies run: | sudo apt-get update sudo apt-get -yqq install \ postgresql \ postgresql-contrib \ libpq-dev \ chromium-chromedriver gem install bundler bundle install --without development production - name: Setup Database env: HANAMI_ENV: test PGHOST: localhost PGUSER: runner run: | hanami db prepare - name: Run Specs run: bundle exec rspec