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:
- A testing workflow that fires up on push to any branch, which runs tests and coverage,
- A build workflow that fires up on push or pull request to master.
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
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.
Django psycopg2-binary djangorestframework
-r base.txt pytest pytest-django pytest-cov flake8-django
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:
docker-compose.ymlfor our build workflow,
docker-compose.test.ymlfor our tests.
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:
.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
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.
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
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
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.
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: