Sunday, August 26, 2007

Cruise control with SVN - Automated build system

We recently configured Cruise Control http://cruisecontrol.sourceforge.net/ for automating our builds. We found it a fantastic and a simple tool for this purpose. Some of the features that we configured were:

1. Periodic Build as per specified frequency.
2. Perform an SVN update before starting the build.
3. Get the details of the SVN changes that were received during this build.
4. Email the Build report with SVN history of changes (and build details).
5. Web based console for triggering builds and viewing build logs.
6. Reuse our existing ant and batch scripts in the build.

Lets get to the details of how to setup Cruise Control with SVN now...

SOFTWARE COMPONENTS
The first step would be to download the various software components needed.

1. Java. Since CruiseControl is a java software, it needs Java to be present on your machine. You could download Java from the Sun website and extract it to some directory (say: D:/Java15).

2. CruiseControl. download the zip, and extract it to a directoy (say: D:/CruiseControl). We used CruiseControl version2.7. http://cruisecontrol.sourceforge.net/

3. SVN Command line. CruiseControl would need to use this for firing SVN Update, etc to retrieve the latest files from SVN. To download SVN command-line go to: http://subversion.tigris.org/ We used Subversion for Win32, version 1.4.4. Extract the SVN client into a directory (say: D:/SVN_CLIENT). Then set your "PATH" variable to SVN_CLIENT/bin folder so that you can fire the "svn" command from any directory in your command window.


CONFIGURATION

Okay. Now that we have the software components we need. Lets begin with configuring CruiseControl for the various features mentioned above.

The first step would be to check if CruiseControl runs. For that we fire the D:/CruiseControl/cruisecontrol.bat script. This script requires that JAVA_HOME environment variable be set to point to a valid Java installation. If you don't have this variable set, or aren't sure then just edit the bat file and add the following line to the start:
set JAVA_HOME=D:/Java15 (or whatever your Java directory path is).

Also do a search for the "-webport" string in the cruisecontrol.bat file. It will point to the port number where cruisecontrol opens an HTTP port for your browser to connect to. Its usually set to 8080 (I changed mine to 9000 to avoid clashing with my Tomcat instance).

Now, run cruisecontrol.bat file, and open your browser to point to http://localhost:8080/ (or whatever you have set as port). You should see the CruiseControl page. This will let you know if your CruiseControl is up and running.

If all is ok till here,....our next step will be to configure cruise control for our project.

CruiseControl is completely driven from one configuration file (D:/CruiseControl/config.xml) - which is wonderfully convienient and simple. Lets edit the config.xml file.

Here is a sample configuration file (config.xml):
<cruisecontrol>

<project name="xPROJECT">

<property name="xPROJECT_TRUNK" value="D:/trunk" />
<property name="xPROJECT_ANT_HOME" value="${xPROJECT_TRUNK}/tools/apache-ant-1.7.0" />
<property name="DEV_PROPERTY_FILE" value="${xPROJECT_TRUNK}/developer-gsl/build.properties"/>
<property file="${DEV_PROPERTY_FILE}" />


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

<!-- Perform SVN UPDATE of specified folders -->
<bootstrappers>
<svnbootstrapper localWorkingCopy="${xPROJECT_TRUNK}/middletier" />
<svnbootstrapper localWorkingCopy="${xPROJECT_TRUNK}/utilities" />
</bootstrappers>

<!-- Wait for 1 minute from the last SVN update -->
<modificationset quietperiod="60">
<svn localWorkingCopy="${xPROJECT_TRUNK}/middletier"/>
<svn localWorkingCopy="${xPROJECT_TRUNK}/utilities"/>
</modificationset>

<!-- Build every 3 hours -->
<schedule interval="10800">
<composite>

<!-- BUILD CLEAN -->
<ant anthome="${xPROJECT_ANT_HOME}"
antWorkingDir="${xPROJECT_TRUNK}"
buildfile="${xPROJECT_TRUNK}/buildsystem/scripts/buildMes.xml"
target="clean">
<property name="basedir" value="${xPROJECT_TRUNK}"/>
<property name="devpropertyfile" value="${DEV_PROPERTY_FILE}"/>
</ant>


<!-- BUILD JAVAUTILS -->
<ant anthome="${xPROJECT_ANT_HOME}"
antWorkingDir="${xPROJECT_TRUNK}"
buildfile="${xPROJECT_TRUNK}/buildsystem/scripts/buildMes.xml"
target="buildJar">
<property name="basedir" value="${xPROJECT_TRUNK}"/>
<property name="devpropertyfile" value="${DEV_PROPERTY_FILE}"/>
</ant>

