August 20, 2007

CruiseControl Integration

Surround SCM
Surround SCM supports integration with CruiseControl. This article was written using Surround SCM 5.0.4 and CruiseControl 2.7. [toc]

Integration Documentation

The documentation for the integration is found in the Cruise Control Web Site.

A Simple Cruise Control Example

The program comes with a sample project using pvcs and ant as the build tool. I took this sample file and made some modifications. To minimize the changes, I decided to also use Ant as the build tool, and since I already had an example set up, I decided to use that one, which you can find in this wiki. Please review this example first before proceeding with this article.

CruiseControl Does Not Appear To Handle Spaces

In the example mentioned above, the files were added to a mainline branch called "Ant Example". This branch was referenced in the CruiseControl Config.XML file, with quotes to make sure that the spaces were correctly evaluated. However, when I ran CruiseControl, it kept complaining that it couldn't find branch "Ant" under mainline "Ant". I did some research on the internet and found other users that have run into similar issues. In order to move past this issue, I made the following changes to the example:
  1. I created a new mainline branch called "CruiseControlTest"
  2. I created a new folder called "CCtest" on the root of my D: drive
  3. I copied the "MessageRunner" folder to the "CCtest" folder
  4. I then added the "MessageRunner" folder I just had copied to the "CruiseControlTest" mainline branch and set the working directory of the top level repository (CruiseControlTest) to "D:CCtest".
  5. I made the nescessary changes to the build.xml file that Ant uses to do the build.
These are the contents after the changes:
<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="MessageRunner" basedir="." default="jar">

<taskdef name="sscmget" classname="com.seapine.surroundscm.ant.SSCMGet"/>
<taskdef name="sscmcheckin" classname="com.seapine.surroundscm.ant.SSCMCheckin"/>
<taskdef name="sscmbranch" classname="com.seapine.surroundscm.ant.SSCMBranch"/>

    <property name="src.dir" value="src"/>
    <property name="classes.dir" value="classes"/>

    <target name="clean" description="Delete all generated files">
        <delete dir="${classes.dir}" failonerror="false"/>
        <delete file="${ant.project.name}.jar"/>
    </target>

    <target name="compile" description="Compiles the Task">
        <mkdir dir="${classes.dir}"/>
        <sscmget
         serverconnect="localhost:4900"
         serverlogin="administrator:"
         file="/"
         branch="CruiseControlTest"
         repository="CruiseControlTest/MessageRunner/src"
         destdir="D:CCtestMessageRunnersrc"
         recursive="true"
         quiet="false"
         writable="false"
         overwrite="replace"
         force="true"

         />

        <javac srcdir="${src.dir}" destdir="${classes.dir}"/>
    </target>

    <target name="jar" description="JARs the Task" depends="compile">
        <jar destfile="${ant.project.name}.jar" basedir="${classes.dir}">
        <manifest>
               <attribute name="Main-Class" value="MessageRunner"/>
        </manifest>
        </jar>

      <sscmcheckin
         serverconnect="localhost:4900"
         serverlogin="administrator"
         file="${ant.project.name}.jar"
         branch="CruiseControlTest"
         repository="CruiseControlTest/MessageRunner"
         comment="Check In from Ant"
         makewritable="true"
         deletelocal="false"
         quiet="true"
         force="true"
      />
       <sscmcheckin
         serverconnect="localhost:4900"
         serverlogin="administrator"
         file="/"
         branch="CruiseControlTest"
         repository="CruiseControlTest/MessageRunner/classes"
         comment="Check In from Ant"
         makewritable="true"
         deletelocal="false"
         quiet="true"
         force="true"
      />
         <tstamp/>
         <sscmbranch
         serverconnect="localhost:4900"
         serverlogin="administrator:"
         branch="${DSTAMP} - ${TSTAMP} - ${ant.project.name}"
         repository="CruiseControlTest/MessageRunner"
         parent="CruiseControlTest"
         type="snapshot"
         comment="Ant Build on ${DSTAMP} at ${TSTAMP}"
         />
    </target>

</project>
Now I had a valid Ant project with no spaces in any names to hold me back.

Creating the Config.XML File

I first took the sample config file provided for the sample "Connect Four" project and made changes to match my project and Surround SCM. First, I changed the project name to "MessageRunner". The second change was to the <bootstrapper> portion of the file. The CruiseControl documentation states that none of the arguments are required, so at first, I simply tried using "<surroundbootstrapper />", however, I kept getting some errors. I decided to go ahead add the arguments:
     <surroundbootstrapper
        branch="CruiseControlTest"
        repository="CruiseControlTest/MessageRunner"
        recursive="1"
        forcefetch="1"
        serverconnect="127.0.0.1:4900"
        serverlogin="Administrator:"
     />
Third, I modified the "modificationset" section. Again, the documentation states that none of the arguments are required so I first simply tried using "<surround/>", but due to errors, I decided to use the arguments:
     <surround
         branch="CruiseControlTest"
         repository="CruiseControlTest/MessageRunner"
         file="/"
         recursive="1"
         serverconnect="127.0.0.1:4900"
         serverlogin="Administrator:"
     />
The next set of changes were as follows:
  1. Changed the paths of the Ant_Home and the location of the Build.xml file.
  2. I changed the log directory to the D:CCtestMessageRunner directory.
  3. I changed the artifact directory to the D:CCtestMessageRunner
This is what the finished file looks like:
<cruisecontrol>
    <project name="MessageRunner">

        <listeners>
            <currentbuildstatuslistener file="logs/${project.name}/status.txt"/>
        </listeners>

        <bootstrappers>
            <surroundbootstrapper

             branch="CruiseControlTest"
             repository="CruiseControlTest/MessageRunner"
             recursive="1"
             forcefetch="1"
             serverconnect="127.0.0.1:4900"
             serverlogin="Administrator:"

             />

        </bootstrappers>

        <modificationset quietperiod="30">
            <surround
             branch="CruiseControlTest"
             repository="CruiseControlTest/MessageRunner"
             file="/"
             recursive="1"
             serverconnect="127.0.0.1:4900"
             serverlogin="Administrator:"

            />
        </modificationset>

        <schedule interval="300">
            <ant anthome="C:apache-ant-1.6.5" buildfile="D:CCtestMessageRunnerbuild.xml"/>
        </schedule>

        <log>
            <merge dir="D:CCtestMessageRunnertargettest-results"/>
        </log>

        <publishers>
            <onsuccess>
                <artifactspublisher dest="D:CCtestMessageRunnerartifacts" file="D:CCtestMessageRunnerMessageRunner.jar"/>
            </onsuccess>
        </publishers>

    </project>
</cruisecontrol>