November 21, 2009

Django continuous integration with Hudson and Nose

At work we’ve decided to use Hudson for our con­tin­u­ous inte­gra­tion server.

I started off using Joe Heck’s great Python and Hudson writeup as a guide.

But to get really good report­ing, includ­ing a cov­er­age report, you’re going to want to use Nose, django-​nose, and my nose-​xcover plugin.

Before you get Hudson up and run­ning, you’ll first want to create a test set­tings module for your appli­ca­tion. Here’s a sample:

With that in place you’ll want to set up a sep­a­rate test require­ments file for pip. If you’re not using pip, I can’t be held respon­si­ble if the cen­tral com­mit­tee gets ahold of you.

Why use my fork of nose? We’ll get to that in a second. First let’s set up our build script.

  1. We change into Hudson work­space set up for this build
  2. Set up a vir­tualenv for our project
  3. Acti­vate it
  4. Install our application’s requirements
  5. Install our application’s test requirements
  6. Assum­ing you have a prop­erly con­structed setup.py, this com­mand will sym­link it into your virtualenv’s site packages
  7. Finally run our tests, using our test settings.

The –with-​coverage option tells nose we want to cap­ture cov­er­age infor­ma­tion. The –cover-​package option tells nose we only want report­ing on our appli­ca­tion. The –with-​xunit option will gen­erte a nosetests.xml file in our work­space with the results of the test run.

Finally, the –with-​cover-​xml option is an option I added to nose’s cov­er­age plugin, and the reason why I’ve got my fork listed in our test-requirements.pip. Finally, the –with-​xcoverage option acti­vates my nose-​xcover plugin. It out­puts an XML cov­er­age report that Hudson can use, and it’ll honor the –cover-​package option you spec­i­fied ear­lier, so your cov­er­age per­cent­age won’t be arti­fi­cially low­ered, or inflated, by third-​party code you use.

Now let’s con­fig­ure Hudson to use the two XML reports we’re generating.

First the test pass/fail report.

Config [Hudson].jpg

And then our cov­er­age report, you’ll need the Cober­tura plugin for this:

Config [Hudson]-1.jpg

That’s right, you’ll also want the Chuck Norris plugin. Why? Because Chuck Norris can divide by zero. That’s why.

Also, I’d highly rec­om­mend the Green balls plugin, because Hudson’s default of blue == pass just doesn’t fly with me, or Chuck.

While we’ve been set­ting up Hudson, I had another build in the oven baking using the recipe above. Let’s see how it turned out:

Dummy [Hudson].jpg

Editor’s note: I updated this post to use my nose-​xcover plugin and not my fork of nose.

Filed under: Django,Programming,Python,Technology

Next:
Previous:

