Configuring CruiseControl.Net
At Huddle I’ve recently been involved with looking at the build setup that we have in place (also see my article Defining a development tree). I’ve attached the build scripts and Cruise Control config to the blog, but will explain them below.
1. Setting up Cruise Control
- Once installed setup the “working” and “artifact” directories where all the builds can take place. This should be on a separate partition to Windows. I like to use the following setup:
- Add Cruise Control’s config (ccnet.config) to source control. Setup a Cruise Control project that watches the source control directory ccnet.config is located in, and deploys the config (to itself) when any changes are made. In other words it is possible to deploy Cruise Control updates via Cruise Control. You can extended this as it’s good to keep the XSL files used by the dashboard as well as the dashboards config.
- The next step is to add two projects, one to build our application (triggered every 60 seconds) and another to build & deploy our application (upon demand). Here is an example:
- Notice the “inclusionFilters”. These are put in place so that the build does not trigger everytime a non related build file is checked in. The “xmllogger” is also important as it stores all the NAnt build logs.
d:\build\working\myproject\trunk\ d:\build\artifact\myproject\trunk\ d:\build\artifact\myproject\trunk\archives\ d:\build\artifact\myproject\trunk\packages\ d:\build\artifact\myproject\trunk\build\
<project name="# cruise control"> <triggers> <intervalTrigger seconds="480" /> </triggers> <sourcecontrol type="svn"> <trunkUrl>http://buildbox/huddle/cruisecontrol</trunkUrl> <workingDirectory>c:\Program Files\CruiseControl.NET</workingDirectory> <executable>c:\Program Files\Subversion\bin\svn.exe</executable> <username>build</username> <password>build</password> </sourcecontrol> </project>
* The only downside is to make sure you don’t make any mistakes in the config file or you’ll break Cruise Control. You may not notice it straight away. The easiest thing to do is to stop and then start the Cruise Control.Net Windows service. If it fails to start, check the Event Log to see what’s wrong.
<project name="my.huddle.dev (trunk) build" queue="Trunk" queuePriority="1"> <workingDirectory>d:\build\working\myhuddle\trunk</workingDirectory> <artifactDirectory>d:\build\artifact\myhuddle\trunk</artifactDirectory> <triggers> <intervalTrigger seconds="60" /> </triggers> <labeller type="iterationlabeller"> <prefix>10</prefix> <duration>2</duration> <releaseStartDate>2008/6/18</releaseStartDate> <separator>.</separator> </labeller> <sourcecontrol type="filtered"> <sourceControlProvider type="svn"> <trunkUrl>http://buildbox/huddle/trunk</trunkUrl> <username>build</username> <password>build</password> </sourceControlProvider> </sourcecontrol> <tasks> <nant> <executable>tools\nant\bin\nant.exe</executable> <nologo>true</nologo> <buildFile>"build\1.nant.build"</buildFile> <buildArgs>-D:root.directory=\\Staging\e$ -D:environment=dev</buildArgs> <logger>NAnt.Core.XmlLogger</logger> <targetList> <target>build</target> </targetList> <buildTimeoutSeconds>1800</buildTimeoutSeconds> </nant> </tasks> <publishers> <merge> <files> <file>d:\build\artifact\myhuddle\trunk\reports\fxcop.xml</file> <file>d:\build\artifact\myhuddle\trunk\reports\nunit\*.xml</file> <file>d:\build\artifact\myhuddle\trunk\reports\sourcemonitor.xml</file> <file>d:\build\artifact\myhuddle\trunk\reports\sourcemonitor-details.xml</file> </files> </merge> <xmllogger logDir="d:\build\artifact\myhuddle\trunk\buildlogs\publisher\" /> </publishers> </project>
2. Queue Priority
One problem I encountered was the “build” project running at the same time as the “build/deploy” project. As both projects use the same working directory this would throw an error as subversion locks the working directory during an svn-update.
To get round this projects can be given a queue priority which forces them to be run sequentially instead of concurrently. Here’s an example snippet:
<project name="my.huddle.dev (trunk) build" queue="Trunk" queuePriority="1">
A queue must be given a name (this has to be the same for all projects using that queue). The project then has a “queuePriority” for that queue
3. Publishers
These are relatively simple to setup. For any XML output from applications such as FxCop, nCover etc… if you tell Cruise Control where they are it’ll merge everything into the build log, making it available on the web dashboard.
Here is an example of how we have our publishers setup:
<publishers> <merge> <files> <file>d:\build\artifact\myhuddle\trunk\reports\fxcop.xml</file> <file>d:\build\artifact\myhuddle\trunk\reports\nunit\*.xml</file> <file>d:\build\artifact\myhuddle\trunk\reports\sourcemonitor.xml</file> <file>d:\build\artifact\myhuddle\trunk\reports\sourcemonitor-details.xml</file> </files> </merge> <xmllogger logDir="f:\build\artifact\myhuddle\trunk\buildlogs\publisher\" /> </publishers>
4. Don’t touch ccnet.config!
There are two main reasons, once ccnet.config is setup, to not touch it, or to touch it as little as possible.
- If NAnt build files handle most of the logic, they can be run/tested etc… via developers calling them from the command line. In other words, mimicking the build environment.
- As mentioned above, each time you change ccnet.config, you risk breaking Cruise Control, which is harder to notice than breaking a NAnt build file (which you can test locally before committing the change).
One problem we had was the name of our release branch for each iteration. For example “iteration09″, “iteration10″ etc… This required us to update ccnet.config each time to reflect svn paths etc… However, we’ve now changed to a more elegant solution that fits the usage of subversion much better. Our release branch is always called “release”. When it comes to cutting a new branch, “release” is renamed (or tagged) as “iterationXX”. Upon the next release, all the trunk changes are merged into the “release” branch.
6. Builds & deployments
Our old build process, up each commit, would trigger a full build and deployment of the code. The whole process would take around 5-10 minutes (if not more), and by the time it has finished, it would trigger again!
So for MyHuddle we have two projects.
- A project that purely does the build (upon each commit), and any metrics such a test coverage. This is to ensure the build is not broken.
- A project that deploys the code (upon forcing it to run) to our development server (upon demand). This project actually does a build and deploy. There’s potential to make it just do the deploy but require the first project to run prior.
From my experience of build servers, it’s well worth investing in processor power, and hard drive space. Both are very cheap at the moment. Also make sure the build server purely focuses on doing the build, nothing else such as being a DC, or email server, web server etc… Otherwise you risk things slowing down and builds taking 10+ minutes.
7. Test deploys
We currently only have limited restrictions when releasing Test builds. This is something we should (or are) looking into to improve so as not to interrupt any testing taking place.
For now, test deployments run nightly or via a “force build” in CCTray. There are plugins for Cruise Control to limit who can “force build” but we need to look into those, and it’s currently not a huge issue regarding who can force build.
8. Moving Forward
My next step in to look at cleaning up ccnet.config. I seem to remember CruiseControl (not .Net) has a “property” element for defining variables which you can re-use in each project. This would save repeating a lot of paths, variables etc… I know there’s a way of seperating out ccnet.config into seperate XML (config) files, but it’s not something I want to look at straight away (as any changes to a non ccnet.config file, require CruiseControl to be restarted, it will only notice updates to ccnet.config).
That’s it for now. Everything else is handled by NAnt which I’ll detail in my next post. I’ll upload the source code when I get a chance.


