Recent entries
Recent Comments

Julian Simpson

Configuring CruiseControl the CruiseControl way

You just started using CruiseControl. You use a Version Control System to manage your code. You installed CruiseControl on a spare computer in the office; now it is giving you immediate feedback on the changes that occur in that codebase. Life is good. Then the disk on that spare computer fails, and your build server resumes its previous role as a doorstop.

"No problem". you think: "All the code changes are in the VCS. We can regenerate any of the artifacts that we need to. In fact, all we need is the config file ... ". Yes. That config file. The config file on the hard disk that doesn't work anymore. This post will outline how to manage your configuration for CruiseControl without fear of losing it. Like many tools, CruiseControl becomes useless without configuration.

In previous ThoughtWorks projects, we always needed to allow someone to have access to the build server to make configuration changes for CruiseControl. Once projects grow past a few developers, it becomes hard to have everyone be familiar with the installation. Typically we end up with one person (sometimes your humble narrator) becoming the dedicated CruiseControl administrator for the project. This change creates a bottleneck in the team because all the changes to CruiseControl then become funnelled through that one person.

The first step in mending this situation is getting CruiseControl to apply its own configuration. Let's get started. In addition to the projects that build and test your code, you will need a new project to apply the configuration to the server. We have been doing this to put the configuration file in the right place, using CruiseControl's <bootstrapper> plug-in to update the configuration files when they change:

<?xml version="1.0"?>

<cruisecontrol>

    <project name="config">

<labelincrementer defaultLabel="${project.name}-1" 
separator="-"/>

        <listeners>
            <currentbuildstatuslistener 
file="/var/spool/cruisecontrol/logs/${project.name}/
currentbuildstatus.txt"/>
        </listeners>
   
        <bootstrappers>
<svnbootstrapper localWorkingCopy="/etc/cruisecontrol"/>
        </bootstrappers>

        <modificationset quietperiod="30">
            <svn LocalWorkingCopy="/etc/cruisecontrol"/>
        </modificationset>

        <schedule interval="60">
            <ant antWorkingDir="/etc/cruisecontrol"
antscript="/var/spool/cruisecontrol/tools/apache-ant-1.6.5
/bin/ant"
                 uselogger="true"/>
        </schedule>

        <publishers>
            <artifactspublisher
                file="${project.name}/build.log"
                dest="logs/${project.name}"
            />
        </publishers>
    </project>
</cruisecontrol>

This will robotically update the configuration until the end of time. It's simple but surprisingly effective. There's no longer a dependency on the person who can make changes to CruiseControl. Suddenly they don't need to make the trivial changes on behalf of the rest of the team because anybody can safely change the configuration. If someone does check in a broken configuration, it's all under version control. Once you revert the change you can find the person who changed it and try and understand what they wanted to do.

This is a big step forward. But if you check in a broken configuration it will still be applied to CruiseControl. Fortunately CruiseControl has the good sense not to apply broken configuration; but you're missing a vital piece of feedback, and for that you need to write a simple validator like this one:

package org.juliansimpson;

import java.io.File;

import net.sourceforge.cruisecontrol.CruiseControlException;
import net.sourceforge.cruisecontrol.config.XMLConfigManager;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;

public class ConfigValidator extends Task {
	public String configFile;

	public void execute() throws BuildException {
		try {
			File file = new File(configFile);
			new XMLConfigManager(file);
		} catch (CruiseControlException e) {
throw new BuildException("Invalid CruiseControl Config");
		} 
	}
	
	public void setConfigFile(String config) {
		configFile = config;
	}

}

The validator uses internal classes of CruiseControl itself to validate the configuration. Ideally we would have an external interface to do this - perhaps a command line option or an "official" Ant task. I've asked the CruiseControl Enterprise team to look at this for future releases. This approach does mean that you need to set the classpath so that the validator can find your CruiseControl install, but this way you find out with certainty that the configuration is valid for your version of CruiseControl. I like to run these as an Ant task. It's very simple and easy for everyone to see what it does. Here's how I included it in a simple Ant build:

<project name="cruisevalidator" default="publish" >

	<import file="build-library.xml"/>    
    
