When working as part of a team, you'll almost certainly want a centralized continuous integration (CI) environment setup. Good solutions exists for that including the many CI-as-a-service offerings (Travis, CircleCI, ...), open source solutions (Jenkins) and proprietary (TeamCity).
However, if you do a lot of work on your own or you want to run CI against your local version control repository, one solution is to run a local installation of a CI server inside a Vagrant VM on your desktop environment.
That's the approach I've taken for CI on the Python and Django projects that I work on. I chose to use Jenkins for the CI server as it's easy to install and well supported with plugins.
Jenkins VM Build
For testing a Django project you'll typically need a Jenkins server with, at a minimum, the following installed:
- Postgres (because we always test against the same database platform as production)
- Python 3 (ok, you may also need Python 2 for old projects)
- Some Jenkins plugins. e.g. git, violations (code quality), cobertura (coverage) and sloccount (lines of code)
Of course we don't want to build our VM by hand because that's tedious. Fortunately we have tools like Ansible that we can use to automate the build and maintenance of the server. Additional, I've created an Ansible configuration for building a Jenkins server that can get you started which includes the base server configuration listed above.
To build a local Jenkins VM, clone or download the GitHub repository where I keep the Ansible playbooks and configurations I use regularly. In the examples directory you'll find the Jenkins example with a README that you can follow to create your Jenkins server.
Jenkins Build Configuration for Django
If all has gone well you should have a Jenkins server running at http://localhost:8888/. It's now time to create a Jenkins project to run builds against your Django project.
I'm not going to give step-by-step instructions on creating a Jenkins project, but below are a few of the key components to a build for a Django project.
Source Code Management
Assuming you want your project to fetch code from a local git repository, you'll need to configure Jenkins in a similar manner to the following.
Here I'm accessing over SSH a git repository on my desktop machine (user@myhost). For this to work, you'll need to setup SSH keys such that the VM can connect to the desktop without a password.
Here's a build step you might use for a Django project structure created with cookiecutter-django. If you use a different project template, you'll need to modify accordingly.
#!/bin/bash # Create a virtualenv virtualenv --python=python3.4 MYAPP # Activate the virtualenv source MYAPP/bin/activate # Install project Python packages pip install -r requirements/local.txt # Setup required environment variables export DJANGO_SETTINGS_MODULE=config.settings.local export DATABASE_URL=postgres://jenkins:jenkins@localhost/jenkins # Apply migrations ./manage.py migrate # Run the django-jenkins management command ./manage.py jenkins --enable-coverage --coverage-rcfile .coveragerc --max-complexity 10 # Delete the virtualenv rm -rf MYAPP
The Django management command 'jenkins' runs tasks to test, lint, establish coverage and perform a code line count. It is provided by the Python package django-jenkins. In your Django project settings (config.settings.local in the above example) you'll need to configure django-jenkins with which of your apps you want tasks applied to and what those tasks are. Here's an example of what those django-jenkins settings might look like for a simple project.
PROJECT_APPS = ( 'myapp.users', 'myapp.blog', 'myapp.events', ) JENKINS_TASKS = ( 'django_jenkins.tasks.run_flake8', 'django_jenkins.tasks.run_sloccount', )
Post Build Actions
You'll need to add some post build actions to generate the reports for the build results. Here are the actions you need to configure based on the example we are describing here.
Unit Test Report
Hopefully, there's enough detail here to save yourself some time getting a Jenkins CI server up and running on a local VM against you Django project.