<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Tegan Mulholland&#039;s Blog</title>
	<atom:link href="http://teganmul.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://teganmul.wordpress.com</link>
	<description>tech stuff</description>
	<lastBuildDate>Sat, 22 May 2010 00:29:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='teganmul.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Tegan Mulholland&#039;s Blog</title>
		<link>http://teganmul.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://teganmul.wordpress.com/osd.xml" title="Tegan Mulholland&#039;s Blog" />
	<atom:link rel='hub' href='http://teganmul.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Custom CruiseControl.NET publisher</title>
		<link>http://teganmul.wordpress.com/2010/05/22/custom-cruisecontrol-net-publisher/</link>
		<comments>http://teganmul.wordpress.com/2010/05/22/custom-cruisecontrol-net-publisher/#comments</comments>
		<pubDate>Sat, 22 May 2010 00:29:39 +0000</pubDate>
		<dc:creator>teganmul</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[CruiseControl.NET]]></category>
		<category><![CDATA[NUnit]]></category>

		<guid isPermaLink="false">http://teganmul.wordpress.com/?p=3</guid>
		<description><![CDATA[Recently my team got a new requirement to report our build and test results to a centralized Engineering Excellence system. They get most of their results directly from integration with TFS, but we run our builds and tests with CruiseControl &#8230; <a href="http://teganmul.wordpress.com/2010/05/22/custom-cruisecontrol-net-publisher/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=teganmul.wordpress.com&amp;blog=13787083&amp;post=3&amp;subd=teganmul&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Recently my team got a new requirement to report our build and test results to a centralized Engineering Excellence system. They get most of their results directly from integration with TFS, but we run our builds and tests with CruiseControl and NUnit. They provided us with a web service to send our results to.</p>
<p>Enter custom CruiseControl tasks. As of CruiseControl.NET 1.5, publishers are simply tasks placed in the &#8220;publishers&#8221; section of the project configuration.</p>
<p>The official CruiseControl.NET documentation explains <a title="CruiseControl.NET : Custom Builder Plug-in" href="http://builds.flexwiki.com/builds/doc/CCNET/Custom%20Builder%20Plug-in.html">how to create a custom task</a>. Kris has a very helpful blog post specifically on <a title="Adding a Custom Publisher to CruiseControl.NET" href="http://krisselden.com/2007/01/29/adding-a-custom-cruisecontrolnet-publisher/">creating a custom publisher</a>. Neither of them explain how to obtain the unit test results, so that&#8217;s what I want to show here.</p>
<p>Unit test results don&#8217;t show up in the integration result object passed to the task. To get the unit test results, you have to read them from the build log (luckily, it&#8217;s standard xml). Make sure to include a &lt;merge&gt; publisher that includes the NUnit results file in your project configuration <em>before</em> your custom publisher or the test results won&#8217;t be there.</p>
<div id="_mcePaste" style="position:absolute;left:-10000px;top:95px;width:1px;height:1px;overflow:hidden;">NetReflector.dll</div>
<pre>public void Run(IIntegrationResult result)
{
    if (result.Status != IntegrationStatus.Unknown)
    {
        string fn = new LogFile(result).Filename;
        string logFileName =
            StringUtil.RemoveInvalidCharactersFromFileName(fn);
        string logFileDir = result.BuildLogDirectory;

        string logFilePath = Path.Combine(logFileDir, logFileName);
        int totalTests;
        int failedTests;
        int testsNotRun;

        using (var fileStream = File.Open(logFilePath,
            FileMode.Open, FileAccess.Read))
        {
            XDocument doc = XDocument.Load(new XmlTextReader(fileStream));

            var testResultsList =
                doc.XPathSelectElements("//build//test-case");
            if (testResultsList != null)
            {
                foreach (var testResults in testResultsList)
                {
                    totalTests++;
                    string execAttr =
                        testResults.Attribute("executed").Value;
                    bool wasRun = bool.Parse(execAttr);

                    if (!wasRun)
                    {
                        notRun++;
                    }
                    else
                    {
                        string succAttr =
                            testResults.Attribute("success").Value;
                        bool succeeded = bool.Parse(succAttr);
                        if (!succeeded)
                        {
                            failedTests++;
                        }
                    }
                }
            }
        }
        // Do something with the results
    }
}</pre>
<p>The function StringUtil.RemoveInvalidCharactersFromFileName comes from CruiseControl.Core. A similar method of finding the log file path is used in some of the built in tasks. Once you have the location of the log file, you can easily use xpaths to parse any part of the test results. I wrote some code to filter specific test namespaces into the results so we can report on different sets of tests off of the same build.</p>
<p>If you&#8217;re interested in the overall build status, I would use IIntegrationResult.Status rather than LastIntegrationStatus. I believe LastIntegrationStatus actually refers to the previous rather than the current run.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/teganmul.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/teganmul.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/teganmul.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/teganmul.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/teganmul.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/teganmul.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/teganmul.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/teganmul.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/teganmul.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/teganmul.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/teganmul.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/teganmul.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/teganmul.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/teganmul.wordpress.com/3/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=teganmul.wordpress.com&amp;blog=13787083&amp;post=3&amp;subd=teganmul&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://teganmul.wordpress.com/2010/05/22/custom-cruisecontrol-net-publisher/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/dd98a2cc5ad2ba1c4c74f2b3c44d588a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">teganmul</media:title>
		</media:content>
	</item>
	</channel>
</rss>
