Monday, June 16, 2008

How to call Rake from CruiseControl.Net

CruiseControl.Net is a great Continuous Integration tool. It is easier to setup than CruiseControl (java). Plus it makes more sense to use CC.Net if you work at a .Net shop.

To script the Continuous Integration process, I first investigated using MSBuild. At this time, I found MSBuild to work well for building Visual Studio projects. But MSBuild wasn't mature enough to accomplish much else. NAnt is a more mature alternative to MSBuild, which I've used on some projects. NAnt is fairly powerful (even better in my opinion than the original Ant). However, there is one problem with both these tools: XML is not a programming language.

Rake is a programming language. Rake is actually Ruby, with some additional stuff to give it the powers of Make. Rake also makes sense in a .Net shop because 1) Ruby can call .Net objects using the Ruby/.Net Bridge. 2) John Lam is currently porting Ruby to run directly on the .Net DLR.

So how do you get CruiseControl.Net to call Rake? The best solution would be to create a CC.Net plugin to call Rake. But if your like me, time is limited. So an easy kludge will suffice. The kludge is this: 1) CC.Net calls either MSBuild or NAnt, which is already built in. 2) MSBuild or NAnt executes Rake via an Exec task.

(You may be wondering why not use CC.Net exec task. The short answer, I couldn't get CC.Net exec task to call Rake. I'm not sure why. It just didn't work well.)

First - CC.Net calls MSBuild or NAnt. This is very simple. In the CC.Net config file you add a task...

<nant buildFile="nant.xml" />


<msbuild projectFile="msbuild.xml" />

Then you have NAnt or MSBuild call Rake. Here are the nant.xml and msbuild.xml files:

<?xml version="1.0"?>
<project name="Rake Runner" default="RakeBuild" basedir=".">
<target name="RakeBuild">
<exec program="c:\ruby\bin\rake.bat" />

<Project xmlns=""
<Target Name="RakeBuild">
<Exec Command="rake" />

Notice that each just calls the RakeBuild target, which is the default target.

Rake will then run the default target (you could specify a Rake task in the scripts above). Here is an example Rake script which displays all the environment variables:

task :default => [:test]

task :test do
ENV.each {|k,v| puts "#{k}=#{v}" }

CC.Net captures the output a little different for MSBuild vs NAnt. MSBuild's output is append to the end of the build log. Which results in a long build log. NAnt's output is captured to a different page "NAnt Output". However, NAnt prepends each line with "[exec]".