CodeKicks.com
Focus on Microsoft Technologies - Tutorials, Articles, Code Samples.

Thursday, January 04, 2007

Cruise Control using .NET for Continuous Integration

What is Continuous Integration

The practice of continuous integration represents a fundamental shift in the process of building software. It takes integration, commonly an infrequent and painful exercise, and makes it a simple, core part of a developer's daily activities. Integrating continuously makes integration a part of the natural rhythm of coding, an integral part of the test-code-refactor cycle. Continuous integration is about progressing steadily forward by taking small steps.

Integration should happen continuously, and continuously is more often than you might think. The frequency of integration will vary from project to project, from developer to developer, and from modification to modification. However, as a goal and a good rule of thumb, developers should integrate their changes once every few hours and at least once per day.

Learning how to integrate so frequently requires practice and discipline. Fundamentally, an integration can occur at any point when the code compiles and all the unit tests are passing. The challenge is learning how to write software so that you never stray too far from this point. If you are testing at the right level of granularity and are refactoring regularly, then you should never be more than a few minutes away from this point. This means that you are almost always in a position where you can launch a new integration.

Deciding when to integrate is all about controlling risk. When making modifications in a high traffic area of the code base or when conducting broad refactorings like class renaming or package reorganisation, there is an elevated risk of impacting other developers or of having merge conflicts when committing. The longer that developers go without integrating, the greater the likelihood of conflicts and the larger the effort required to resolve those conflicts. As the effort of integration increases exponentially in proportion to the time between integrations, best practices dictate that when making high-risk changes a developer should start from a clean workspace, focus only on required modifications, proceed with the smallest logical steps, and then commit at the earliest opportunity.

A successful integration is a measure of progress. It provides feedback that the new code runs correctly in the integration environment and successfully interoperates with the rest of the code base. Code sitting unintegrated in a developer's workspace simply does not exist. It is not part of the code base, it cannot be accessed by other developers or tested by the customer. Only when it has been successfully integrated is the benefit of the new code realised.

References

  • This text is snipped from Owen Rogers' recent article: Scaling Continuous Integration submitted to XP2004
  • Martin Fowler and Matt Foemmel's classic article: Continuous Integration

The CruiseControl .NET Server

CruiseControl.NET (CCNet) consists of a suite of applications, but at its core is the CruiseControl.NET Server which is an automated integration server.

The Server automates the integration process by monitoring the team's source control repository directly. Every time a developer commits a new set of modifications, the server will automatically launch an integration build to validate the changes. When the build is complete, the server notifies the developer whether the changes that they committed integrated successfully or not.

Read more about this process at CruiseControl.NET Integration Process.

Effectively, integration becomes as easy as checking in code. Using an automated integration server not only makes integration easy, it also guarantees that an integration build will happen. There is no danger of developers forgetting to validate their changes after checking in.

The CCNet Server offers several key features:

  • 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

You can see what applications CruiseControl.NET integrates with at Using CruiseControl.NET with other applications.

CruiseControl .NET Tools

The other applications in the CruiseControl.NET suite are:

  • Web Dashboard: A .NET web application that gives you a status and detailed view of the CruiseControl.NET projects and servers in your organisation.
  • CCTray: A client System Tray application that enables you to see 'at a glance' the state of your projects from any machine on your network.

Download CruiseControl for .NET

CruiseControl for .NET Tutorial in Detail - Version 1.0

Introduction

The idea of this article is to help you get started with CruiseControl.NET.  I’m assuming that you already know a bit about Continuous Integration and Test Driven Development and that you want to get up and running with CruiseControl.NET as quickly as possible.

I’m going to concentrate on setting up a system based on this environment:

·         .NET Framework v1.1

·         Visual Studio .NET 2003

·         Visual SourceSafe 6.0

 

This is a pretty common set-up at the moment.  However a lot of the ideas in this article are equally applicable to different versions of the CLR and Visual Studio .NET, and to different source control providers.

I’ve found that the many configuration options available in CruiseControl.NET can be a bit daunting so we are going to create a simple CruiseControl.NET setup by performing a series of steps.  You will end up with a working system which you can refine to meet your own needs.  Our configuration will consist of:

·         the CruiseControl.NET continuous integration server, initially running from the command prompt and later as a service

·         the Web Dashboard application which provides detailed information about completed builds

·         the CCTray system tray application, which runs on client machines and permits easy launch of the web application, forcing of builds etc

 

I have found these three applications to be excellent for the purposes of our development team.

