Drupal5, Macgyver, and CruiseControl

Recently I have been watching lots of Macgyver. I discovered that, one of my favourite episodes is "The Road Not Taken" (season 2, episode 7) where Macgyver employs some sort of rudimentary early-warning system to save a group of orphan children, himself, his boss (yes, papa Thorton, as Jack Dalton used to call him :), and his and his boss's former love interests!!! Lots of people. All saved because of a privimite early warning system consisting of ropes and pans. No wonder all the super powers and wanna-be super powers these days spend lots of cash on Airborne Early Warning and Control Systems (AWACS, http://en.wikipedia.org/wiki/AWACS).

If you want to justify deploying an Early Warning System (or want to write something on that topic), you first have to find something to warn about. For us computer programmers, what is it that we will be happy to be warned about early while we are programming? I had to add "while we are programming" because otherwise the reply will be quite open. To answer the question, how about computer bugs? It's a good starting point after all. If we are warned of bugs as soon as they are born in the code base, that should prevent lots of drama afterwards if you are working in a team.

So what kind of Early-Warning tools is your average Drupal developer armed with? According to Big G, all core and contributed code under the Drupal project are regularly test at http://testing.drupal.org . That is a very good news, the bad news is, it's not available while we are working outside the Drupal project. The path to Nirvana is as follows:
- Install CruiseControl
- Install phpUnderControl
- Install our patch.

Installing CruiseControl (CC)
You really don't need to install CC in the sense you have to install the rest of the software. Installing here means downloading the lastest zip file from
http://cruisecontrol.sourceforge.net/download.html . Once downloaded, unzip it
and place it whereever you like. I am assuming it's in "/home/sweet/cruisecontrol/" (of course I am also assuming you are operating a modern Unix box :) .

Installing phpUnderControl
Pretty easy if you have installed any kind of PEAR package before. Here's the
usual command -
$ pear install --alldeps phpunit/phpUnderControl

Now we need to install the phpUnderControl-specific extensions inside CC. This
will take you only one command:
$ phpuc install /home/sweet/cruisecontrol

Installing Our Patch
Download our patch (see attachement below) and copy all the files inside
"/home/sweet/cruisecontrol/webapps/cruisecontrol/"

Controlling Our Project, Finally...
It's time to introduce our project to CC. We will do so by creating three empty directories, two XML files, and one call to your version controlling tool.

Inside "/home/sweet/cruisecontrol/", there is a directory named "projects/".
Every software project you want to control via CC is housed here. Let's assume
that the name of our hypothetical, , world changing project is "TankControl".
Afterall, you need to control your Tanks to change the face of the Earth, don't
you?

That leads us to create "/home/sweet/cruisecontrol/projects/TankControl/".
Remember, I said we need to create three directories? One down, two to go.
Here goes the next one - "/home/sweet/cruisecontrol/projects/TankControl/build". And the last one - "/home/sweet/cruisecontrol/projects/TankControl/build/logs/".

Having built the directories Ladies and Jentleman, it's time to populate them.
So we will now checkout a working copy of TankControl from its repository. It
happens that TankControl is maintained under Subversion, which I can tell you
is your favourite source code control tool, isn't it?

$ svn co PATH_TO_TANKCONTROL_REPO source

Note that we are keeping our working copy under the "source" directory. You can use any name for this directory, but "source" is the name preferred by the
gods (Think of Zeus, Apollo, Venus, etc, etc).

Speaking of the gods, what do you think they used to configure the world? If
you ask a Java programmer, the answer definitely will be "XML". This brings us to the last step of our noble endevour. Create two XML files and we are done. Good news is, one of the XML files is already there and we need to extend it. So fire up your favourite text/xml/whatever editor and open
"/home/sweet/cruisecontrol/config.xml". You'll see something like this:

<?xml version="1.0"?>
<cruisecontrol>
  <project name="connectfour" >
    <bla /> <bla /> </bla />
  </project>
</cruisecontrol>

This "connectfour" is a demo app that comes with CC. We can ignore that (or
even delete that) and proceed to include "TankControl". Here is a snippet
of XML that will do:

--------------------------- XML SNIPPET BEGINS ----------------------------

<project name="TankControl" buildafterfailed="false">
    <plugin
      name="svnbootstrapper"
      classname="net.sourceforge.cruisecontrol.bootstrappers.SVNBootstrapper"/>
      <plugin
      name="svn"
      classname="net.sourceforge.cruisecontrol.sourcecontrols.SVN"/>
  
    <listeners>
      <currentbuildstatuslistener file="logs/${project.name}/status.txt"/>
    </listeners>
  
    <bootstrappers>
      <svnbootstrapper localWorkingCopy="projects/${project.name}/source/"/>
    </bootstrappers>
  
    <modificationset>
      <svn localWorkingCopy="projects/${project.name}/source/"/>
    </modificationset>
  
    <schedule interval="300">
      <ant
        anthome="apache-ant-1.7.0"
        buildfile="projects/${project.name}/build.xml"/>
    </schedule>
  
    <log dir="logs/${project.name}">
      <merge dir="projects/${project.name}/build/logs/"/>
    </log>
  
    <publishers>
      <currentbuildstatuspublisher
        file="logs/${project.name}/buildstatus.txt"/>
  
      <email
        mailhost="localhost"
        buildresultsurl="http://cruise.example.com/buildresults/${project.name}"
        skipusers="true"
        spamwhilebroken="true"
        returnaddress="project@example.com">

        <failure address="dev@lists.example.com" reportWhenFixed="true"/>

      </email>
    </publishers>
  </project>

--------------------------- XML SNIPPET ENDS ----------------------------

We need one more XML file to control "TankControl". If you are familiar with
Ant or Phing, you already know about "build.xml":

--------------------------- build.xml BEGINS -------------------------

<?xml version="1.0"?>
<project name="TankControl" default="build" basedir=".">

  <target name="checkout">
    <exec dir="${basedir}/source/" executable="svn">
      <arg line="up"/>
    </exec>
  </target>

  <target name="test">
    <exec executable="test-runner-xml.php"
        output="${basedir}/build/logs/test-result.xml" error="/dev/null" >
      <arg line="${basedir}/source/"/>
    </exec>
  </target>

  <target name="build" depends="checkout,test"/>

</project>

--------------------------- build.xml BEGINS -------------------------

Have you noticed the use of "test-runner-xml.php" here? This is the script that will run all unit tests everytime the source code is updated. Find it among the attachments below. Then copy it under your path and give it executable permissions (yes, do a chmod). If you are tired of all these business, then mention the full path of test-runner-xml.php as the value of "executable".

Finally, it's time to launce CC with all its glory:

$ cd /home/sweet/cruisecontrol/
$ ./cruisecontrol.sh

See Also
[0] http://www.phpunit.de/pocket_guide/3.3/en/continuous-integration.html
[1] http://cruisecontrol.sourceforge.net/main/configxml.html