Related

  • http://www.rhonabwy.com/wp/ Joe Heck

    Nice writeup! I’ve been won­der­ing about nose & django together, but hadn’t yet found the django-​nose piece.

    Did you have to do much work on the system host­ing Hudson to enable vir­tualenv? Would love to see/hear what you spe­cific build steps look like for this setup.

  • http://heisel.org Chris

    Joe,

    Didn’t have to do much to get it to use the virtualenv.

    I’m run­ning the tests via a shell job, so all I had to do was create the vir­tualenv and source it.

    This gist http://​gist.​github.​com/​2​40296 is pretty much our build com­mand. Then we have one other build com­mand for pylint using what you had in your tutorial.

  • Stavros

    Hello, I love your guide (and the final result), but I don’t like having to install a fork of offi­cial pack­ages (it’s a bit hard to main­tain). Do you think your changes could ever see their way upstream?

  • http://heisel.org Chris Heisel

    Stavros,

    Thanks! Two thoughts, you can give the folks at Nose a ping, I sent the main­tainer a pull request on Bit­Bucket, but haven’t heard back.

    I’ll also look and see if I can make a plugin that’d do the same thing my patch is doing.

    Chris

  • http://heisel.org Chris

    Stavros,

    Give this plugin I whipped up a try, it should com­pli­ment nose’s built-​in cov­er­age plugin, adding the XML output: nose-​xcover

  • Stavros

    I just tried your plugin, it is much better and I have gotten every­thing work­ing fine (after set­ting up your plugin nose couldn’t find it, but I copied the module man­u­ally in /site-​packages/). The cov­er­age and nosetests xml files are gen­er­ated fine, but for some reason Hudson reports my tests as failed, even though nosetests.xml has failures=”0″…

    I’ll figure it out sooner or later, thanks for grant­ing my request!

  • Stavros

    Hmm, tests pass but Hudson reports a failed build. Could this be because I’m just run­ning man​age.py test?

  • Stavros

    Word to the wise, don’t use the pypi ver­sion of django-​nose, get the one from github.

  • http://jacob.champness@gmail.com jacob

    Hi Chris, First, apolo­gies, I’m a python/django noob. When you say to “create a test set­tings module for your appli­ca­tion,” what exactly does this mean? If I merely parse the state­ment word-​by-​word, given my rudi­men­tary knowl­edge, I take it that I should create a file with a .py exten­sion (i.e. a module) in (one of (or all of?)) the appli­ca­tion direc­to­ries in my django project. Is that cor­rect? If so, does it matter what the module is named? Is some­thing some­where sup­posed to refer to it? Which of my django appli­ca­tions should con­tain it? Where exactly in the dir struc­ture of the appli­ca­tion should it go? Does this assume one Hudson project per django app?

  • http://heisel.org Chris

    Jacob,

    The set­tings module is a reg­u­lar python file that can live any­where on your Python path. It’s doc­u­mented on the “Django Web site”:http://​docs.​djan​go​pro​ject.​com/​e​n​/​1​.​1​/​t​o​p​i​c​s​/​s​e​t​tings/

    Often times folks will have a set­tings module in their project folder, or if you’re build­ing a reusable appli­ca­tion you might have a set­tings file for test­ing inside that application.

    My Hudson con­fig­u­ra­tion doesn’t assume one appli­ca­tion per Hudson project. You could run a large test suite con­tain­ing many appli­ca­tions if you wanted.

  • Jacob

    Thanks!

  • http://www.caktusgroup.com/blog/ Tobias McNulty

    As another resource, Colin, one of the guys I work with, just did a writeup of our Django/Hudson setup here at Caktus:

    http://​www.​cak​tus​group.​com/​b​l​o​g​/​2​0​1​0​/​0​3​/​0​8​/​d​j​a​n​g​o​-​a​n​d​-​h​u​d​s​o​n​-​c​i​-​day-1/

    It walks you through set­ting up a new Hudson instal­la­tion to test a Django project – hope some­one finds it useful!

  • Tim

    Really good post but:

    “Assuming you have a prop­erly con­structed setup.py” – No I don’t, any point­ers to what is a proper setup.py for a Django app?

  • James English

    I wonder if you could help me out, I am trying to get this to work but I am run­ning into a lot of problems

    So when hudson runs my build script (which is exactly the same as your except I renamed ve to trunk) I get: /var/lib/hudson/jobs/dummy/workspace/trunk/build-settings.sh: 3: source: not found

    Then when it tries to run: pip install -E ./trunk -r requirements.pip

    I get: IOEr­ror: [Errno 2] No such file or direc­tory: ‘requirements.pip’

    Then I get some more errors, but those are the first 2 so I fig­ured they prob­a­bly impact the rest of the errors.

    Some help is greatly appre­ci­ated, I can’t figure out why source won’t work in the shell script. I’ve gone to the $WORK­SPACE direc­tory myself and run the shell script and it has worked fine!

    I even tried past­ing the shell script into hudson and still got the same source not found error.

  • James English

    I answered my own ques­tion. I had to go into the hudson set­tings and set “shell executable” to “bash” for some reason it wasn’t using the bash shell

  • http://twitter.com/c089 Christoph Neuroth

    Hey, greate writeup! I have one prob­lem with the cober­tura plugin in a python project with nosetests: It seems to ignore files which are not tested at all, so I have 100% cov­er­age on classes, files and con­di­tion­als (which, unfor­tu­nately, is just not ture ;)). Do you have any ideas what could be caus­ing this?

  • Daniel Watkins

    –cover-​inclusive