Python, Django and GitHub CI/CD
A demo CI/CD pipeline using Python Django and Pytest
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
- 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
- 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>