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:
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
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.
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
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!