Motivation
The current way of using MSBuild with CCNet suffers from two problems. They worsen with the number of projects that are in the build.

1. If you have many projects or a big team, you probably have lots of warnings or error messages. The standard build report of Dashboard for MSBuild is just a list with no obvious order or relation to certain projects. This makes it hard to find the reason for breaking builds and to get control over the warning plague.
2. The size of a log file gets pretty big. In our case the log of a single build, with verbositiy set to minimal, takes more than 4 megabytes, not including additional output like UnitTest results. On average we have a build every 15 minutes for 8 hours per days, so we need 4MB * 4 * 8 * 5 = 640 MB per week. The waste of space is bad but in the dawn of terabyte sized hardidisks not the real problem. The bigger problem is the waste of time! The xsl transformations on such large files can take quite some time. In our case Dashboard and CCNet server run on a well equipped machine. Nevertheless, requesting the build report page takes several seconds. Now imagine several developers simultaneously requesting the report after a build has finished ...
My first thought was to modify the supplied compile-msbuild.xsl transformation. After analyzing the xml log content I realized, that grouping errors and warnings by project was a pain and finally I failed. So I decided to write my own logger for MSBuild to make life for xsl transformations easier. In addition this solved also the space and time problem. The results were really satisfying. The log size shrunk from over 4MB to under 50KB and the xsl transformation run lightning fast. The build report is now structured, with nice summaries in the header

Features
- small log files == fast transformation
- if errors are present => no warnings are displayed; projects are sorted by build order.
- if no errors are present => projects are sorted by the number of warnings they produced
- no errors or warnings => happiness
- total number of projects and warnings are displayed in the header
- pathes are stripped from the working folder
- message is formated as Error | Message | File
How to use
- Copy Rodemeyer.MsBuildToCCnet.dll to your \CruiseControl.NET\server folder
- Copy msbuild2ccnet.xsl to your \CruiseControl.NET\webdashboard\xsl folder
- Copy cruisecontrol.css to your \CruiseControl.NET\webdashboard folder
- If you have modified the dashboards stylesheet, just copy the section-project, section-error, section-warning, error and warning style.
- In your ccnet.config file locate the <msbuild> task. Change the <logger> node to
<logger>c:\Program Files\CruiseControl.NET\server\Rodemeyer.MsBuildToCCNet.dll</logger>
I highly suggest that you set the verbosity level to quiet or minimal to avoid excessive large log files!
<buildArgs>/v:quiet /noconlog /p:Configuration=Debug</buildArgs>
- In your dashboard.config file locate the <buildReportBuildPlugin> section. Remove the compile-msbuild.xsl and msbuild.xsl if present. Theses transformations are not compatible with the MsBuildToCCNet logger. Add the msbuild2ccnet.xsl transformation instead.
<buildReportBuildPlugin>
<xslFileNames>
<xslFile>xsl\header.xsl</xslFile>
<xslFile>xsl\msbuild2ccnet.xsl</xslFile>
<xslFile>xsl\modifications.xsl</xslFile>
[...]
Thats it! Just force a build and enjoy your new report.
Options
In the <buildArgs> you can specify the verbosity level for MSBuild. The MsBuildToCCNet logger interprets the different levels as follows:
| Quiet |
errors, warnings and number of projects are logged (minimal file size) |
| Minimal |
errors, warnings and one entry for every project |
| Normal |
like minimal plus messages with high importance |
| Detailed |
like normal plus messages with normal importance (not recommended) |
| Diagnostic |
like detailed plus messages with low importance (not recommended) |
Source
The complete source is attached to this page.
Updates
| 2007-03-01 |
Version 1.0.0.2 fixes a crash that occurs if msbuild warns about a reference to an non existant project |
| 2007-03-15 |
Version 1.0.0.3 uses msbuild-output.xml by default, as suggested by Markus Hastreiter, if not started by a ccnet msbuild task |
| 2007-10-01 |
Version 1.0.0.4 fixes a crash with errors that are not related to files (Found by Steven Smith) |
Great Logger! I first got an NullRerefence exception because I use NAnt instead of <msbuild> task and I didn't know that a logfile name is needed as first parameter.
<arg value="/logger:Rodemeyer.MsBuildToCCNet.MsBuildToCCNetLogger,c:\program files\CruiseControl.Net\server\Rodemeyer.MsBuildToCCnet.dll;${CCNetWorkingDirectory}\msbuild.log" />If one doesn't apply any logfile name base.Parameters is null and therefor you get the NullReference exception. My suggestion would be to support a default logfile name like
There is an issue when a warning contains a reference to a generic (List<string> e.g.). The logger deosn't escape the < and the > and throws an exception due to an unclosed tag.
The MSBuild Logger uses the XmlTextWriter.WriteAttributeString which does escape the "<" and the ">" arrows.
Alexey, could you please send me a log which contains the "unclosed tag" so that I can investigate this issue.
Christian, good work!
Just a minor issue: In my scenario (msbuild via nant) when using the target "Clean,Build" and have a warning for a project, the warning as well as informational messages (about the cleaning process) are part of the result of the xsl transformation.
When using this line
<xsl:apply-templates select="error|warning"/>instead of the original one without the select attribute in this block
<xsl:element name="td">
<xsl:attribute name="class">
<xsl:if test="../@error_count > 0">section-error</xsl:if>
<xsl:if test="../@error_count <= 0">section-warning</xsl:if>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:element>
everything the result looks as expected (without the messages but only with warnings and errors).
We build a big solution file (.sln) that contains lots of projects (.vcproj, .vbproj, .csproj).
Two build configuraitons for everything: "release|win32" and "debug|win32"
I'm would use two <msbuild/> statements to build with "/p:Configuration:Debug" and "/p:Configuration:Debug", respectively
People open the .sln to work on the code base.
I'd like to cluster the messages on 2 levels according to build config and project.
Could msbuild2ccnet help here?
From the little code I've seen, I'd have to change the logger, right?
I have configured everything a described here.
Still it seems, that XSLT-Transformations are not applied at all. I always see the raw xml.
Any suggestions?