DRY your CruiseControl.NET Configuration

Don’t Repeat Yourself (DRY) is one of the principles of good software development. The idea is that there should ideally be one and only one “source of knowledge” for a particular fact or calculation in a system. Basically it comes down to not copying-and-pasting code around or duplicating code if at all possible. The advantages of this are many.

Advantages of DRY

  • There will be less code to maintain
  • If a bug is found, it should only have to be fixed in one place
  • If an algorithm or process is changed, it only needs to be changed in one place
  • More of the code should become reusable because as you do this you will parameterize methods to make them flexible for more cases

If it’s good for code isn’t it good for other things like configuration? Why yes it is.

Using CruiseControl.NET Configuration Builder

The Configuration Preprocessor allows you to define string properties and full blocks of XML to use for substitution and replacement. To start using the Configuration Preprocessor, you add xmlns:cb=”urn:ccnet.config.builder”, an xml namespace, to your document to tell the config parser that you plan to do this.

From there you can define a simple property like:


Or you can make it a full block of XML:


http://svn.example.com/svn/$(client)/$(project)/trunk D:\Builds-Net\projects\$(client)\$(project)\trunk
svn.exe
true


Defining Reusable Blocks

Using these ideas I wanted to come up with a templated approach that would allow me to share configuration among multiple projects. That way, if I added new statistics or change the layout of my build server, I would only have to change it in a single place. Thus keeping things DRY. It also encourages more consistency across multiple projects making things easier to understand.

So, I started defining some reusable blocks in the main ccnet.config file which you can see below. The exact details will depend on your configuration of course.

Full Example of config.xml




http://svn.example.com/svn/$(client)/$(project)/trunk D:\Builds-Net\projects\$(client)\$(project)\trunk
svn.exe
true



C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MSBuild.exe
D:\Builds-Net\projects\$(client)\$(project)\trunk

build.proj $(build-args)
$(build-targets)
600
D:\Program Files\CruiseControl.NET\server\Rodemeyer.MsBuildToCCNet.dll



C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe
D:\Builds-Net\projects\$(client)\$(project)\trunk

build.proj $(build-args)
$(build-targets)
600
D:\Program Files\CruiseControl.NET\server\Rodemeyer.MsBuildToCCNet.dll





D:\Builds-Net\projects\$(client)\$(project)\trunk\*.Test.xml
D:\Builds-Net\projects\$(client)\$(project)\trunk\*.CoverageMerge.xml
D:\Builds-Net\projects\$(client)\$(project)\trunk\*.CoverageSummary.xml
D:\Builds-Net\projects\$(client)\$(project)\trunk\*.FxCop.xml




D:\Builds-Net\projects\$(client)\$(project)\logs
















At the end of the file you can see the cb:include references. Those are one-line includes to include the configuration of each project. This makes things easier to manage, I think, because you only have to look at the individual project configuration.

Using Reusable Blocks in Individual Configuration Files

From there I need to make use of those defined blocks in in individual file. The first thing I needed to do was to set the parameters that I had defined as simple string replacements in the reusable blocks. Normally you would do that with cb:define as I showed above. But the trick is that you can only have one property with a given name defined. If you include multiple project configurations that doesn’t work. What does work is using cb:scope definitions. This allows for a value to be defined only within a specific scope.


client="ExampleClient"
project="SpecialProject"
build-args="/p:Configuration=Debug"
build-targets="Clean;Test">
...

From there you just need to start including the blocks that you defined in the main ccnet.confg within the scope block.

Full Example of Project Configuration

client="ExampleClient"
project="SpecialProject"
build-args="/p:Configuration=Debug"
build-targets="Clean;Test">













As you can see, the only one I didn’t template out was the email block because that depends on the developers working on each project.

Have fun bringing simplicity and consistency to your Cruise Control.NET configuration!

For the full details see the CruiseControl.NET Configuration Preprocessor documentation.

5 thoughts on “DRY your CruiseControl.NET Configuration”

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>