Hardware

We are going to work with three machines:

·        the CruiseControl.NET build server, which will run the continuous integration server and the Web Dashboard – referred to in the configuration files that follow as "%buildserver%"

·        the server which hosts the SourceSafe database – referred to in the configuration files as "%sourceserver%"

·         a client machine which will run the CCTray system tray application and also view the CruiseControl.NET Web Dashboard using its browser

 

You can run everything on the same machine if you wish.

 

Software

To start with you’ll need the bits and pieces:

·         Visual Studio .NET 2003

·         Visual SourceSafe.  Version 6.0.

·         CruiseControl.NET.  Version 1.0 from: http://ccnet.thoughtworks.com.  It now comes with a neat installer (CruiseControl.NET-<version>-setup.exe)

·         NAnt for running build scripts.  Version 0.85-rc3 from: http://nant.sourceforge.net

·         NAntContrib for Visual SourceSafe support.  Version 0.85-rc3 from:  http://sourceforge.net/projects/nantcontrib

·         NUnit for adding test fixtures to Visual Studio .NET projects.  Version 2.2.0 from: http://www.nunit.org

 

The more recent versions of CruiseControl.NET can dispense with the need for NAnt, as they talk to SourceSafe directly for source retrieval and use Visual Studio .NET for the builds.  However I have not yet fully investigated this scenario, so we'll stick with NAnt for this article.

I’m also assuming that you have an IIS web server on your build server correctly configured to dish up ASP.NET pages.

Installation: Build Server

Your build server needs to have, at the least, a Visual SourceSafe client installation.  It does not, however, need a Visual Studio .NET installation as we will be using the NAnt solution task to build our project.

Create a directory on your build server to hold all the bits and pieces.  Mine is C:\Projects\CI (short for Continuous Integration).  In this directory:

·         Unzip NAnt to C:\Projects\CI\

·         Unzip NAntContrib to C:\Projects\CI\.  Then copy the contents of the nantcontrib-0.85-rc3\bin directory to the nant-0.85-rc3\bin directory.  This will enable NAnt to use the "vssget" task later on.

 

Now run the CruiseControl.NET installer on the build server and accept all the default settings except for the destination folder.  I like everything in the same place, so enter "C:\Projects\CI\CruiseControl.NET".

 

You now have a single directory on the build server containing your continuous integration environment.

 

Installation: Source Server

Your source control server needs a Visual SourceSafe server installation.

 

Installation: Client

Your client machine needs a Visual Studio .NET installation in order to create the project in this example.

 

It also needs NUnit 2.2 installed so that we can write some tests.

 

You will find the installer for the CCTray application inside the webdashboard\cctray folder in the build server installation.  Run this on the client, installing it to any destination folder you like.

 

Towards Our First Successful Build

We are going to run the continuous integration server from the command line at first – it's easier to see what's going on.  Open a command prompt window and navigate to C:\Projects\CI\CruiseControl.NET\server.  Run ccnet.exe.  You will see this output a bit like this:

[CruiseControl Server:Debug]: The trace level is currently set to debug...

[CruiseControl Server:Info]: Reading configuration file "C:\Projects\CI\CruiseControl.NET\server\ccnet.config"

[CruiseControl Server:Info]: No projects found

[CruiseControl Server:Info]: Registered channel: tcp

[CruiseControl Server:Info]: CruiseManager: Listening on url: tcp://192.168.0.1:21234/CruiseManager.rem

[CruiseControl Server:Info]: Starting CruiseControl.NET Server

 

Nice and neat – a big improvement on previous versions.  Starting in version 1.0 of CruiseControl.NET debug tracing is turned on by default, so even more information is displayed to help you get up and running.  The application is reading an XML file called ccnet.config, which at present has next to nothing in it.  But it is very happily starting and waiting for something to happen.  Unfortunately nothing will happen until we put something in ccnet.config.

We will modify ccnet.config file so that it contains two things:

·         a source code repository to examine for changes

·         a nant.exe to run and also a build file to run against

 

Once we’ve done this we’ll get our first successful build.

Modify ccnet.config

Leave ccnet.exe running and open ccnet.config in your favourite editor.  Whenever we change and save this file it will force a restart of the continuous integration server so we'll get immediate feedback.  Modify it to look like this:

