Setting up CI on Hudson for Python based AppEngine apps

This post describes how I for JS-Analytics use a Hudson build server for Continues Integration, publishing to Google AppEngine on successful builds.

The build currently does just two things:

  • It runs all my unit-tests and calculate code coverage on them. This step is to ensure that the application isn’t broken before the second step is executed.
  • It publishes the latest changes to Google AppEngine

Running the unit tests


This is a straight forward execution of my unit tests. With some assisting tools. I use XML-runner to generate xml reports that Hudson can read to produce some nice output, and I use Coverage to calculate the metrics.

To get coverage to run I had to install it manually for python2.5. To run the coverage tool I run the following build step.

#!/bin/bash -ex cd jsAnalytics coverage run test coverage xml --omit=/usr/

It calculates the code covered during the test-run and omits the result as XML.

I then have the following setting set in the build to publish the results:




Publishing to AppEngine

#!/bin/bash -ex rm ~/.appcfg_cookies cd jsAnalytics echo <password> | python2.5 .google_appengine/ -e <user email> --passin update .

The above snippet first removes the appcfg_cookies from the user directory. This is to allow builds the publish to different AppEngine projects to run on the same Hudson installation, and can be omitted if you wish.

The snippet then executes the update command with a user and passes a password. The user for me is a special Google Apps account created for publishing to AppEngine.

What the build gives me

Basically I’m just looking at two trends, I want the amount of tests to increase and I monitor the coverage to ensure I’ve not added something without tests. The only problem right now is that the code coverage report is somewhat tainted with the app_engine helper files. Something I’m not too fond of.

That and the added value that my check-ins are continually evaluated, and the next version is always available on AppEngine.