Continuous integration/Tutorials/Test your python
This tutorial is aimed at getting Jenkins jobs to be triggered for your python project. We will cover steps that needs to be done in your code repository and how to have jobs added and triggered by Wikimedia continuous integration platform.
Contents
Design[edit | edit source]
The jobs are meant to be run using tox, a thin wrapper around virtualenv. As a prerequisite you will need a working setup.py to let tox install your python project in an isolated environment. Each environment defined in the tox file can then be defined as a Jenkins job. Whenever a change is proposed in Gerrit, all the defined jobs will be triggered and report back in Gerrit. The jobs are run on labs instance under the integration labs project.
Prerequisites[edit | edit source]
You should have a working setup.py installed and a few tests. What is the point of writing a python module if it can not be installed and lacks even the most basic tests. One can use the python module pbr to easily bootstrap a setup.py.
Matching conventions and adding tox support[edit | edit source]
Your repository should match a bunch of conventions and support tox. Do not be afraid, that is surprisingly very easy to achieve. We will get environments to run the flake8 python linter and nose tests.
Create a configuration file setup.cfg to finely tune the behavior of the utilities:
# configuration section for nose [nosetests] verbosity = 1 detailed-errors = 1 # configuration for flake8 [flake8] # W293: whitespace on blank lines is ok ignore = W293 # Raise the default 79 limit max-line-length = 90 # Ignore some well known paths exclude = .venv,.tox,dist,doc,build,*.egg
List your requirements! Most probably your project will require additional modules. The convention in python world is to list the modules in two files:
- requirements.txt
- for modules needed to execute your software
- test-requirements.txt
- additional dependencies when executing tests
The will be added to tox configuration which invokes 'pip install --pre'.
Then create a tox configuration boilerplate. This is done in a file tox.ini at the root of your repository. We will define two environments: py26 and py27 for tests with python 2.6 and 2.7, then flake8 to run the linting utility.
# Tox configuration [tox] minversion = 1.6 skipsdist = True # List the environment that will be run by default envlist = flake8, py26, py27 [testenv] # Default configuration. py26 and py27 will end up using this setenv = VIRTUAL_ENV={envdir} # Passed to 'pip install --pre', that will install the dependencies listed in those files deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt commands = nosetests # Settings specific to the flake8 environment [testenv:flake8] # The command to run: commands = flake8 # We only need flake8 when linting, we do not care about the project dependencies deps = flake8 [testenv:venv] # Let you pass additional arguments when invoking tox commands = {posargs}
Then you can install tox:
pip install tox
At first list environment triggered by default:
$ tox -l py26 py27 flake8 $
Execute them using tox. If all went well you will seen green success.
You can execute a single environment by passing -e to tox:
$ tox -e flake8 ...
Editing Jenkins configuration[edit | edit source]
Since you have installed Jenkins Job Builder, aim at the configuration directory fetched under config. You will create a job for each tox environment you want triggered using two job templates:
- {name}-tox-{toxenv} python 2.7.3 or 3.2.3 (Ubuntu Precise)
- {name}-tox-{toxenv}-trusty python 2.7.6 or 3.4.0 (Ubuntu Trusty)
The name of the template will be used to forge the name of the Jenkins job. The templates takes two parameters:
- {name} : a prefix representing your project
- {toxenv} : the tox environment you want this job to run
Lets say your project is team/software1 and you want to invoke the tox environments py27, py34 and flake8. Add your project in your team configuration file (team.yaml), set the list of values for toxenv and define the job templates to use:
- project: name: 'team-software1' toxenv: - py27 - py34 - flake8 jobs: - '{name}-tox-{toxenv}' - '{name}-tox-{toxenv}-trusty'
Save the file, you have completed the configuration.
Now run Jenkins jobs builder in testing mode to verify its properly creating the new jobs:
$ mkdir output $ jenkins-jobs test -o output ./config $ ls -1 output/team-software1-tox* output/team-software1-tox-py27 output/team-software1-tox-py27-trusty output/team-software1-tox-py34 output/team-software1-tox-py34-trusty output/team-software1-tox-flake8 $
They are written using the XML format Jenkins use to describe jobs.
You can then git add the modified YAML file and submit it for review and later deployment.
See CI/JJB#Deploy_changes to deploy the change in Jenkins.
Note that team-software1-tox-py34 is not going to work since it is going to run on Ubuntu Precise which does not provide python 3.4. We would simply not trigger it, lets look at how to change Zuul configuration to trigger the proper jobs.
Editing Zuul configuration[edit | edit source]
The configuration is held in integration/zuul-config.git repository which has a single file: layout.yaml.
Under the projects section add an entry for the Gerrit repository name (ex: team/software1). We will want to trigger on patch proposals and when someone vote +2:
- team-software1-tox-py27
- team-software1-tox-py34-trusty
- team-software1-tox-flake8
Which is defined as:
projects: - name: team/software1 test: # reacts on patches proposals - team-software1-tox-py27 - team-software1-tox-py34-trusty - team-software1-tox-flake8 gate-and-submit: # reacts on +2 - team-software1-tox-py27 - team-software1-tox-py34-trusty - team-software1-tox-flake8
Save, commit and propose the patch for review.
Refer to Zuul upstream documentation for layout.yaml for more details.