I haven’t found a comprehensive article about running CruiseControl.Net under Mono, with the intention of building Mono code entirely on GNU/Linux in a daily build routine. I found bits and pieces here and there, so here’s my take on getting it running from start to finish.
This article assumes that you have a working knowledge of Mono, .Net, and the GNU/Linux command interface. For reference, I am using Ubuntu Server 10.10 Maverick.
0. A note about the code in this blog post
Some of the commands and lines of code in this blog post are ridiculously long. You won’t get the line breaks right unless you copy and paste the whole code block, so do just that and don’t retype the commands by hand. The blog post format breaks the lines to make the other half of certain long commands look like a new command. Retyping them like that would result in Bad And Unpredictable Things.
If you want to preview the code, paste it into a text editor.
With that said, let’s go:
1. Getting the binaries in place
First, we get the CruiseControl.Net binaries. I choose to put them under /opt/ccnet/bin and the Dashboard under /var/www/ccnet-dashboard. Log on to the server, go to your home directory, and become root:
sudo su
Then, fire off this sequence that downloads CruiseControl.Net, unpacks it, and places the server and dashboard in their folders:
mkdir ccnet-temp
cd ccnet-temp
wget http://downloads.sourceforge.net/project/ccnet/CruiseControl.NET%20Releases/CruiseControl.NET%201.6/CruiseControl.NET-1.6.7981.1.zip?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fccnet%2Ffiles%2FCruiseControl.NET%2520Releases%2FCruiseControl.NET%25201.6%2F&ts=1305836389&use_mirror=freefr
apt-get install unzip
unzip CruiseControl.NET-1.6.7981.1.zip?r=http:%2F%2Fsourceforge.net%2Fprojects%2Fccnet%2Ffiles%2FCruiseControl.NET%20Releases%2FCruiseControl.NET%201.6%2F
mkdir /opt/ccnet
mv Server /opt/ccnet/bin
mv WebDashboard /var/www/ccnet-dashboard
One thing here that’s important is that you do not download NAnt and put it in the same directory for convenience. It uses a different version of log4net.dll and you’ll get a ton of Exceptions From Hell with regards to missing functions.
Yes, DLL Hell can exist under Mono, too. In a limited version.
Besides, we won’t need NAnt.
2. Configuring the Dashboard
Setting up the Dashboard is really just a matter of setting up a standard Mono site, with one exception. We need to adjust a couple of paths.
cd /var/www/ccnet-dashboard
nano dashboard.config
Find those lines under <xsl> … </xsl> a bit down which contain paths. You will find that they use backslash as a path separator, like so:
<xslFile>xsl\header.xsl</xslFile>
This, of course, is a no-no. Change the slashes in these description to a forward slash. We’re on Unix now.
<xslFile>xsl/header.xsl</xslFile>
Also, while we’re editing this file anyway, insert the following line immediately after the header.xsl line, so that it becomes the second of three xsl lines. It will become clear later why. Rather than returning to edit this file when we’re discussing that problem later, it’s easier to just do it now.
<xslFile>xsl/msbuild2ccnet.xsl</xslFile>
Press Ctrl+O to save and Ctrl+X to exit.
3. Configuring the Server
This is the hairy part. For now, I won’t go into details about how to run ccnet as a daemon. That may come as an addendum. Once the process runs, as root, then the rest is no longer a porting issue. I will take us to the part where ccnet is running and building code using xbuild, the mono equivalent of msbuild.
If you are anything like me, you have already tried running ccnet.exe just to see if it runs (try first, read instructions later). It doesn’t. It croaks on a number of exceptions. We’ll deal with these. The first is some blahblah log4net Appender Console problem.
This problem stems from the fact that CruiseControl.Net likes to print to the console in color, but this is not supported in Mono. So we’ll need to dig into the server config file (which is different from the ccnet config file).
cd /opt/ccnet/bin
nano ccnet.exe.config
The first thing we’ll find there is something else we’ll need to fix, so we’ll do so while we’re at it. It’s the Windows backslash again in a couple of XSL file paths.
You’ll see a couple of lines looking like
<file name=”xsl\header.xsl”/>
…which need to change to
<file name=”xsl/header.xsl”/>
The difference is in the slash.
Also, replace the file name compile.xsl with msbuild2ccnet.xsl just like the one we added in the Dashboard, for reasons that will become clear later.
When this is done, you need to go through the rest of the config file and change backslashes in paths to forward slashes. There are three more of them spread out in the file, referring to log or trace files looking like ${TMP}\ccnet.log.
Done? Good. Let’s solve that exception above, then. The problem is about halfway through this file, in something referring to ColoredConsoleAppender.
<appender name=”Console” type=”log4net.Appender.ColoredConsoleAppender”>
Change the class name to just log4net.Appender.ConsoleAppender, and delete all the <mapping> sections underneath (Ctrl+K deletes a line in nano).
Ctrl+O, Ctrl+X to save and exit. We can now run
mono ccnet.exe
and it will start without exceptions. But it has no code or projects yet. Hit Ctrl+C to exit ccnet.exe.
4. Setting the project and source repositories
Time to edit ccnet.config.
This is straightforward, just like ccnet on Windows. I choose to build under /home/ccnet/{projectname}/build, and put artifacts in /home/ccnet/{projectname}/artifact. Create your project build folders as appropriate. Also, add some preliminary triggers. Here’s the relevant part of my ccnet.config, adapt as appropriate and insert into yours:
<project name="Activizr"> <workingDirectory>/home/ccnet/Activizr/build</workingDirectory> <artifactDirectory>/home/ccnet/Activizr/artifact</artifactDirectory> <webURL>http://build.activizr.com/server/kestrel/project/Activizr/ViewLastBuildReport.aspx</webURL> <sourcecontrol type="svn"> <trunkUrl>svn://peregrine/Activizr/trunk</trunkUrl> <workingDirectory>/home/ccnet/Activizr/build</workingDirectory> <cleanCopy>true</cleanCopy> </sourcecontrol> <triggers> <intervalTrigger name="continuous" seconds="30" /> </triggers> </project>
Do try to run
mono ccnet.exe
with your config, just to see that the code checks out. It won’t build, because there are no build tasks yet, but test it this far anyway. As there are no build tasks, everything will succeed and ccnet will report a success in the Dashboard.
5. Getting the code to build
Getting the code to build using xbuild, the equivalent of msbuild, was the hardest part to figure out. Ccnet requires XML logging of the build to function correctly, and on Windows systems, the logger parameter has this syntax:
/logger:class,assembly;outputfile
When passing this to xbuild, it would complain that the output file did not exist. Of course it didn’t. It’s supposed to be an output file. I was tearing my hair at permissions until I realized the problem was in the semicolon, which is a command separator in the Unix shell. It was trying to run the outputfile as a separate command! So the msbuild task can’t be used at all, and we need an alternate logger which has a default output file.
Fortunately, there is one. This is where that msbuild2ccnet.xsl style sheet comes in.
While still in /opt/ccnet/bin, run
wget http://confluence.public.thoughtworks.org/download/attachments/6253/Rodemeyer.MsBuildToCCnet.dll?version=5
mv Rodemeyer.MsBuildToCCnet.dll\?version\=5 Rodemeyer.MsBuildToCCnet.dll
Then, download the new logger’s style sheets and place them in the server and dashboard xsl folders:
cd xsl
wget http://confluence.public.thoughtworks.org/download/attachments/6253/msbuild2ccnet.xsl?version=2
mv msbuild2ccnet.xsl\?version\=2 msbuild2ccnet.xsl
cp msbuild2ccnet.xsl /var/www/ccnet-dashboard/xsl
cd ..
Phew, that’s a lot of tweaking. But now, we can finally run xbuild as an exec task. Afterwards, we merge the new logger’s output into the master ccnet log. Open ccnet.config again.
nano ccnet.config
Here are the tasks and publishers you need in ccnet.config for this. Put them as part of the <project>…</project> structure:
<tasks>
<exec>
<executable>xbuild</executable>
<baseDirectory>/home/ccnet/Activizr/build</baseDirectory>
<buildArgs>/logger:/opt/ccnet/bin/Rodemeyer.MsBuildToCCnet.dll</buildArgs>
<buildTimeoutSeconds>900</buildTimeoutSeconds>
<successExitCodes>0</successExitCodes>
</exec>
</tasks>
<publishers>
<merge>
<files>
<file>/home/ccnet/Activizr/build/msbuild-output.xml</file>
</files>
</merge>
<xmllogger />
</publishers>
This is also the explanation for the two other xsl files we changed before — the new logger.
After you’ve done this, you can start
mono ccnet.exe
and your project will check itself out, build, and report the results in the Dashboard.
6. Getting xbuild to build in Release mode
The xbuild utility has a bug which causes it to only build the first solution configuration. The solution is ugly: create a new solution configuration called “Autobuild” (or something else that comes before Debug) that copies from Release. No reason to create the config for all projects, just the solution.
That’s what I have discovered so far. This will probably be updated as I go…
Configuring and Running CruiseControl.Net under Mono http://bit.ly/l8rZ5E
It should be possible to run this as a separate, non-root user, if you change the installation directories.
That way, any security holes will hopefully not give the attacker root access.
You don’t need to change installation directories — you just need to change the ownership and permissions on these directories.
Configuring and Running CruiseControl.Net under Mono: http://is.gd/m2RXYA #mono – Another project that will probably change languages
Hi Rick
Thanks for this tutorial.
I have followed your steps but cannot get the webdashboard to work. I am using Ubuntu 12.04, Mono 2.10 and ccnet 1.67.
When visiting the website I get this error message:
Could not load type ‘ThoughtWorks.CruiseControl.Core.Config.Preprocessor.Evaluator’ from assembly ‘ThoughtWorks.CruiseControl.Core, Version=1.6.7981.1, Culture=neutral, PublicKeyToken=null’.
Any ideas on how to fix this?
I know that you posted this blog some time ago so I am also interested if you are still using ccnet with mono or something else now? I ask this because ccnet have released a new version (1.8) and it seems like they are not supporting mono. I have been looking for a while now for a builder server for mono that runs on ubuntu and so far this is the best I have found that is opensource.
Thanks
Liam
Hi Liam,
sorry to hear about your problem. Unfortunately, I haven’t run into your problem, nor am I still running ccnet on mono — the chief reason being that xbuild doesn’t have the AspNetCompiler, which I need in order to pack Resources into the assembly (Mono doesn’t grok the Resources namespace, unfortunately, so the website code must be pre-built).
I’m still running Mono for deployment, but for the reason above, I had to be dragged kicking and screaming into building on Windows.
For the record, though, do note that you don’t need the dashboard just to make daily (or continuous) builds work. You can have emails sent on builds if you like. That’s how I do it.
Cheers,
Rick
Hi Rick
Thanks for your response.
I still seem to be having other trouble with the ccnet build so as much as I am not a fan of it, building on windows could be an option. The packaging of resources for ASP.Net is also something that I would like to have.
If you don’t mind me asking what are you using to build on windows? Is it cruisecontrol.net?
Thanks
Liam