<target name="validated-config" depends="cruise-validator.jar">
<taskdef name="validate" 
classname="org.juliansimpson.ConfigValidator" 
classpathref="main"/>
        <echo message="validating ${config}" />
        <validate configFile="${config}" />
    </target>
    
<target name="publish" depends="validated-config">
<echo level="info" 
message="copying CruiseControl config to server" />
<copy file="${config}" todir="${cruisecontrol.dir}" 
failonerror="true" 
description="Copy configuration to CruiseControl server" />
<echo level="info" 
message="forcing a reload of config on server" />
<get src="http://localhost:8000/invoke?operation=
reloadConfigFile
&amp;objectname=CruiseControl+Manager%3Aid%3Dunique"
        	dest="${build.dir}/reload.html" />
    </target>
    
</project>

It all works together like this: The CruiseControl BootStrapper fetches us the latest CruiseControl configuration, but in isolation from CruiseControl install - you still don't know if it is a valid configuration file yet. The "validated-config" target calls the ConfigValidator Ant task. This invokes enough of CruiseControl to make sure that the configuration is legal, and that some of the directories referred to in the configuration exist. If that passes, the "publish" target copies the configuration to the CruiseControl server itself. Finally the same target forces a reload of the CruiseControl configuration using a simple HTTP request to the JMX interface. This ensures that the configuration is reloaded immediately, so that the team knows the configuration is valid. Thanks to my colleague Tim Brown for this great idea.

Summary: I have to admit being careless sometimes with XML configuration files. This approach works particularly well for me because I have the safety net of the validation. I do a similar thing with my email and web server installation as well, which I hope to write about soon. The validator code and build files are available on my website at http://www.juliansimpson.org/.

©Julian Simpson 2007. All rights reserved.

Tags :

Comments > (HTML is allowed)

  1. Nicolás Cornaglia
    November 21st, 2007 @ 02:16 PM

    Nice touch. I never thought about config files...

  2. David Pattinson
    December 6th, 2007 @ 11:37 AM

    It's nice to be able to test that config file before you check it in too, in cases where you're trying to do something tricky and/or the build time is long. In that case it can help to extract environment specific parameters (for example the spam list for breakages, or the database schema name) into a properties file that you merge into the config as part of pushing it onto the target environment. This way you can have a seperate set of properties for testing your config file on a local box, and run less risk of accidentally breaking the build.

  3. John
    May 21st, 2008 @ 06:54 AM

    I implemented this but was frustrated to find how strict the validation rules were. I have "<svnbootstrapper />" in my project. This is causing a validation error to be thrown: "Error validating cruisecontrol config: 'localWorkingCopy' must be an existing directory." I guess i could rename my project to better coincide with the expected output, or create dummy directories (very ugly). how would you propose getting around this? I also have <svn /> and suspect this will be a problem as well.

  4. Julian Simpson
    May 22nd, 2008 @ 07:48 PM

    John, Can you email me some more of the output please? medic (at) build-doctor {dot} com Thanks. Best Julian.

  5. Ajay
    June 3rd, 2008 @ 05:29 AM

    Hi Julian This is really great idea. I have a question regarding setting the desired directories only in the config file , so that any change in this directory doesnt kick thebuild process .. say for example ..i have specified in the config file as any change under /LTP project ..kicks in build process but now i decide there is a directory with docs and if anything changes there the build shouldnt kick in ..is it possible to exclude dirs and the build doesnt kick in ? thanks

  6. Julian Simpson
    June 3rd, 2008 @ 01:37 PM

    Hi Ajay, You could specify multiple entries in the modification set: http://cruisecontrol.sourceforge.net/main/configxml.html#svn Mail me at the email address above your post if you want to go into more detail on this. Cheers Julian.

  7. mathias hannus
    September 15th, 2008 @ 05:28 PM

    Thanks for the great article. I have a cruisecontrol config with included project files (<include>. For some reason the xml validation doesn't cover the included files. Do you have any advice how to get the validation executed for them as well as the main configuration file?

Sorry, comments are closed for this article.


Products  |  Customers  |  Contact Us
Copyright 2008 ThoughtWorks, Inc.