I consider myself a neophyte when it comes to continuous integration (CI), but having read up on the topic, “played around” a bit, reviewed a couple of products, and having now incorporated it into our standard development practices, I am starting to hold my own. If nothing else, the benefits of continuous integration are now obvious and, well, I can’t imagine ever turning back.
For me, the power of continuous integration extends far beyond build validation. CI it has become a welcome management tool which allows me to keep my finger on the pulse of numerous developed products as well as individual developer contributions. Though I am very interested in the overall success/fail state of the current build, equally valuable is the the notifications which email specified team members the code change log which accompanies each build. (i.e. A list modified files and associated comments since the last automated build.) If you are responsible for overall project success (which typically includes management of deliverable, code quality, task distribution, etc) then continuous integration is for you.
As I mentioned earlier, I reviewed a few products. Last year, I reviewed FinalBuilder which provided me a nice and easy introduction into this space. Based almost completely on its popularly and price tag (free), I have since turned to CruiseControl.NET. I will not claim that was able to quickly get up and running with CruiseControl.NET. At times, I was down-right questioning if I was smart enough to figure out the product and its configuration. But, alas, it is now running on a dedicated build machine and my team and I are all the better for it.
Please let it be known that I am not a wizard when it comes to CruiseControl.NET. I am, however, good at is documentation of repeatable actions and I tried to capture the steps on getting started with CruiseControl.NET below. As always, any feedback is greatly appreciated.
By the way, if you are looking for general information on continuous integration or CruiseControl.NET, you are not going to find here. For more information, you may wish to consult the following: What is Continuous Integration and What is CruiseControl.NET.
That’s basically it. Best of luck!
1. Find a Build Machine
Though CruiseControl.NET could be installed on a development machine, I recommended that it be installed on a dedicated build server. Your build server should have access your source control repository and an optimal STMP server. The server should have IIS and the NET Framework installed as well. More information on the build server to follow…
2. Install CruiseControl.NET
Download CruiseControl.NET Server and Dashboard and install using provided default selections.
http://downloads.sourceforge.net/ccnet/CruiseControl.NET-1.3-setup.exe?modtime=1182463056&big_mirror=0
3. Install MSBuild
If you are working with .NET 2.0+ applications, you can build using MSBuild. Otherwise, you may need to learn a bit about NANT. All of the provided sample configurations below assume you will be using MSBuild.
The MSBuild DLL is not included in initial CCNET Server installation, but it can be downloaded from the ThoughtWorks site: http://ccnetlive.thoughtworks.com/MSBuildXmlLogger%2DBuilds/. To install, simply copy the ThoughtWorks.CruiseControl.MSBuild.dll into C:\Program Files\CruiseControl.NET\server\ location.
4. Install Source Control Client
You will potentially need to install your source control client on the build machine. For the samples provides, we are using Borland StarTeam 2005. CruiseControl.NET integrates with just about every source control system I could think of, so if you are using something other than StarTeam, you will want to consult the Source Control Block documentation.
5. CruiseControl.NET Server Configuration
CruiseControl.NET Server is driven by CCNET configuration file settings. After the fresh install, the configuration is essentially empty and requires manual updates to the ccnet.config file itself. As far as my knowledge, there is no associated configuration editor. First things first, crack open “C:\Program Files\CruiseControl.NET\server\ccnet.config” in Visual Studios or your favorite XML editor. (There is shortcut under All Programs > CruiseControl.NET > CruiseControl.NET Config.)
If you have a pre-configured ccnet.config file available, simply overwrite the file content. If you are starting from scratch, you may wish reference the online CruiseControl.NET configuration overview and review samples: http://confluence.public.thoughtworks.org/display/CCNET/Configuring+the+Server. Additional example configuration files were installed on your build box as well: C:\Program Files\CruiseControl.NET\Examples. They are worth a look.
The bad news: Though you will find examples sprinkled throughout the ThoughtWorks site and the locations noted above, you will most likely need to muck around with your own config file for a while until you get it right. Additional samples are provide below, but just as I wasn’t able to find the magic configuration combination to get my server running right off the bat, I bet you won’t either.
The good news: Getting the right configuration was trail-and-error process for me. I kept the configuration very simple at first and then built upon it. Hopefully the next steps can help you with your troubleshooting.
6. Start CruiseControl.NET Server
The CCNET Server is not started at the time of installation. Thus, you will need to start the service manually: Administrative Tools > Services > CruiseControl.NET Server > Select > Start the service.
If the service fails at startup, it will immediately stop and present the following generic dialogue:
The CruiseControl.NET Server service on Local Computer started and then stopped. Some services stop automatically if they have no work to do, for example, the Performance Logs and Alert service.
If you encounter this error your first stop is to consult the logs: C:\Program Files\CruiseControl.NET\server\ccnet.log. By default, the file contains verbose logging which is helpful (although somewhat difficult to navigate.) Believe me, the logs are your fried.
Based on the log file feedback, I suggest tweaking the ccnet.config file and then restarting the service – repeating until the service is fully configured. And, if it is easier for you, you may run the CCNET Server via the command window: CD C:\Program Files\CruiseControl.NET\server > ccnet.exe. This approach will render errors in the cmd window rather than having to monitor the ccnet.log file. It was a time saver for me at least.
Once the project is successfully setup, you will see something similar to the following listed in the logs:
· [CCNet Server:DEBUG] The trace level is currently set to debug. This will cause CCNet to log at the most verbose level, which is useful for setting up or debugging the server. Once your server is running smoothly, we recommend changing this setting in C:\Program Files\CruiseControl.NET\server\ccnet.exe.config to a lower level.
· [CCNet Server:INFO] Reading configuration file “C:\Program Files\CruiseControl.NET\server\ccnet.config”
· [CCNet Server:INFO] Registered channel: tcp
· [CCNet Server:INFO] CruiseManager: Listening on url:tcp://localhost:21234/CruiseManager.rem
· [CCNet Server:INFO] Starting CruiseControl.NET Server
· [PROJECTNAME:INFO] Starting integrator for project: PROJECTNAME
At this point, the Server is waiting to initiate the next build. Based on the config file <triggers> setting it could take a while to get the checkout and build to fire. Adjust the following setting to around 10 seconds while still in the testing phase:
<triggers>
<intervalTrigger name=“continuous“ seconds=“10”
buildCondition=“IfModificationExists“/>
</triggers>
On a similar note, the Server restarts itself automatically each time the ccnet.config file is modified.
7. Potential Gotchas
I ran into a couple specific cases while debugging which I suspect could be common issues.
1. Ensure the MSBuild timeout value allows enough time to the build to complete. This will otherwise return in a failure which wasn’t easy to troubleshoot.
<msbuild>
<timeout>600</timeout>
</msbuild>
2. For web solutions, update the TargetPath for the Debug and/or Release build of the application to be outside of the source application directory. Otherwise, you will receive the following error:
ASPNETCOMPILER : error ASPRUNTIME: The precompilation target directory cannot be in the same tree as the source application directory.
This can be done by modifying the following in the solution file:
Debug.AspNetCompiler.TargetPath = “c:\ccnet\PrecompiledWeb\SampleWeb\”
Release.AspNetCompiler.TargetPath = “c:\ccnet\PrecompiledWeb\SampleWeb\”
Alternative, one may update the Output location found in the application MSBuild properties.
You may be wondering why an updated solution won’t be updated with the next scheduled build. As it works out (and makes sense) only changes which are applied to source control are pulled onto the build box.
8. Automating Your Builds
Once the build process is running successfully, modify the <intervalTrigger> setting to a reasonable value and then update the “CruiseControl.NET Server” Service Startup Type to Automatic and then Start the service. I might suggest also crossing your fingers for the next day or so.
9. Monitoring Your Builds
The CCNet Web Dashboard Application is used for reporting a wide range of information. At one end of the scale it reports summary details of all projects being managed by CruiseControl.NET and at the other it can give specific metric output for any specific build. The Dashboard is setup with your initial installation. You may access the Dashboard application by navigating a location similar to the following: http://buildbox.com/ccnet/ViewFarmReport.aspx. For more information on the Web Dashboard: http://confluence.public.thoughtworks.org/display/CCNET/Web+Dashboard
The CCTray an optional utility for use with the CruiseControl.NET Continuous Integration server. It provides feedback upon build progress, and allows control over some of the server’s operations. As “optional utility” implies, the CCTray isn’t included with the base installation. You may download the Windows Tray Application from the following location and install using provided default selection: http://downloads.sourceforge.net/ccnet/CruiseControl.NET-CCTray-1.3-Setup.exe?modtime=1182463076&big_mirror=0. There isn’t much to using the CCTray but I do consider it a handy add-on. Basically, you will find a shortcut to the CCTray on your desktop. Launch the application to begin monitoring the automated build(s) status and schedule. The information provides via the CCTray is very similar to that which is provided in the Dashboard application. For more information on CCTray: http://confluence.public.thoughtworks.org/display/CCNET/CCTray.
Sample Configuration Files
If you have made it this far, I really, really hope your required configuration is similar to mine. If so, this is your golden ticket. I have provided two flavors of configuration files below. You will undoubted need to tweak the files a bit (replace the project locations and names along with credentials will obviously be required), but hopefully these will help get you started. By the way, the formatting of the XML leaves something to be desires as I have formatted to fit within the given real estate.
Windows Service, StarTeam, MSBuild, Emailing and Unit Tests
<cruisecontrol>
<project name=“SampleService“ queue=“Q1“ queuePriority=“0“>
<workingDirectory>c:\Projects\Services\SampleService
</workingDirectory>
<artifactDirectory>c:\ccnet\artifacts\Services\SampleService
</artifactDirectory>
<category>Continuous Builds</category>
<webURL>http://buildbox.com/ccnet/server/local/project/
SampleService/ViewProjectReport.aspx</webURL>
<triggers>
<intervalTrigger name=“continuous“ seconds=“600“
buildCondition=“IfModificationExists“/>
</triggers>
<state type=“state“ directory=“c:\ccnet\state“/>
<labeller type=“defaultlabeller“>
<prefix>Build-1.0.</prefix>
<incrementOnFailure>false</incrementOnFailure>
</labeller>
<sourcecontrol type=“starteam“>
<executable>c:\Program Files\Borland\StarTeam 2005\
stcmd.exe</executable>
<project>Project</project>
<username>user</username>
<password>password</password>
<host>10.1.10.100</host>
<port>11111</port>
<path>Projects/Services/SampleService</path>
<autoGetSource>true</autoGetSource>
</sourcecontrol>
<tasks>
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\
v2.0.50727\MSBuild.exe
</executable>
<workingDirectory>C:\Projects\Services\SampleService
</workingDirectory>
<projectFile>SampleService.sln</projectFile>
<buildArgs>/noconsolelogger /p:Configuration=Debug /v:m
</buildArgs>
<targets>Clean;Build</targets>
<timeout>600</timeout>
<logger>ThoughtWorks.CruiseControl.MsBuild.XMLLogger,
C:\Program Files\CruiseControl.NET\server\
ThoughtWorks.CruiseControl.MsBuild.dll</logger>
</msbuild>
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\
v2.0.50727\MSBuild.exe</executable>
<workingDirectory>C:\Projects\Services\SampleService
</workingDirectory>
<projectFile>UnitTestBuild.proj</projectFile>
<buildArgs>/noconsolelogger /p:Configuration=Debug /v:diag
</buildArgs>
<targets>Tests</targets>
<timeout>1500</timeout>
<logger>ThoughtWorks.CruiseControl.MsBuild.XMLLogger,
C:\Program Files\CruiseControl.NET\server\
ThoughtWorks.CruiseControl.MsBuild.dll</logger>
</msbuild>
</tasks>
<publishers>
<merge>
<files>
<file>c:\ccnet\artifacts\Services\SampleService\
mbUnit-testResults.xml</file>
<file>c:\ccnet\artifacts\Services\SampleService\
msbuild-results.xml</file>
</files>
</merge>
<xmllogger/>
<email from=“no-reply@buildbox.com“
mailhost=“localhost“ includeDetails=“TRUE“>
<users>
<user name=“User 1“ group=“BuildMaster“
address=“user.one@buildbox.com“/>
<user name=“user 2“ group=“TechLead“
address=“user.two@buildbox.com“/>
</users>
<groups>
<group name=“BuildMaster“ notification=“always“/>
<group name=“TechLead“ notification=“change“/>
</groups>
</email>
</publishers>
</project>
</cruisecontrol>
Web Application, StarTeam, MSBuild, Emailing, and Build Dependencies
<cruisecontrol>
<project name=“SampleWeb“ queue=“Q2“
queuePriority=“1“>
<workingDirectory>c:\Projects\Web\SampleWeb
</workingDirectory>
<artifactDirectory>c:\ccnet\artifacts\Web\SampleWeb
</artifactDirectory>
<category>Continuous Builds</category>
<webURL>http://buildbox.com/ccnet/server/local/project/
SampleWeb/ViewProjectReport.aspx</webURL>
<modificationDelaySeconds>15</modificationDelaySeconds>
<triggers>
<intervalTrigger name=“continuous“ seconds=“3600“
buildCondition=“IfModificationExists“/>
<projectTrigger project=“SampleData“>
<!– Force build when data component is successfully built. –>
<triggerStatus>Success</triggerStatus>
<innerTrigger type=“intervalTrigger“ seconds=“30“
buildCondition=“ForceBuild“/>
</projectTrigger>
</triggers>
<state type=“state“ directory=“c:\ccnet\state“ />
<labeller type=“defaultlabeller“>
<prefix>SampleWeb-Build-</prefix>
<incrementOnFailure>true</incrementOnFailure>
</labeller>
<sourcecontrol type=“starteam“>
<executable>C:\Program Files\Borland\
StarTeam Cross-Platform Client 2006 R2\stcmd.exe</executable>
<project>Project</project>
<username>user</username>
<password>password</password>
<host>10.1.10.100</host>
<port>11111</port>
<path>Projects/Web/SampleWeb</path>
<autoGetSource>true</autoGetSource>
</sourcecontrol>
<tasks>
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\
v2.0.50727\MSBuild.exe</executable>
<workingDirectory>C:\Projects\Web\SampleWeb
</workingDirectory>
<projectFile>SampleWeb.sln</projectFile>
<timeout>900</timeout>
<buildArgs