<cruisecontrol>

  <project>

    <name>CITest</name>

    <triggers>

      <intervalTrigger seconds="60" buildCondition="ForceBuild" />

    </triggers>

    <sourcecontrol type="vss">

       <project>$</project>

       <username>ccnet</username>

       <password>ccnet</password>

       <ssdir>\\%sourceserver%\vss</ssdir>

    </sourcecontrol>

    <tasks>

      <nant>

        <executable>C:\Projects\CI\nant-0.85-rc3\bin\nant.exe</executable>

        <buildFile>cruise.build</buildFile>

        <targetList>

          <target>run</target>

        </targetList>

      </nant>

    </tasks>

  </project>

</cruisecontrol>

 

We have created a "project" element containing three other elements:

·         triggers – which tells CruiseControl.NET what sort of source code repository checks to perform.  We have asked that a build be forced every 60 seconds.  Later on we'll modify this to check the source code repository for changes.

·         sourcecontrol - which tells CruiseControl.NET which source code repository to monitor for changes

·         tasks -  which describes the NAnt binary and build script to run when changes are detected.  We don’t have the NAnt build script yet, but that doesn’t matter right now.

Let’s look at the file in detail.

Configure Visual SourceSafe

We have added a "sourcecontrol" element for Visual SourceSafe.  This is often the tricky part of CruiseControl.NET configuration.  You should note the following:

·         The "project" element is required.  I have initially set its value to “$” representing the root project in Visual SourceSafe.  We don’t have our own SourceSafe project yet.  When we do, we'll change this value.

·         The "username" and "password" elements are also required.  If they don’t refer to a valid SourceSafe user name with a valid password then CruiseControl.NET will freeze while displaying output which looks something like this:

 

...

...

[CITest:Debug]: Executing process D:\Program Files\Microsoft Visual Studio\VSS\win32\ss.exe history $ -R -Vd03/12/2005;22:00~03/12/2005;21:55 -Yccnet,badpassword -I-Y in C:\Projects\CI\CruiseControl.NET\server\CITest\WorkingDirectory

...

...

 

This is because (unseen by you) the SourceSafe command line application (ss.exe) is attempting to prompt you for a valid password!  You will need to break out of ccnet.exe and possibly kill ss.exe in task manager.  So set up a build user and password for CruiseControl.NET using SourceSafe Administrator, or input your own login credentials.

·         It’s a good idea to set the "ssdir" element, even though things should still work correctly without it as ss.exe will extract the server details from your build server’s copy of srcsafe.ini.  It appears to be able to locate this file by stepping up one directory in the hierarchy from where ss.exe is running!  The content of the element should be the name of the folder containing your database’s srcsafe.ini file.  Here the folder is shared as “vss” on the machine we’ve named %sourceserver%.

·         There is also an optional "executable" element which supplies ccnet with the path to ss.exe.  If you don’t supply one ccnet does some peeking in the registry to extract the path to your ss.exe, so I don’t personally bother with it.

 

Save the ccnet.config file.  Your console output should change immediately to something which contains lines like this.

 

 [CruiseControl Server:Debug]: Error loading buildfile.

[CruiseControl Server:Debug]:     Could not find file "C:\Projects\CI\CruiseControl.NET\server\CITest\WorkingDirectory\cruise.build".

 

Let's view our failure in the Web Dashboard.

The Web Dashboard

There is no initial configuration required for the Web Dashboard.  Simply navigate to http://%buildserver%/ccnet in a browser.  You’ll be able to see the CITest project and view details of the failure.

Now let’s fix that build file problem.

First Successful Build

We told CruiseControl.NET that:

·         there was a build file called “cruise.build”

·         the build file contained a target called “run”

 

This was all lies.  Let’s remedy the situation.  Create the cruise.build file in C:\Projects\CI\CruiseControl.NET\server\CITest\WorkingDirectory.  Mine looks like this:

<?xml version="1.0"?>

<project default="run">

  <target name="run">

  </target>

</project>

 

This should be enough to get us going.  The next time ccnet goes through a cycle I get this:

[CITest:Info]: No modifications detected.

[CITest:Info]: Build forced

[CITest:Info]: Building

[CITest:Info]: Build complete: Success

[CITest:Info]: Integration complete: 04/05/2005 22:44:14

 

Excellent!  Refresh the Web Dashboard and you’ll be able to gloat over your success.

CCNet System Tray Application

In fact I’m so pleased that I want to view my successful build another way.  Let’s set up the CCTray application.  CCTray uses .NET remoting to communicate with the build server.

We will need to tell CruiseControl.NET the URL for our particular project so that cctray can jump straight to that project's web page.  To do this add a "webURL" element to ccnet.config like this:

<cruisecontrol>

  <project name="CITest">

    <name>CITest</name>

<webURL>http://%buildserver%/ccnet/default.aspx?

_action_ViewProjectReport=true&amp;

server=local&amp;project=CITest</webURL>

...

...

I obtained this by viewing the CITest web page and pasting its URL into the config file, using &amp; in place of ampersands.

Now run the cctray.exe application on your client machine. (Tip: we add cctray.exe to our startup folder so that it is always running).

Double click on its system tray icon to bring up the application's main window then select Settings... from the File menu.

Now click on the Add... button to add our build server.  In the next dialog type the name of the build server in the input box and click on the Add Server button.  Select CITest from the projects list on the right and click OK.  You should now see our build server in the list on the main settings dialog.  Click OK.

Now the icon will go red if a failed build occurs.  You can also force a build by launching the main window and right clicking on the list entry for our project.  Cool!

What’s Next

Let’s summarise what we have achieved so far and what the final steps will be.  We have:

·         Configured the CruiseControl.NET continuous integration server (ccnet.exe) using the ccnet.config file.  This is nearly complete for the purposes of our project.  We are currently forcing a build every 60 seconds so that we don't have to modify our code in order to kick off a build.

·         Configured the CruiseControl.NET Web Dashboard so that it displays the results of our builds.

·         Configured the CruiseControl.NET system tray application (cctray.exe) so that remote clients are informed of build results and can view the status of their project in a browser.

 

Let's change the configuration so that CruiseControl.NET only runs a build when the source code repository changes.  It will then execute NAnt with our cruise.build file.  What we do inside the build file is up to us.  We are going to:

·         Clean the build directory for our project

·         Get the latest source code from the repository and compile it

·         Run tests

 

Remove Force Build

Modify the "triggers" element it so that it looks like this:

<cruisecontrol>

  <project name="CITest">

    <name>CITest</name>

    <webURL>http://localhost/ccnet</webURL>

    <triggers>

      <intervalTrigger seconds="60" />

    </triggers>

...

...

 

We have removed the force build.  From now on we will rely on checkins to start the integration process.

Add a Visual Studio .NET Project

Create a C# class library project with Visual Studio .NET called CITest.  Place it in your normal projects location – not under the CI directory.  Don’t add any code – just check that it builds.  Now, using Visual Studio, add your project to source control under the root SourceSafe project, so that we can reference its project path as "$/CITest" in our ccnet.config file.  (Tip:  When the "Add to SourceSafe Project" dialog pops up in Visual Studio, clear the "Project" text box completely, select the "$/" node and press OK.  A project named CITest will then be correctly added under the root.  If you type "CITest" in this box, you'll end up with a project called $/CITest/CITest!)

Now modify the "project" element within the "sourcecontrol" element of our ccnet.config file as follows:

<cruisecontrol>

  <project name="CITest">

...

...

    <sourcecontrol type="vss">

      <project>$/CITest</project>

...

...

 

You should still have a successful build!

Now we are going to modify the cruise.build file to clean the build directory, get the source and compile it.

Backtracking to NAnt

We are going to run NAnt directly against our cruise.build file for a while.  Remember that this is all that CruiseControl.NET does – so when we've got it all working smoothly we can just plug it back again.  In the meantime we will get a bit more help with diagnostics from the output produced by NAnt.

It is very useful, whenever you're experiencing problems with CruiseControl.NET, to run NAnt directly against your build file, so this technique may well save you a lot of time somewhere down the line.  if you're really having problems try running it with the "–verbose" option.

Create a batch file called startnant.bat in the C:\Projects\CI directory and insert the following line:

nant-0.85-rc3\bin\nant.exe -buildfile:CruiseControl.NET\server\CITest\WorkingDirectory\cruise.build

This will execute NAnt against our cruise.build file.  Stop CruiseControl.NET and execute startnant.bat.  You will see this:

 

NAnt 0.85 (Build 0.85.1932.0; rc3; 16/04/2005)

Copyright (C) 2001-2005 Gerry Shaw

http://nant.sourceforge.net

 

Buildfile: file:///C:/Projects/CI/CruiseControl.NET/server/CITest/WorkingDirectory/cruise.build

Target framework: Microsoft .NET Framework 1.1

Target(s) specified: run

 

 

run:

 

 

BUILD SUCCEEDED

 

Total time: 0.1 seconds.

 

Now modify cruise.build so that it deletes and creates a "Source" directory in which we are going to get and build our source.  It will now look like this:

<?xml version="1.0" ?>

<project default="run">

  <target name="run" depends="clean">

  </target>

  <target name="clean">

    <delete dir="Source" failonerror="false" />

    <mkdir dir="Source" />

  </target>

</project>

 

When you run startnant.bat it will delete the Source directory (if it exists) then create it.  Now add a target which uses the vssget task from NAntContrib to get the source from SourceSafe:

<?xml version="1.0" ?>

<project default="run">

  <target name="run" depends="get">

  </target>

  <target name="get" depends="clean">

    <vssget username="ccnet"

            password="ccnet"

            localpath="Source"

            recursive="true"

            replace="true"

            writable="false"

            dbpath="\\%sourceserver%\vss\srcsafe.ini"

            path="$/CITest"/>

  </target>

  <target name="clean">

    ....

</project>

 

The "srcsafe.ini" at the end of the "dbpath" attribute isn't required if you're using a UNC path to access your source control server.  Check that you're getting the source correctly by running startnant.bat.  At the end of the build the CITest directory should contain a copy of the source.

Finally add a target to build the solution file:

<?xml version="1.0" ?>

<project default="run">

  <target name="run" depends="build">

  </target>

  <target name="build" depends="get">

    <solution configuration="debug" solutionfile="Source\CITest.sln" />

  </target>

  <target name="get" depends="clean">

    ...

    ...

</project>

 

Notice that each time we modify the file we change the dependencies.  The targets will be run by NAnt in the following order:

·         clean

·         get

·         build

 

Later on we'll run a test target.  Note that I haven't used any NAnt properties in my build file.  I leave this for you to play with later.

When you run startnant.bat you should now see:

NAnt 0.85 (Build 0.85.1932.0; rc3; 16/04/2005)

Copyright (C) 2001-2005 Gerry Shaw

http://nant.sourceforge.net

 

Buildfile: file:///C:/Projects/CI/CruiseControl.NET/server/CITest/WorkingDirectory/cruise.build

Target framework: Microsoft .NET Framework 1.1

Target(s) specified: run

 

clean:

 

   [delete] Deleting directory 'C:\Projects\CI\CruiseControl.NET\server\CITest\WorkingDirectory\Source'.

    [mkdir] Creating directory 'C:\Projects\CI\CruiseControl.NET\server\CITest\WorkingDirectory\Source'.

 

get:

 

   [vssget] Getting '$/CITest' to 'C:\Projects\CI\CruiseControl.NET\server\CITest\WorkingDirectory\Source'...

 

build:

 

 [solution] Starting solution build.

 [solution] Building 'CITest' [Debug] ...

 

run:

 

 

BUILD SUCCEEDED

 

Total time: 1.1 seconds.

Now restart ccnet and cctray.  You should still have a successful build.  If not, view the NAnt log (by clicking on the “View Build Log” link in the Web Dashboard) to find out the reason.

Once you have everything running smoothly, try breaking the build by checking out a file from the CITest project, adding a compilation error and checking it in again.  CruiseControl.NET will detect the modification and the build will fail.  Fix it!

NAnt and Assembly References

In previous versions of NAnt there were often problems when referencing third party assemblies installed in the GAC.  These seem to be resolved in the latest version (at least in the case of NUnit) so the simplest thing for us to do in order to be able to write some tests is:

·         add a reference to the nunit.framework assembly in the CITest directory by using the ".NET" tab "Add Reference" dialog.

 

Add a Test

Modify your Class1.cs to look something like this:

using System;

using NUnit.Framework;

 

namespace CITest

{

  /// <summary>

  /// Summary description for Class1.

  /// </summary>

  [TestFixture]

  public class Class1

  {

    public Class1()

    {

      //

      // TODO: Add constructor logic here

      //

    }

 

    [Test]

    public void ThisTestWillDefinitelyFail()

    {

      Assert.Fail("This test fails and I expect Cruise Control to display this message");

    }

  }

}

 

Now modify the cruise.build file one last time to run any test fixtures present in your dll.  Here is the final version of cruise.build, with the modifications highlighted:

<?xml version="1.0" ?>

