Python, Django and GitHub CI/CD

A demo CI/CD pipeline using Python Django and Pytest

Gabi Cavalcante
3 min readSep 30, 2019

GitHub Actions was introduced last year, and it’s an API for cause and effect on GitHub. You can orchestrate any workflow, based on any event, you can have your workflow run on push events to master and release branches, or only run on pull_request events that target the master branch, or run every day of the week at Friday 02:00. The workflows are code in a repository, as you will see in this project, so you can create, share, reuse, and fork.

I’m working in a Django project and when I started I found a problem: there was not CI/CD working or integration/unit test. In the past I used the GitLab CI/CD, but now the code was hosted on GitHub. So, my challenge was create tests to my Django project (it was implemented before I got the job) and create CI/CD pipeline for integrating it with GitHub CI/CD. For this tutorial, the application that I’m gonna show you, demonstrates CRUD operations using class based views in Django (you can find here). It also includes UI for all CRUD views and it’s based on the semaphoreci.com tutorial.

Local project setup

  1. You can use virtualenv for setting up this project.
$ virtualenv -p python3 env

2. Download the project

$ git clone https://github.com/gabicavalcante/django-test-ci.git

3. Install pip requirements

$ pip install -r requirements.txt
  1. Create a new psql database
postgres=# create database pydjango;

3. Setup your database credentials and SITE_URL in settings.py file available inside core folder.

4. Once you have setup your database, open command prompt and run the migrate command to create the application default database and the superuser.

(env) $ python manage.py migrate(env) $ python manage.py createsuperuser

5. Once all of the above command run successfully, let’s run:

(env) $ python manage.py runserver

6. And visit the web browser with http://127.0.0.1:8000

Environment variables

The following environment variables can be set to override defaults:

  • SECRET_KEY: Django secret key.
  • DB_ENGINE: Django database backend.
  • DB_NAME: database name.
  • DB_HOST: database hostname.
  • DB_PORT: database port.
  • DB_USER: database user.
  • DB_PASSWORD: database password.

Test with PyTest

To tell pytest witch Django settings that should be used for tests runs, we need to setup a pytest configuration file, called pytest.ini in our project root directory. The file contains:

[pytest]
DJANGO_SETTINGS_MODULE=core.test_settings
addopts = --nomigrations --cov=. --cov-report=html

To run the tests, we can invoke directly pytest command instead of manage.py test. The pytest-django is designed to run with the pytest command, but in case of you want to use manage.py test with pytest-django, you can create a simple test runner.

CI/CD GIthub

The example pipeline contains 3 blocks:

Install Dependencies

Installs pip requirements

Run Code Analysis

Run code analysis / code linting with Pylint

Run Unit Tests

Runs Unit Tests with pytest module for views and models file

Control when your workflows are triggered

Some time we don’t want workflows run on every push to every branch in the repo. So, we can have our workflow run on push events to master and release branches:

on:
push:
branches:
- master
- release/*

or only run on pull_request events that target the master branch:

on:
pull_request:
branches:
- master

or, run every Friday at 02:00:

on:
schedule:
- cron: 0 2 * * 5

For more information see Events that trigger workflows and Workflow syntax for GitHub Actions.

Run your jobs on different operating systems

GitHub actions provides hosted runners for Linux, Windows and macOS. To change the operating system for you job simply specify a different virtual machine:

runs-on: ubuntu-latest

For more information see Virtual environments for GitHub Actions.

Conditionally run steps or jobs

GitHub Actions supports conditions on steps and jobs based data present in your workflow context. To run a step only as part of a push and not in a pull_request you simply specify a condition in the if: property based on the event name:

steps:
- run: npm publish ..
if: github.event == 'push'

For more information on the expression language see Workflow syntax for GitHub Actions.

Use an action

Actions are reusable units of work that can be built and distributed by anyone on GitHub. You can find a wide varity of actions in the GitHub marketplace. Actions are referenced by specifying the repo that contains the action and the ref that you want to use.

- name: < display name for action >
uses: {owner}/{repo}@ref
with:
<map of inputs>

--

--

Gabi Cavalcante

Dev Python, curiosa, nordestina, feminista e completamente apaixonada por tecnologia de impacto social.