<!-- BUILD JAVAPERSISTER -->
<exec command="${xPROJECT_TRUNK}/buildsystem/bin/buildMes.cmd"
workingdir="${xPROJECT_TRUNK}/"
args="${DEV_PROFILE} javapersister"
errorstr="BUILD FAILED/>

</composite>
</schedule>

<!-- SEND EMAIL -->
<publishers>
<htmlemail buildresultsurl="http://localhost:8080/"
mailhost="smtpout.secureserver.net"
username="someuser@somedomain.com" password="somepassword"
returnaddress="build@somedomain.com"
subjectprefix="[xPROJECT-BUILD-NOTICE]"
skipusers="true"
>

<always address="build-person@somedomain.com"/>

<!-- Mapping SVN usernames to Alias -->
<!--
<map alias="john" address="john@somedomain.com" />
<propertiesmapper file="svn-users-email-list.properties" />
-->
</htmlemail>
</publishers>
</project>

</cruisecontrol>



The details for each of the above elements (and much more) can be found here:
http://cruisecontrol.sourceforge.net/main/configxml.html.

Lets discuss some of the elements above:

1. Each project in CruiseControl is inside a <project> element. All configuration settings for a particular project will go inside the <project> element. As you see above, we have configured a project element called "xPROJECT". This is the name that is visible in the CruiseControl web screen (and the logs folder,etc).

2. The <property> elements can be used to define properties, much like its done in ANT. These properties can be used in the config.xml file, and are also passed to your ant scripts that are invoked by CruiseControl. You can specify a properties file also like I have done using:
<property file="${DEV_PROPERTY_FILE}" />
Where ${DEV_PROPERTY_FILE} resolves to the value of the variable DEV_PROPERTY_FILE (which is a simple properties file containing name-value pairs that will drive the build process).

3. The <bootstrappers> contain those elements which are triggered BEFORE the build. For instance, in our case, we want to do an SVN update of specific working folders on our machine before firing the build. Therefore the below configuration specifies that an SVN update should be done of the "middletier" and "utilities" folder before firing the build process:
<bootstrappers>
<svnbootstrapper localWorkingCopy="${xPROJECT_TRUNK}/middletier" />
<svnbootstrapper localWorkingCopy="${xPROJECT_TRUNK}/utilities" />
</bootstrappers>

There are lots of other elements that can be configured like the <cvsbootstrapper>, <starteambootstrapper>, <vssbootstrapper>, etc depending on your source-code configuration management system.

Note that for using the <svnbootstrapper>; element, the SVN Client must be configured on your system (i.e the "svn" command must be in your PATH) .

4. The <schedule> element holds the elements that will be executed periodically depending on the "interval" attribute. For instance in our case <schedule interval="10800"> implies that the build should be run every "10800"seconds - which is every 3 hours.

Inside, the <schedule> element is the <composite> element - which indicates that we will be using multiple <ant> or <exec> elements for one build. The <ant> elements point to the actual build scripts that will be invoked for building the project. Note that the "anthome" attribute has been set to point to the ANT version that we use for our project. If for some reason, you need to invoke a script (or a batch file) then use the <exec> element. For example, in our case:

<exec command="${xPROJECT_TRUNK}/buildsystem/bin/buildMes.cmd"
workingdir="${xPROJECT_TRUNK}/"
args="db2 javapersister"
errorstr="BUILD FAILED/>

The "command" attribute points to the script to be executed. The "args" contains two arguments "db2" and "javapersister" that get passed to the script. The "errorstr" attribute contains the strings to search for to indicate failure (of course return value of the command is also used by CruiseControl - and that can result in incorrect failure indications if the
scripts are not written with correct return code handling).

5. The last is the <publisher> element, that contains those elements that must be executed irrespective of whether a build passed or failed (Much like the "finally" of the infamous "try-catch-finally" block in Java). The <publisher> element can be used to send emails (build notices), yahoo/sametime message, ftp uploads, execute scripts, etc after a build has been attempted/succeeded/failed. You can specify stuff like: Do this on build failure, and do this on build success, and do this everytime irrespective of build status. For more details see the configuration documentation of CruiseControl. Most commonly used is the <htmlemail> element - which sends an email containing URL to the CruiseControl webpage, brief summary of build status, build time, SVN Modification history, etc. CruiseControl can be configured to send an email to those developers whose modifications made it into the build. For that: set "skipusers" attribute to "false" and provide <map> elements for mapping SVN user names to email addresses (or provide a mapping properties file in the form
of name-value pairs like john=john@somdomain)

<!-- Mapping SVN usernames to Alias -->
<map alias="john" address="john@somedomain.com" />
<propertiesmapper file="svn-users-email-list.properties" />

THATS ALL !
Now start cruisecontrol.bat - and you should see your project in CruiseControl's web console.

No comments: