Staged builds with CruiseControl
In his seminal article on Continuous Integration, Martin Fowler covers the practice of “staged builds” when discussing fast builds. He addresses what he calls “commit builds” and “secondary builds”. I like to think of them as lightweight builds and heavyweight builds. In any case, the purpose in having two different types of builds run from your Continuous Integration server is so that your primary (commit) build is super fast to provide rapid feedback. In particular, some teams will not move on to their next task until their integration build is successful, so if they must wait more than say 10 minutes or so (impatient, aren’t we
), they’ll get discouraged with the build process “taking too long”.
In Extreme Programming Explained, Second Edition, Kent Beck recommends that (integration) builds take no longer than 10 minutes to execute. This can be difficult if you are running your compilation, unit tests, component tests (that rely on a database), system tests, and functional or acceptance tests, a host of automated inspections and web deployments with every build. By segmenting your integration builds, you can use your commit build to run your compilation, execute unit tests (that don’t have heavy external dependencies) and perform a deployment. Then, your secondary build can run your component and system tests that have heavier dependencies along with inspections tools such as code coverage, coding standard checks, and so on. Typically, you want to use your commit build success as an indicator to move on to your next development task, while your secondary build is running.
Let’s look at an example in CruiseControl. I’ll use my brewery example. I create two CruiseControl projects in the config.xml. The first is named brewery-commit and the second is named brewery-secondary. The brewery-commit project uses the modification set to poll the mainline of my Subversion repository like so:
<project name="brewery-commit">
...
<modificationset quietperiod="120">
<svn RepositoryLocation="http://build.integratebutton.com/svn-repo/main/brewery/trunk"
username="patrick.henry"
password="L!berty"/>
</modificationset>
...
Note how the commit build is polling the repository for the latest commit to Subversion. Now, let’s see the secondary build:
<project name="brewery-secondary">
...
<modificationset quietperiod="120">
<buildstatus logdir="logs/brewery-commit" />
</modificationset>
...
Instead of monitoring the Subversion repository, it looks for a successful build in the brewery-commit CruiseControl project using the buildstatus element. Essentially, you are establishing a project dependency. The other trick is that you must call a different delegating build. For instance, the brewery-secondary project will call a delegating build called build-brewery-secondary.xml which calls the same project build file, but a different target. This target is responsible for executing the longer-running tests and the inspections. Make sense?

August 1st, 2008 at 4:58 am
Thank you for the dependency-tip. We will try this, too. Small hint: As Subversion uses atomic commits, the quietperiod should be set to 0 as supposed by the cruisecontrol manual.
Best regards,
Timo