Using Github Actions to test and build your code

In todays blog post I will show you how to use Github Actions to automate the workflow of your project. Github Actions allows you to run any workflow on any GitHub event, which makes it the perfect CI/CD tool. We will create two workflows today:

You can see github actions in action in my iot-home project repository on Github.

Setting up the project

First off, let’s start with a Dockerfile.

FROM python:3.7
ENV PYTHONUNBUFFERED 1
ARG requirements=requirements/development.txt

RUN mkdir /code
WORKDIR /code

COPY /requirements /code/requirements/
RUN pip install -r $requirements

COPY . /code/

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

It is pretty standard to what you can see in any tutorial. The only difference is the requirements arg. We will use that to switch the files dynamically that should be downloaded by the PIP tool, depending on the flow we want to build (test, build, production, etc.). That’s pretty neat!

Now let’s take care of the requirements files. We won’t do anything fancy. Just simple stuff to run and test a Django Rest Framework API project.

We should of course specify the versions, but at this stage of the project it doesn’t matter that much.

Now the last part - the docker-compose files. We want to specify a file for each of the environments we want to build. For this tutorial we will create two files:

Let’s start with the docker-compose for testing:

version: '3'

services:
    test:
        build:
            context: .
            args:
                requirements: requirements/testing.txt
        environment:
            - DJANGO_SETTINGS_MODULE=iothome.settings.testing
        command: bash -c "
            pytest --cov-config .coveragerc --cov=. && flake8"
        volumes:
            - .:/code
        networks:
            - main

networks:
    main:

We can see some interesting things happening here. First of all, this docker-compose file runs a service called test. On build there is a requirements arg supplied with the directory to our testing pip requirements (just like in the Dockerfile). I specify the django settings module in the ENV values. You can do that, if you have mutliple settings files. The important part is the command entry:

bash -c "pytest --cov-config .coveragerc --cov=. && flake8"

This runs pytests with coverage and flake8.

As for the build docker-compose:

version: '3'

services:
    postgres:
        image: postgres
        environment:
            - POSTGRES_DB=postgres
            - POSTGRES_USER=postgres
            - POSTGRES_PASSWORD=postgres
        networks:
            - main
        ports:
            - "5432:5432"
    web:
        build:
            context: .
            args:
                requirements: requirements/base.txt
        environment:
            - DJANGO_SETTINGS_MODULE=iothome.settings.production
        command: python manage.py runserver 0.0.0.0:8000
        volumes:
            - .:/code
        networks:
            - main
        ports:
            - "8000:8000"
        depends_on:
            - postgres

networks:
    main:

This one is your standard docker-compose for running a Django server instance. We have two services: postgres which supplies the database and web, which is the actual Django server. What interests us here is the requirements argument, as you can see here we have the base.txt file instead. Moreover the command is different, as it runs the server.

Now that we know how these files are setup in our project, let’s move on to Github Actions.

Setting up Github Actions

All your workflow files should be kept in the .github/workflows/ directory placed in the root of your project. A workflow is a configurable automated process made up of one or more jobs. You must create a YAML file to define your workflow configuration. Such files have the following extensions: .yaml or .yml. We will use only a fraction of options in this tutorial, so if you want to learn more, be sure to check the Github Actions documentation.

This will be our testing workflow named test.ci.yml:

name: IoT Home Test

on: [push]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Test Project
        run: docker-compose -f iothome/docker-compose.test.yml run test

Let’s analyze step by step what is happening here.

name: IoT Home Test

This is the name of your workflow. It will appear on your repository Github Actions. You can name it anyway you want, but it’s good to give it a meaningful description of what you are doing. If you omit name, GitHub sets it to the workflow file path relative to the root of the repository.

on: [push]

That describes the trigger for the workflow. In this workflow, we want it to start on any push to the repository, to test whether the tests are fulfilled.

jobs:
  test:
    runs-on: ubuntu-latest

You can specify jobs that the workflow will do. Here we have only one job, named test, which runs on the ubuntu-latest image.

steps:
      - uses: actions/checkout@v2
      - name: Test Project
        run: docker-compose -f iothome/docker-compose.test.yml run test

And finally the steps the job will take. Here we only run the docker-compose file, as we specified all the testing, coverage and flake in our docker-compose.

On to our build.ci.yml file:

name: IoT Home Build

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Build Stack
        run: docker-compose -f iothome/docker-compose.yml up -d

This is the build file. It works similarly to the testing workflow, but with some changes. First of all, we changed the name (well doh!). Secondly, as you can se, we changed the on trigger to push and pull request to the master branch. Finally it runs a different docker-compose file, so as intended.

Summary

In this blog post we described how to setup a Django project to run tests and server through various docker-compose files, with a Dockerfile that reads the requirements dynamically. Then we setup some Github Actions workflows for testing and building. As far as CI/CD goes, the new feature from Github is as good as CircleCI or other providers. Adding this was a huge step for Github users and I think that more and more companies will use this as their base continuous delivery systems.

And here you can see how it looks on Github Actions page:

Github Actions


Tell me what you think!