Continuous Integration

Continuous Integration

What is Continuous Integration?

There are a number of ways to do CI. If you don’t have a server, and you’re happy for your project to be hosted remotely on GitHub or on another site, you can use remote services such as TravisCI, CircleCI and GitLab. If you have your own server, and you need everything to be private (sometimes this is the case if you’re working on academic work with industry partners), then there are services you can host locally such as Jenkins and Buildbot.

TravisCI

We’ll here pick this, as it’s easy to set up from what we’ve already done:

First, log in to Travis CI with your GitHub account.

Now, to build our repository, we’ll need to put a very simple Travis configuration file into the root of the Git repository. Create a file called ‘.travis.yml’. This is written in a markup language called YAML, but the syntax for this is very simple.

Travis comes preinstalled with many programming languages, but uses an older version of Ubuntu. Because we have used Docker throughout to run our software, however, we can just use this as the basis on Travis to run our software. We need to specify only a few options, and everything is set up for us:

sudo: required

services:
  - docker

These options just tell travis that root permissions are needed (a requirement for Docker itself), and we need Docker to be installed.

When Travis builds first start, they clone the latest commit from the Git repository, and then change directory into that folder. So from then on, you can write out commands referring to files in that folder.

So now, we want to get the right environment to run our tests. Let’s build the Docker container from the Dockerfile in our repository. Add the following lines.

before_install:
  - docker build . -t build

The before_install section here tells Travis to run the bash command on the subsequent line. This is normally where you run any setup which is needed to run the tests.

Now, we’ve done everything we need to do before running the tests, so let’s put in the command to run them. We do this in a ‘script’ block:

script:
  - docker run -v`pwd`:/io build pytest -v .

The total file should now look like:

sudo: required

services:
  - docker

before_install:
  - docker build . -t build

script:
  - docker run -v`pwd`:/io build pytest -v .

Stage this file in your Git repository and commit it. Push it to GitHub, then navigate to the Travis website again. You should now see that your repository has appeared, and that a build is in progress. If everything is correct, your Python tests should run remotely!

Clearly, we could have much more complex build processes than this, and you run Python inside the build environment rather than in a Docker container. However, it’s in general a good idea to delegate these into a container, as it avoids you having to duplicate the install script in multiple places, and keeps the development environment where you work the same as the test environment.

Writing a README file

One common thing to do is to add a readme file to a GitHub repository. Create a Generally these just give some information for people who come across the project, such as install instructions. These files are typically written in Markdown - a simple syntax which is widely used online in forums and in many other places. A simple README.md, written in Markdown, for this project could be:

# Functions

![Travis Build Status](https://travis-ci.com/rpep/mytestrepo.svg?branch=master)

Writing a simple package. This repository follows the material on https://scientific-programming.github.io
to create a repository with simple Python tests and Continuous Integration set up.

The URL here points to my repository on Travis; replace it with the one from yours. You can find this by clicking the following when you are on a repository page on Travis.

Workflow

A normal workflow for continuous integration is often something like:

It can also be useful to set up tests to run at periodic intervals - i.e. nightly. This means that if a dependency unexpectedly changes in a repository that you’re using, it is picked up as early as possible.