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). service-01 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?