Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / XML

Continuous Integration using CruiseControl.NET, NANT, CVS, and NUnit

4.00/5 (14 votes)
25 Sep 2006CPOL6 min read 1   694  
A guide to configuring a Continuous Integration server.

Introduction

Recently, I set up a build system for a software development team working in .NET. I was interested in the Continuous Integration approach, where builds occur automatically as changes are detected in source control. My other goals were to keep my team's build process simple and understandable, and to group tasks in a way that makes sense and encourages reuse.

Most of my information was gained by reading of other developers' experiences documented on the web, but I could not find a single, comprehensive "newbie guide" on how to set up an entire system. My intention is to provide such an article, explain the logic behind my decisions, and perhaps ease the process for others implementing similar systems.

This article assumes that you have the requisite tools already set up. I used Visual Studio 2005, CruiseControl.NET 1.0.1, NAnt 0.85-rc3, and NUnit 2.2.7. Tortoise CVS 1.8.26 is used as a CVS client, and IIS is needed for CruiseControl.NET's Web Dashboard.

Background

The developer's toolset is usually composed of at least the following tools:

  • Source control repository to store code in a common location and allow multiple developers to share a code base (e.g., CVS, Subversion, VSS).
  • Unit testing framework to run unit tests which are written as part of the code development process and can flag unintentional changes to code (e.g., NUnit, JUnit).
  • Automated build tool to allow building from the command line and to perform related tasks (e.g., Ant, NAnt, MSBuild).
  • Continuous Integration tool which monitors for code changes and triggers builds (e.g., CruiseControl, Draco).

Build tools have increased in complexity over the years, and many overlap in functionality. As a result, implementation decisions can be endless. For example, should unit tests be run directly from CruiseControl, NAnt, or MSBuild? If email notification is used, how should this be wired up? The answers lie in the strengths and weaknesses of each tool, but implementing or investigating each one can be time-consuming.

Flow Control

To aid in understanding how this system works and what each component does, I've provided a typical scenario:

  1. Developer commits code changes/additions to CVS.
  2. CruiseControl.NET detects changes.
  3. CruiseControl.NET updates code on build machine.
  4. CruiseControl.NET invokes NAnt script.
  5. NAnt script builds application using devenv.com.
  6. NAnt script runs unit tests. Final CruiseControl.NET tasks support display of unit testing information.
  7. CruiseControl.NET manages output files for display in its Web Dashboard.
  8. CruiseControl.NET sends emails as appropriate.

Continuous Integration Tool: CruiseControl.NET

Of the two most common Open Source Continuous Integration tools, I chose CruiseControl.NET. I did not spend a lot of time comparing them, and my decision was based on the fact that some developers consider it more flexible. Its most useful features are its ability to poll source control for changes, and a powerful Web Dashboard (requires IIS) that provides a history of all builds and their details.

Initial Setup

The heavy lifting will involve setting up a project block in the ccnet.config file. Aside from that, you will probably want to turn on logging in the ccnet.exe.config file.

Automated Build Tool: NAnt

I found that running unit tests and builds in NAnt (invoked by CruiseControl) is more manageable than running them directly from CruiseControl. Packaging build and unit tests into a single NAnt script also allows for easier script debugging, and gives developers a tool which can build and test from the command line if desired. Because the default.build file is checked into CVS with the rest of the project, changing it will cause CruiseControl.NET to rebuild.

Both NAnt and CruiseControl.NET can run any executable and have tags dedicated to running unit tests. But, NAnt provides more support for ancillary tasks such as file management, and its flow control is more flexible.

Initial Setup

Set up a default.build NAnt file in the base directory of the project, which builds the project and runs NUnit tests. For the tests, I recommend Thea Burger's pattern that allows unit tests from multiple assemblies all to run to completion despite a possible failure in one assembly.

XML
<target name="test" description="runs the unit tests" >
    <!-- test first Assembly. -->
    <exec program="nunit-console.exe" failonerror="false" 
                resultproperty="testresult.Main.exe">
        <arg value="RelativePath/Main.exe" />
        <arg value="/xml=UnitTest-Main.xml" />
    </exec>

    <!-- test second Assembly. -->
    <exec program="nunit-console.exe" failonerror="false" 
                  resultproperty="testresult.SecondaryAssembly.dll">
        <arg value="RelativePath/SecondaryAssembly.dll" />
        <arg value="/xml=UnitTest-SecondaryAssembly.xml" />
    </exec>

    <!-- Check the results properties and fail if necessary -->
    <fail message="Failures reported in unit tests." 
          unless="${int::parse(testresult.Main.exe)==0}" />
    <fail message="Failures reported in unit tests." 
          unless="${int::parse(testresult.SecondaryAssembly.dll)==0}" />
</target>

Compiler: MSBuild.exe or Devenv.com

These are the two options for building a .NET solution or project from NAnt or at the command line. I experimented with both, but used devenv.com because the current version of MSBuild cannot build setup files! MSBuild offers additional capabilities which overlap with the Ant/NAnt family, and some developers prefer it to devenv because it does not necessitate installation of Visual Studio on the build machine. However, the setup shortcoming was a deal breaker, and there was no need to use both MSBuild and NAnt in the process.

It's worth noting that some tools belong in the solution, in post-build events. An example of this is obfuscation, which occurs only as part of the Release build and needs to be run before constructing the setup files.

Other Tools: CVS and NUnit

For my project, the choices of CVS and NUnit were predetermined. CruiseControl provides similar tools for monitoring a variety of other code repositories as well. NUnit is prevalent, and has been used by my team on a number of projects.

More CruiseControl.NET Setup Pointers

The Merge Tag

Depending on how you wire up CruiseControl.NET, it might be necessary to "Merge" output from an invoked application, in order to get test results to appear in the Web Dashboard and in email messages. This is the case when invoking NUnit from NAnt as outlined above. When NAnt invokes NUnit, XML output is explicitly requested.

XML
<exec program="nunit-console.exe" failonerror="false" 
              resultproperty="testresult.Main.exe">
    <arg value="RelativePath/Main.exe" />
    <arg value="/xml=UnitTest-Main.xml" /> <!-- keep xml output -->
</exec>

These files are then "merged" in ccnet.config.

XML
<merge>
    <files>        
        <!-- these file names need to conform to those found in default.build -->
        <file>C:\cruisecontrol-dev\test\RegexDemo\UnitTest*.xml</file>
    </files>
</merge>

CruiseControl.NET recognizes the XML from NUnit (and a number of other apps as well) and knows what to do with it.

The Web Dashboard

Once all processes are running and visible, you can tweak the CruiseControl.NET Web Dashboard by changing dashboard.config or the XML, XSL, and CSS that shape its content. The email messages sent out by CruiseControl.NET are also controlled in the same way, by a separate set of files.

Summary

In the final analysis, the build process outlined here is configured in three places: CruiseControl.NET's ccnet.config, the NAnt default.build, and in the solution itself. CruiseControl is a great system, and we've found unexpected uses for it even in the first few weeks. I continue to be impressed with its flexibility.

Sample Code

The sample code contains an example of ccnet.config which builds a simple application with one unit test and no unusual dependencies. The sample app can be checked into CVS and used for testing. The default.build file is included as well.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)