3.1. Install CruiseControl.NET
3.2. Create a CCNet Website in IIS
3.3. Install Nunit
4. CruiseControl.NET Server Configuration – General
5. Structure of a ‘Project’ Configuration File
6. Source Control Block
7. Trigger Block
8. Labeller Block
This article is the revised and updated version of an old one I wrote in 2008.
Following suggestions I will try to be shorter and focused.
I will review the various steps needed to setup and configure a working CruiseControl.Net server.
The goal is to set up a Continuous Integration process for a sample project as close as possible to a real-life project.
I will point out several issues that might arise and I will provide solutions as well.
I will try to underline all the details that you need to be aware of.
During the article I will guide you through the installation process of the following software:
The following are optional:
You can find information about how to install: Subversion, TortoiseSVN and AnkhSVN in the article: Guide to Versioning a Visual Studio Solution with Subversion, TortoiseSVN and AnkhSVN.
There you can also find a quick guide about how to create a Subversion repository and how to add a Visual Studio solution to source control.
This tutorial assumes that you have Subversion 1.9.7 installed and that you have configured a Subversion repository at the url: svn://localhost/trunk as shown in the article: Guide to Versioning a Visual Studio Solution with Subversion, TortoiseSVN and AnkhSVN.
If you already have a working environment with a repository and versioned files, you can go on reading and replace the paths and names in the examples with the paths and names in your environment.
This tutorial will assume that you install CruiseControl.NET on the same machine on which you had installed the Subversion repository. So, first of all, let’s go through the steps needed to install CruiseControl.NET on your server machine.
Download the latest CruiseControl.NET release from: SourceForge or the latest build from cruisecontrolnet.org.
For this article I used the installer for version 1.8.5 (CruiseControl.NET-184.108.40.206-Setup.exe), downloaded from the SourceForge website.
Run the setup executable file and follow the wizard. When prompted, you must configure it like in the following screenshots:
‘Install CC.Net server as windows service’ must be checked so that the setup will install CruiseControl as a Windows service.
In the Services management console the CruiseControl service will be displayed with the name: CruiseControl.NET.
‘Create virtual directory in IIS for Web dashboard’ will create a virtual directory named ccnet in the machine’s IIS web server. If you have an IIS server installation supporting multiple web sites (this is not the case for Windows XP Professional or Windows 10 Home) and prefer to have a separate web site for the CCNet web dashboard you should uncheck this option.
If this is your choice you will have to manually create a website in IIS showing the content of the folder: C:\Program Files (x86)\CruiseControl.NET\webdashboard.
In the next paragraph I will show you how to create an IIS 5.0 web site for the CruiseControl.NET web dashboard.
When the install process is finished all the content will be installed in the folder:
C:\%ProgramFiles%\CruiseControl.NET (e.g. C:\Program Files (x86)\CruiseControl.NET).
Under this path you will find a directory called server, containing all the CCNet binary files and executables, and a directory called webdashboard, containing the CruiseControl.NET web interface.
Here I will add and configure a Website in IIS for the CruiseControl.NET Webdashboard: the administrative interface of CruiseControl.NET.
Open IIS Manager in Administrative Tools, right-click on the Web Sites node and select New Web Site.
The Web site creation wizard will start.
Click Next and you will be prompted for a Web Site Description.
Type CCNet and click Next, leave Unassigned the IPAddress, choose a port number (say: 222) and leave empty the ‘Host Header for this site’ field, then click Next.
Choose C:\%ProgramFiles%\CruiseControl.NET\webdashboard as the path for the Website and click Next.
Allow ‘Read’ and ‘Run scripts’, the default, and click Next. The wizard is finished and the new Website created.
For more recent versions you will have to use IIS version specific actions to configure it in this way.
If you don’t have a full IIS version available you can use IISExpress. If you need a tool to configure it you can try: IISExpressGUI
For the sake of our example we will need Nunit so, if you haven’t already done, install it on the same machine on which you have installed CruiseControl.NET.
Unzip the content of the package in a folder of your choice, say: C:\%ProgramFiles%\NUnit
All the configuration files we’re going to talk about are placed or are to be placed in: C:\Program Files (x86)\CruiseControl.NET\server.
CruiseControl.NET comes with two server executables: ccservice.exe which is the windows service installed by the installation setup and ccnet.exe which is a console application included for testing purposes.
It is much easier to debug a console application that a service so I strongly suggest to make your initial tests with ccnet.exe and carefully read the console output to get familiar with CCNet behavior.
Each of the two executables comes with a default configuration file (i.e.: ccservice.exe.config and ccnet.exe.config) that you don’t need to change at the moment.
Moreover both the server processes (windows service or console application) look for a file named ccnet.config in which you will place all the actual information needed by CCNet to learn what it is supposed to do and how it is supposed to do it.
ccnet.config is an xml file with a root element named: cruisecontrol and a child element named: project, for each set of activities that we want CruiseControl.NET to execute, as shown in the following example:
<cruisecontrol xmlns:cb="urn:ccnet.config.builder"> <project name="project1"> ... </project> <project name="project2"> ... </project> </cruisecontrol>
We will setup our CruiseControl.NET configuration with two logical sets of activities.
For the sake of clarity we will benefit of the usage of xml entities.
We’ll define each ‘project’ configuration in a separate file and import all the files in ‘ccnet.config’ by means of entity definitions and entity declarations:
< !DOCTYPE cruisecontrol [ < !ENTITY project1 SYSTEM "file:project1.xml.config"> < !ENTITY project2 SYSTEM "file:project2.xml.config"> ]> <cruisecontrol xmlns:cb="urn:ccnet.config.builder"> &project1; &project2; </cruisecontrol>
Let’s focus, at first, only on the first project, so delete the second entity reference (i.e.: &project2; ) thus obtaining:
< !DOCTYPE cruisecontrol [ < !ENTITY project1 SYSTEM "file:project1.xml.config"> < !ENTITY project2 SYSTEM "file:project2.xml.config"> ]> <cruisecontrol xmlns:cb="urn:ccnet.config.builder"> &project1; </cruisecontrol>
Note that I specified an XML Namespace in the root
<cruisecontrol> xml tag. It refers to the namespace in which preprocessor directives are defined.
It will allow us, later, to use that namespace to:
– define constants to be expanded later, with the
– encapsulate sections that change the value of an existing constant, with the
What we need to do now is create a file named: project1.xml.config in C:\%ProgramFiles%\CruiseControl.NET\server and use it to setup CruiseControl.NET main activities.
This file will contain what is called the ‘Project Configuration Block’ for the first CCNet build that we want to configure.
First of all we need to assign a unique name to the root of the Project Configuration Block: the tag. We then write:
<project name="1 - testProject"> <webURL>http://192.168.15.2:222</weburl> <workingDirectory>C:\develop\CCnet\project1WorkingDir</workingDirectory> <artifactDirectory>C:\develop\CCnet\project1CCnetArtifacts</artifactDirectory> ... </project>
Let’s talk about the first three children nodes:
<webURL> represents the URL at which the current project is available through the web interface.
Make sure to set it to the IP of the server machine (in which you installed CCNet) and to the port that you chose for the WebDashboard website when you configured the web site in IIS (see: 3.2. Create a CCNet Website in IIS).
<workingDirectory> is the path to the main directory of this project and is meant to contain the checked out version of the project under integration.
This path will be accessible as an environment variable: %CCNetWorkingDirectory%, available to external scripts.
I use to place all the projects managed with CCNET in folders under a common directory named: C:\develop\CCnet.
For this test project I chose: C:\develop\CCnet\project1WorkingDir.
It is convenient to choose a directory in which to place all the stuff that will be used by CCNet (script files or executable files that you may want CruiseControl.NET to execute) as well as the workingDirectory in which CCNET will checkout the versioned files and the artifactDirectory in which it will output log files.
In the example above I chose the directory: C:\develop\CCnet as the container of all CCNet related stuff.
<artifactDirectory> is the path to the directory where all the build logs for this project will be placed.
Both the paths are subfolders of the common base directory. Here we can use a preprocessor constant.
We go back to the main file and define a constant that we will expand here.
The main file becomes:
< !DOCTYPE cruisecontrol [ < !ENTITY project1 SYSTEM "file:project1.xml.config"> < !ENTITY project2 SYSTEM "file:project2.xml.config"> ]> <cruisecontrol xmlns:cb="urn:ccnet.config.builder"> <cb:define name="BaseProjectsDir">C:\develop\CCnet</cb:define> &project1; </cruisecontrol>
The project file will then expand the newly defined variable with the following syntax: $(BaseProjectsDir)
<project name="1 - testProject"> <webURL>http://192.168.15.2:222</weburl> <workingDirectory>$(BaseProjectsDir)\project1WorkingDir</workingDirectory> <artifactDirectory>$(BaseProjectsDir)\project1CCnetArtifacts</artifactDirectory> ... </project>
Apart from the three tags described above, the main blocks that we’re going to add to the project configuration file are:
Source Control configuration block tells CruiseControl.NET that the project named ‘1 – testProject’ is bound to a Subversion repository.
This means that the task performed when executing this project depends on the status of that particular Subversion repository.
As soon as CruiseControl.NET detects a new revision in the repository it updates its working copy and executes the tasks related to the current project.
Here is the xml excerpt:
<sourcecontrol type="svn"> <trunkUrl>svn://localhost/trunk</trunkUrl> <executable>$(SubVersionExecutablePath)</executable> <workingDirectory>$(BaseProjectsDir)\project1WorkingDir</workingDirectory> <username>ccnetusername</username> <password>ccnetpassword</password> </sourcecontrol>
where we assume of having defined another variable in the main file:
<trunkUrl> contains the url of the repository that we want to check for modifications (e.g., svn://svnserver/pathToRepo).
As we saw in the post Guide to Versioning a Visual Studio Solution with Subversion, TortoiseSVN and AnkhSVN, Subversion could host several repositories under a common folder, say: C:\develop\TestRepo.
But in that article, as well as in the current example, we set up only one repository and run svnserve with the command line: svnserve -d -r “C:\develop\test\repo”.
So, specifying the server name (localhost) and the path to the particular repository we’re interested in, turns out to be simply: svn://localhost/trunk (instead of: svn://localhost/SpecificRepositoryFolder/trunk);
<workingDirectory> is the directory that will contain the working copy checked out by CCNET;
<executable> is the path to the Subversion client executable file to be used by Ccnet.
<timeout> sets the timeout for the source control operation. It defaults to 10 minutes and you can set it to a different amount of time in milliseconds (default) or specifying units (“millis”, “seconds”, “minutes”, “hours”); I left it out thus accepting the default.
If you want to set it to a different value remember to not choose a too short timeout value because if the timeout is exceeded the build will fail without providing information about the reason.
In that case the only way you can retrieve the actual reason of the build failing is by analyzing CCNET log file in the CruiseControl.NET\server folder (if you set log4net to the debug log level)
<password> must be set to a valid svn account that CCNET can use to access Subversion repository.
A trigger block is needed to specify when CruiseControl.NET will start a new integration cycle.
We want to check for the repository status continuously so we need an ‘Interval Trigger’ to tell CruiseControl.NET to perform integration periodically after a specified amount of time:
<triggers> <trigger type="intervalTrigger" name="continuousTrigger" seconds="600" buildCondition="IfModificationExists" initialSeconds="30" /> </triggers>
CruiseControl.NET, as far as project ‘1 – TestProject’ is concerned, polls the repository every 10 minutes to see if any changes has been committed.
The type attribute is used by CruiseControl.NET GUI to identify the type of trigger to be used. We use an intervaltrigger but it’s not the only one and they can be combined;
The name attribute is used by CruiseControl.NET GUI to identify the trigger that requested the build;
The seconds attribute is the amount of time before triggering the next integration cycle.
Each time the time interval elapses, CCNET checks for modifications and, by default, runs integration only if changes are detected.
The initialSeconds attribute is the amount of time before triggering the first integration cycle.
The buildCondition attribute tells to Ccnet if building always or only after a commit
A label is created, at each integration cycle, to identify the specific build occurred.
Different labellers can be used to generate the label that CCNet will use to track the builds.
Other than the Labeller Blocks that come with the CruiseControl.NET distribution, many people provided plugin Labeller Blocks to target the generation of labels with specific formats.
When I first wrote this post there was no assemblyVersionLabeller available in CruiseContro.net and I found a plugin, named SvnRevisionLabeller by David Keaveny (to which I contributed).
This plugin allows labelling CruiseControl.NET builds with Subversion’s repository revision numbers and I think this is a really useful feature. It can be still useful but not needed so I won’t use it in this post.
For detailed information about this plugin see my post: CruiseControl.NET and Subversion – SvnRevisionLabeller.
Below the configuration the Labeller Block using the assemblyVersionLabeller:
<labeller type="assemblyVersionLabeller"> <major>1</major> <minor>2</minor> <build>250</build> <revision>1765</revision> <incrementOnFailure>false</incrementOnFailure> </labeller>
The assemblyVersionLabeller will produce build labels in the format: major.minor.build.svnRevision
where major and minor are the two values you set in the configuration block while svnRevision is the current version in the Subversion’s repository related to this project.
The build number is automatically incremented each time a new build is forced if no further modification has been committed to the repository.
You can use in an external script the build label produced, which is stored in an environment variable.
It can be useful to flag release version of output dlls.
You can access the build number from a script with the syntax: %CCNetLabel% or from a C# application with the following row:
If you used the SolutionInfo approach in your Visual Studio solution (see my post: SolutionInfo and Partitioned Single Solution) you can use the build label produced by SvnRevisionLabeller to update the AssemblyFileVersion attribute in the SolutionInfo.cs file.
In this way you can provide consistent versioning of the released assemblies together with easy trackability of the corresponding source code’s revision.
Our Project configuration file will appear like this so far:
<project name="1 - testProject"> <webURL>http://192.168.15.2:222</weburl> <workingDirectory>$(BaseProjectsDir)\project1WorkingDir</workingDirectory> <artifactDirectory>$(BaseProjectsDir)\project1CCnetArtifacts</artifactDirectory> <state type="state" directory="$(BaseProjectsDir)\state" /> <sourcecontrol type="svn"> <trunkUrl>svn://localhost/trunk</trunkUrl> <executable>$(SubVersionExecutablePath)</executable> <workingDirectory>$(BaseProjectsDir)\project1WorkingDir</workingDirectory> <username>ccnetusername</username> <password>ccnetpassword</password> </sourcecontrol> <triggers> <trigger type="intervalTrigger" name="continuousTrigger" seconds="600" buildCondition="IfModificationExists" initialSeconds="30" /> </triggers> ... <labeller type="assemblyVersionLabeller"> <major>1</major> <minor>2</minor> <build>250</build> <revision>1765</revision> <incrementOnFailure>false</incrementOnFailure> </labeller> </project>
I did not talk about the
<state> tag. Just make sure to configure it. It will be used by CCNET to store the result of the last build.