I recently had to implement a continuous integration framework on one of my projects. Naturally, CruiseControl.NET was the first choice because of it’s extensive feature list and good community support.
If you are not sure what continuous integration is, then here a couple of good places to get you started:
http://en.wikipedia.org/wiki/Continuous_integration
http://martinfowler.com/articles/continuousIntegration.html
More specifically, CruiseControl.NET offers the following features (source):
- Integration with a variety of Source Control systems
- Integration with other external tools, such as NAnt and Visual Studio
- Can build multiple projects on one server
- Remote management and reporting
As you can see it can be configured to do a vast array of things, but for the purpose of this post, I’m interested in achieving the following:
- Setup a CI server
- Setup the config file required for building my projects (I’m going to use MSBuild rather than Nant) & monitor build results by setting email notifications
Step 1 – Setup a CI server
This step couldn’t have been easier. A dedicated build & integration server is always recommended. I’m huge fan of virtualisation and for this particular example I’ve setup a Windows 2008 virtual machine. The software that you’ll need to install on the server are:
- Prerequisites: .NET Framework (latest version), IIS
- CruiseControl.NET
You can download the latest version of CruiseControl.NET from here. At the time of writing of this post, the latest version was 1.5 RC1 and that’s the one I’ve used for my setup. I ran into one issue with this release, which I’ll discuss in the notes section at the end of this post, but I guess that’s acceptable for a RC release.
Download the setup file and go through the installation and choose all of the default options. At the end of a successful installation, you’ll have two main things on the server:
- Web dashboard: This can be accessed by going the following URL: http://localhost/ccnet/
- Windows service: This gets installed with a name of “CruiseControl.NET Server”. This is the main service which is responsible for building your projects.
A quick gotcha over here – if you get an error on the dashboard page just after the installation which says something like “No connection could be made because the target machine actively refused it“, then make sure that the windows service is running. By default, it gets installed with a “Startup type” of “Manual”. If this is the case with you as well, then go to the Services management console and start the service manually.
That’s pretty much what’s required for setting up your server. All that’s required now is to setup your config file with details about the projects that you want to build.
Step 2 – Setup the config file
The config file is located at: C:\Program Files\CruiseControl.NET\server\ccnet.config. Open this is file in your favourite text/XML editor and start entering details about your project. As an example, below is what I ended up with:
<cruisecontrol xmlns:cb="urn:ccnet.config.builder">
<!-- This is your CruiseControl.NET Server Configuration file. Add your projects below! -->
<project name="Build Framework">
<triggers>
<intervalTrigger seconds="3000" buildCondition="ForceBuild" />
</triggers>
<sourcecontrol type="vsts" autoGetSource="true" applyLabel="false">
<server>http://virtual-charon:8080</server>
<project>$/Reach.GlobalConnect/Reach/Reach.Laptop/Main</project>
<workingDirectory>C:\Temp\CCNet_Test\Laptop</workingDirectory>
</sourcecontrol>
<tasks>
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe</executable>
<workingDirectory>C:\Temp\CCNet_Test\Laptop</workingDirectory>
<projectFile>Laptop.Framework\Laptop.Framework.csproj</projectFile>
<buildArgs>/noconsolelogger /p:Configuration=Debug /v:diag</buildArgs>
<targets>Build</targets>
<timeout>600</timeout>
<logger>ThoughtWorks.CruiseControl.MsBuild.XmlLogger,C:\Program Files\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll</logger>
</msbuild>
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe</executable>
<workingDirectory>C:\Temp\CCNet_Test\Laptop</workingDirectory>
<projectFile>Laptop.Common\Laptop.Common.csproj</projectFile>
<buildArgs>/noconsolelogger /p:Configuration=Debug /v:diag</buildArgs>
<targets>Build</targets>
<timeout>600</timeout>
<logger>ThoughtWorks.CruiseControl.MsBuild.XmlLogger,C:\Program Files\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll</logger>
</msbuild>
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe</executable>
<workingDirectory>C:\Temp\CCNet_Test\Laptop\Reach.Laptop.Framework</workingDirectory>
<projectFile>Laptop.BusinessObject.csproj</projectFile>
<buildArgs>/noconsolelogger /p:Configuration=Debug /v:diag</buildArgs>
<targets>Build</targets>
<timeout>600</timeout>
<logger>ThoughtWorks.CruiseControl.MsBuild.XmlLogger,C:\Program Files\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll</logger>
</msbuild>
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe</executable>
<workingDirectory>C:\Temp\CCNet_Test\Laptop\ResourceProvider</workingDirectory>
<projectFile>Laptop.ResourceProvider.csproj</projectFile>
<buildArgs>/noconsolelogger /p:Configuration=Debug /v:diag</buildArgs>
<targets>Build</targets>
<timeout>600</timeout>
<logger>ThoughtWorks.CruiseControl.MsBuild.XmlLogger,C:\Program Files\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll</logger>
</msbuild>
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe</executable>
<workingDirectory>C:\Temp\CCNet_Test\Laptop\Reach.Laptop</workingDirectory>
<projectFile>Reach.Laptop.csproj</projectFile>
<buildArgs>/noconsolelogger /p:Configuration=Debug /v:diag</buildArgs>
<targets>Build</targets>
<timeout>600</timeout>
<logger>ThoughtWorks.CruiseControl.MsBuild.XmlLogger,C:\Program Files\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll</logger>
</msbuild>
</tasks>
<publishers>
<statistics />
<xmllogger />
<email from="test@test.co.uk" mailhost="mail.test.co.uk" includeDetails="true"
mailhostUsername="test" mailhostPassword="test">
<users>
<user name="Test" address="developer@test.co.uk"
group="NotifyGroup" />
</users>
<groups>
<group name="NotifyGroup">
<notifications>
<NotificationType>Always</NotificationType>
</notifications>
</group>
</groups>
</email>
</publishers>
</project>
</cruisecontrol>
Most of the XML is self-explanatory but here are a few things to point out:
- The buildCondition attribute defaults to a value of “IfModificationExists” which will only initiate the build process if there have been changes to the code repository since the last build. I’ve set it to “ForceBuild” – which will initiate the build process irrespective of whether there’s new code checked-in or not.
<triggers> <intervalTrigger seconds="6000" buildCondition="ForceBuild" /> </triggers> - The type attribute is set to “vsts” – this is because I’m using TFS as my source control provider but you could quite easily use any of the other supported source controls including SVN & CVS.
<sourcecontrol type="vsts" autoGetSource="true" applyLabel="false">
- I wanted to get email notifications every time the build was processed. To accomplish this, the following piece of code was added to the config file:
<publishers> <statistics /> <xmllogger /> <email from="test@test.co.uk" mailhost="mail.test.co.uk" includeDetails="true" mailhostUsername="test" mailhostPassword="test"> <users> <user name="Test" address="developer@test.co.uk" group="NotifyGroup" /> </users> <groups> <group name="NotifyGroup"> <notifications> <NotificationType>Always</NotificationType> </notifications> </group> </groups> </email> </publishers>
Most of it is self-explanatory – the only setting worth pointing out is: NotificationType. I’ve set it to “Always” but it can also be set to “Failed” or “Changed”. Other values are explained over here.
Notes: A few quick things to point out which I learnt by experience while setting this up and could save you some time:
- Service security credentials: When your build process is run, you might get an error which says “System.Exception: TF30063: You are not authorized to access TFSServer“. There could be better ways of fixing it but I fixed it by changing the logon credentials of the “CruiseControl.NET Server” windows service to a login which has got access to the TFS server.
- Error if you are using VSTS: If you are using the RC version that I used, you might also run into an error which says “System.Exception: TF30076: The server name {0}MyTFSServer provided does not correspond to a server URI that can be found. Confirm that the server name is correct.“. In order to fix this I had to make a change to the source code and then re-deploy “ThoughtWorks.CruiseControl.Core.dll” to the “C:\Program Files\CruiseControl.NET\server” folder and re-start the windows service. More details here.
- Checking for errors: If you make any changes to the config file and don’t see those changes take affect, then try stopping and then re-starting service. The service will fail to start if there are any errors in the config file. If you get any errors while starting your service or when your build process runs, then you can check for the error logs in either the server’s Application log or in CCNET’s log file located over here: C:\Program Files\CruiseControl.NET\server\ccnet.log
Hope this will help someone out there who is just starting off with CruiseControl.NET. Get in touch via comments or email me if you run into any issues or have any queries regarding this post.
{ 3 comments… read them below or add one }
Also found that CCNet throws an exception because of the long file name for the location of TF.exe. Quickest way around it was to edit the registry value to use the shortname instead.
Thanks for the tip, Charles! Which registry value did you have to change?
Very helpful for 1st timers like me. Thanks for simple article.