<project default="run">

  <target name="run" depends="test">

  </target>

  <target name="test" depends="build">

    <nunit2>

      <formatter type="Xml" />

      <test assemblyname="Source\bin\debug\CITest.dll" />

    </nunit2>

  </target>

  <target name="build" depends="get">

    <solution configuration="debug" solutionfile="Source\CITest.sln" />

  </target>

  <target name="get" depends="clean">

    <vssget username="ccnet"

            password="ccnet"

            localpath="Source"

            recursive="true"

            replace="true"

            writable="false"

            dbpath="\\desktop\vss\srcsafe.ini"

            path="$/CITest"/>

  </target>

  <target name="clean">

    <delete dir="Source" failonerror="false" />

    <mkdir dir="Source" />

  </target>

</project>

 

I’ve added a target which runs NUnit against our assembly.  I’ve specified the “Xml” formatter, as CruiseControl.NET expects XML output.

Check in the code and run startnant.bat to check the cruise.build file.  You should see output ending like this:

...

...

   [nunit2] <failure>

   [nunit2] <message><![CDATA[This test fails and I expect Cruise Control to display this message]]></message>

   [nunit2] <stack-trace><![CDATA[   at CITest.Class1.ThisTestWillDefinitelyFail() in c:\Projects\CI\CruiseControl.NET\server\CITest\WorkingDirectory\Source\Class1.cs:line 22

   [nunit2] ]]></stack-trace>

   [nunit2] </failure>

   [nunit2] </test-case>

   [nunit2] </results>

   [nunit2] </test-suite>

   [nunit2] </results>

   [nunit2] </test-suite>

   [nunit2] </results>

   [nunit2] </test-suite>

   [nunit2] </test-results>

   [nunit2]

 

BUILD FAILED

 

C:\Projects\CI\CruiseControl.NET\server\CITest\WorkingDirectory\cruise.build(6,6):

Tests Failed.

 

Total time: 1.7 seconds.

 

Exactly what we want.  Your ccnet build should fail, and you will see the test failure displayed in the web application.  Now modify Class1 by adding the [Ignore] attribute like this:

    [Ignore("I wanna successful build")]

    [Test]

    public void ThisTestWillDefinitelyFail()

    {

      Assert.Fail("This test fails and I expect Cruise Control to display this message");

    }

 

Sit back and relax.  Your next build will succeed.  You will be able to see the ignored test in the Web Dashboard output.  We’re done!

Now that we have a working continuous integration system there are lots of possible refinements.  I won’t attempt to cover them all, but here are some candidates in no particular order of priority.

Running the CruiseControl.NET Service

An easy one this – just stop running ccnet.exe and start the Windows Service instead.  The output that we have been viewing via the console is still logged to a file called ccnet.log in the CruiseControl.NET\server directory.

Adding Visual Studio Projects

Don't forget that as you add more projects to your solution you will need to add a new "test" element to cruise.build, otherwise your tests won't be run!

Also if you want to use application configuration files (as many people do when using NUnit) you will need to reference them within your "test" element like this:

  <test assemblyname="CITest\bin\debug\CITest.dll" appconfig="CITest\bin\debug\CITest.dll.config" />

 

Adding Multiple CruiseControl Projects

Very handy this – multiple projects handled by the same build server – and/or multiple build servers managed by a single Web Dashboard.  See the CruiseControl.NET documentation for more detail.

Merging NAnt Output

For more control over the output from your build script send it to files and combine the files with the CruiseControl.NET log using a merge task.  This involves changing the "formatter" element in the cruise.build file so that it sends output to files:

<formatter type="Xml"

    usefile="true"

    extension=".xml" />

 

and adding a publishers element to the ccnet.config file so that it merges these files into the log:

...

    <publishers>

      <merge>

        <files>

          <file>Source\bin\debug\*-results.xml</file>

        </files>

      </merge>

      <xmllogger />

    </publishers>

  </project>

</cruisecontrol>

 

Note also that we have added a xmllogger publisher.  This is the default publisher used by CruiseControl.NET and is automatically used if you don't create a publishers element in the ccnet.config.  Once, however, you start to specify publishers you need to include it.  It also needs to be after the merge element.

Bootstrapping NAnt

In our team we maintain two NAnt build scripts.  The first one just cleans the build directory and gets the latest source from the repository.  Included in the latest source is the second build script, which is invoked from the first.  The second script compiles the source and runs the tests.

The advantage of this approach is that we can maintain the second build script as a solution item and modify it (for example by adding a new "test" element) whenever we add a new project to the solution.  When the solution is checked in CruiseControl.NET will automatically perform the modified build.

Summary

Any effort you invest in setting up CruiseControl.NET is repaid many times over, and I hope that this article has helped you on your way.

Post a Comment