I was at CITCON last weekend and someone asked me about managing the CI server configuration files (such as with CruiseControl). I told them that I like to manage my configuration files just like any other software project. The build and CI scripts are not “second-class citizens” when I’m developing software.
First, I create a project in my version control system to manage the files that manage my CI server. Then, I create a project within my CI server to poll for changes against the project in the version control repository. If any changes are found, it retrieves the files and overwrites any relevant files in the CI server directory location (e.g. /opt/cruisecontrol-bin-2.6.2/config.xml).
In this case, you’re using the CI server to look for changes and then overwrite its own configuration files….it reminds me of the ‘Dancin’ with Myself’ song by Billy Idol (1982). The code listing below shows a CruiseControl project called cc-config that polls a Subversion repository which contains CruiseControl configuration files. If changes are detected it calls the delegating build, ${build.config.file}.
...
<project name="cc-config" buildafterfailed="true">
<listeners>
<currentbuildstatuslistener file="logs/${project.name}/status.txt"/>
</listeners>
<modificationset quietperiod="${qp.interval}">
<svn RepositoryLocation="${svn.project.cc-config}"/>
</modificationset>
<schedule interval="${interval}">
<ant anthome="apache-ant-1.6.5" buildfile="${build.config.file}"/>
</schedule>
<log dir="logs/${project.name}" />
</project>
The next code example is the delegating build in Ant. This build cleans any local files and gets the new files from Subversion. Finally, it calls the cc-config project’s build.xml.
<project name="build-cc-config" default="build" basedir="projects/cc-config">
<property file="/opt/cruisecontrol-bin-2.6.2/config.properties" />
<target name="build" depends="clean">
<taskdef resource="svntask.properties" />
<svn>
<checkout url="${svn.project.cc-config}" revision="HEAD" destPath="." />
</svn>
<ant antfile="build.xml" target="all" />
</target>
<target name="clean" description="Deletes all configuration files">
<delete includeemptydirs="true" quiet="true">
<fileset dir="." includes="**/*" />
</delete>
</target>
</project>
The final example is the Ant script that does the actual work, the build.xml. It copies the files retrieved from Subversion and updates these files to the CruiseControl configuration directory, /opt/cruisecontrol/cruisecontrol-bin-2.6.2.
<?xml version="1.0" encoding="iso-8859-1"?>
<project name="cc-build" default="all" basedir=".">
<target name="all">
<copy todir="/opt/cruisecontrol/cruisecontrol-bin-2.6.2">
<fileset dir=".">
<include name="**/*.xml"/>
<exclude name="build.xml"/>
</fileset>
</copy>
</target>
</project>
There are a couple of things to keep in mind if you are using this technique. If you make any changes to configuration files (e.g. /opt/cruisecontrol/cruisecontrol-bin-2.6.2/build-project.xml, etc.), directly on the server, they’ll be overwritten by these changes. The other thing is that if you make changes to the config.xml, they won’t be effective until the next build because it uses the config.xml to find changes to “itself”.
Is anyone using a different technique to solve this issue? Are you managing your CI server changes in your version control system? Is this too extreme?

May 3rd, 2007 at 8:22 am
How do you get the CI server to read the new config files? Does it bounce itself, or does it nicely notice the change and update itself?
It hadn’t occurred to me to use this technique, but it makes a lot of sense. CI configuration files want version control exactly like source code does (arguably even more) — I’ve been bitten before by making a change to the config file and then remembering how to undo it.
I’m kind of petrified of the concept of an application changing its own configuration, so I’d be inclined to implement a small cron script that would poll for changes, signal the CI server to shut down (nicely), back up the old config (for quick recovery), export the new version of the config to the appropriate directory, and then start up the CI server. It’d be a one-page Perl script, basically automating the steps I would go through by hand to update the CI config.
May 3rd, 2007 at 12:15 pm
I love this pattern. I used it at my last job, and will be using it in my new job. This way, I can work on the CruiseControl builds in my own comfy IDE environment, and not have to work on the CC server which is not as comfy.
The only thing that I haven’t resolved for myself is how to test my changes before they go to the “production” CC environment. (At least, not without replicating the entire environment on a local box…)
To Robert:
CruiseControl re-reads (or checks to re-read) the configuration file every time it starts it’s execution loop.
May 3rd, 2007 at 4:09 pm
I think versioning config files is especially attractive when when combined with the include.projects tag. Basically you can have a single wrapper config.xml and then have it pickup the per-project config.xml files from the projects. This allows each project to manage their own settings and even if one project puts a typo in their config.xml it doesn’t cause problems for the other projects.
May 11th, 2007 at 4:21 pm
Can you add this to the CruiseControl wiki? I’ve been looking for something very much like this.