Craftsmanship

How do I create a Github action to test your app with services?

By 20 November 2020 No Comments

Github Actions what is it?

Github Actions is a continuous integration and automated deployment (CI/CD) solution. It’s an extension of Github. Its operation is based on Github events such as a commits push.

We write a process to start in relation to his project. It will be executed according to the criteria set out in the action to be carried out. This has been designed to perform processes on an ongoing basis based on the collaborative work on Git. You should know that Github Actions is based on Docker, so it is recommended to have some concepts on it to use it quite simply.

Write your action

An action has several elements necessary to complete a process:
the event that corresponds to the Github event: push, pull request etc.

However, for beta only the push and pull request are usable.

on: [push, pull_request]

It is of course possible to define more precisely the framework of your action on certain branches of your repository to perform theaction according to specific cases: perform the action only on the master branch for example.


on: 
  push:
  - master

Then we have the jobs. In practical terms, a job is a series of steps performed in an orderly manner.
It has two important elements: the environment and the steps to be taken.

The runs-on setting defines the environment in which the action is performed:


runs-on: ubuntu-latest

There are several possible virtual environments for the execution of your action, this can be useful for it to match the specifics of each. From the latest Ubuntu to Windows 2016,you have a choice 😉

It should be noted that each job is performed in a new instance of the virtual environment.

So if you want to do a series of actions with a link between them, you will have to think about doing it in the same job.

But it is possible to make job dependencies with the need setting:


jobs:
 job1:
 job2:
  need: job1

In this case, job2 will only run once job1 has been completed.

Then we have all the steps to take in the process. With a view to continuous integration, the goal is to start testing automatically. However, you need to define a number of elements before you can run the tests!

This set is defined by the keyword steps.
Each step requires at least one element to perform, that is, one of its elements:

  • the keyword uses to use a specific item:
    • public action
    • an action in the same repository
    • action on the Docker Hub or on the Docker public register

Yes

  • the keyword run to launch a command in bash (knowing that there are several ways to execute an order if necessary)

Finally, we combine the name setting to find out what step this represents.

An example being more and more telling, so here’s a job to test a Django project:


jobs:
 tests:
  runs-on: ubuntu-latest
 
  steps:
  - uses: actions/[email protected]
  - name: Set up Python 3.5.7
    uses: actions/[email protected]
    with:
     python-version: 3.5.7
  - name: Install dependencies
    run: pip install -r requirements.txt
  - name: Run tests
    run: python manage.py test

Here the job tests consists of:

  • install Python 3.5.7 on the Ubuntu environment
  • install outbuildings
  • start testing

For real-world testing, a database is needed, hence the implementation of services.

Add a service to its action

How do we do that?

Very simple, this is close to the definition of a service in a docker-compose.yml but with much less parameters.

The keyword services are used with:

  • Docker image definition to use
  • the list of ports to be exposed from the service
  • a list of environmental variables
  • a list of volumes

All of these elements are not all required but good to know.
In practical terms, this is similar to this, for a Postgres service:


services:
 image: postgres
 env:
 - POSTGRES_USER: postgres
 - POSTGRES_PASSWORD: postgres
 - POSTGRES_BD: postgres
 ports:
 - 5432/tcp
 options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5

We need the Docker image to launch, the port to be exposed and the name of the service. There is a way to transmit environmental values or Docker options as seen in the example above. Sensitive values can be defined with key secrets.


In addition, it is sometimes necessary to need a return of the service status to establish a connection. Therefore, an element is defined that checks the health of the service to know when it is operational (also called health check). I took the example made by Chris PATTERSON and Mike COUTERMASH for PostgreSQL.

In case you do not have health check available, we pause the execution of the process with the order sleep,yes it’s not terrible, I grant you …

All this is fine, but we have to make the link between the service and our application. We will do this through the port and for the host it will be localhost since the service is run directly in the Ubuntu machine in our example. Otherwise that would have been the name of the service.

In the previous example, a random free port is assigned to the machine’s port 5432 and accessed as follows:

${{ job.services.postgres.ports[5432] }}

Nevertheless, it can be attributed in a fixed way:


ports:
- 5432:5432

Here we have port 5432 of the service related to port 5432 of the machine defined in action.

The following workflow is obtained:


name: Test Workflow

on: push



jobs:
  tests:
    runs-on: ubuntu-latest
 
  services:
   image: postgres
   env:
   - POSTGRES_USER: postgres
   - POSTGRES_PASSWORD: postgres
   - POSTGRES_BD: postgres
   ports:
   - 5432:5432
   options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
  
  steps:
   - uses: actions/[email protected]
   - name: Set up Python 3.5.7
     uses: actions/[email protected]
     with:
      python-version: 3.5.7
    - name: Install dependencies
     run: pip install -r requirements.txt
    - name: Run tests
      run: python manage.py test

It remains to change the values of the service in the settings.py file of Django for the connection to the PostgreSQL database as part of our example.

Then the trick is played, more than pushing code and hoping that everything works 😉

English translation: https://hackernoon.com/how-to-create-github-actions-to-run-tests-with-docker-services-ive-been-digging-github-actions-si-bk1133ye

Learn more about our coaching in development?

Contact us
Sarah

Sarah

Développeuse Fullstack | Devops