Keeping Automated Builds DRY

This is not the first time I came back to automated builds and re-evaluate how they are done. This time, I wanted to capture several things at the same time:

1. Specifications and Integration tests have to reside within the same project with the SUT, so that there's no need to maintain 2 separate projects structures and keep them in sync.

2. Ensure that visually we be determined if a class has Specifications or/and Integration tests (SomeClass.cs, SomeClass_Specs.cs, and SomeClass_Integration.cs)

3. Reuse the existing scripts generated by VS.NET for us

The last point is the key. Since VS.NET 2008 project files are actually MSBuild scripts. Good or bad, that's not important. What is important is that information about project and how to compile it already exists and we should be able to re-use it and not re-invent the wheel.

NAntContrib has MSBuild task. Sadly, it says that parameter is the solution file. In reality, it can be just a single project file, after all, it's just an MSBuild script. By running this task on an MSBuild file we can get all the work done for us. What we missing, is the ability to filter out Specs and Integration tests when we don't need those.

What would it look like? Example:

build –D: build.production.deployment=false

would compile all the specs/integ. Tests into the assembly

build –D: build.production.deployment=true

would not compile all the specs/integ. Tests into the assembly

How this would be done?

In nant script we would have something like this:

   1: <target name="compile.app" depends="prep">
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060">   2:</span>     <span style="color: #0000ff">&lt;</span><span style="color: #800000">msbuild</span> <span style="color: #ff0000">project</span><span style="color: #0000ff">=&quot;${app.proj}&quot;</span><span style="color: #0000ff">&gt;</span></pre>

<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060">   3:</span>       <span style="color: #0000ff">&lt;</span><span style="color: #800000">property</span> <span style="color: #ff0000">name</span><span style="color: #0000ff">=&quot;Configuration&quot;</span> <span style="color: #ff0000">value</span><span style="color: #0000ff">=&quot;${build.configuration}&quot;</span><span style="color: #0000ff">/&gt;</span></pre>

<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060">   4:</span>       <span style="color: #0000ff">&lt;</span><span style="color: #800000">property</span> <span style="color: #ff0000">name</span><span style="color: #0000ff">=&quot;OutputPath&quot;</span> <span style="color: #ff0000">value</span><span style="color: #0000ff">=&quot;${app.compile.dir}&quot;</span><span style="color: #0000ff">/&gt;</span></pre>

<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060">   5:</span>&#160;&#160;&#160; <span style="color: #0000ff">&lt;</span><span style="color: #800000">property</span> <span style="color: #ff0000">name</span><span style="color: #0000ff">=&quot;ProductionDeployment&quot;</span> <span style="color: #ff0000">value</span><span style="color: #0000ff">=&quot;${build.production.deployment}&quot;</span><span style="color: #0000ff">/&gt;</span></pre>

<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060">   6:</span>     <span style="color: #0000ff">&lt;/</span><span style="color: #800000">msbuild</span><span style="color: #0000ff">&gt;</span></pre>

<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060">   7:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">target</span><span style="color: #0000ff">&gt;</span></pre>

In project file, we would have to “filter” things that are not always will go into assembly in msbuild fashion:

   1: <ItemGroup>
<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060">   2:</span>     <span style="color: #0000ff">&lt;</span><span style="color: #800000">Compile</span> <span style="color: #ff0000">Condition</span><span style="color: #0000ff">=&quot;$(ProductionDeployment) == 'false' &quot;</span> <span style="color: #ff0000">Include</span><span style="color: #0000ff">=&quot;**\*_Specs.cs&quot;</span> <span style="color: #0000ff">/&gt;</span></pre>

<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060">   3:</span>     <span style="color: #0000ff">&lt;</span><span style="color: #800000">Compile</span> <span style="color: #ff0000">Condition</span><span style="color: #0000ff">=&quot;$(ProductionDeployment) == 'false' &quot;</span> <span style="color: #ff0000">Include</span><span style="color: #0000ff">=&quot;**\*_Integration.cs&quot;</span> <span style="color: #0000ff">/&gt;</span></pre>

<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060">   4:</span>     <span style="color: #0000ff">&lt;</span><span style="color: #800000">Compile</span> <span style="color: #ff0000">Condition</span><span style="color: #0000ff">=&quot;$(ProductionDeployment) == 'false' &quot;</span> <span style="color: #ff0000">Include</span><span style="color: #0000ff">=&quot;**\Infrastructure\Testing\*.cs&quot;</span> <span style="color: #0000ff">/&gt;</span></pre>

<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060">   5:</span>     <span style="color: #0000ff">&lt;</span><span style="color: #800000">Compile</span> <span style="color: #ff0000">Include</span><span style="color: #0000ff">=&quot;Properties\AssemblyInfo.cs&quot;</span> <span style="color: #0000ff">/&gt;</span></pre>

<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060">   6:</span>     <span style="color: #0000ff">&lt;</span><span style="color: #800000">Compile</span> <span style="color: #ff0000">Include</span><span style="color: #0000ff">=&quot;SomeComponent.cs&quot;</span> <span style="color: #0000ff">/&gt;</span></pre>

<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"><span style="color: #606060">   7:</span>     <span style="color: #0000ff">&lt;</span><span style="color: #800000">Compile</span> <span style="color: #ff0000">Include</span><span style="color: #0000ff">=&quot;IContract.cs&quot;</span> <span style="color: #0000ff">/&gt;</span></pre>

<pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"><span style="color: #606060">   8:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">ItemGroup</span><span style="color: #0000ff">&gt;</span></pre>

This would allow Visual Studio .NET to show the files, but have a conditional compiling. Reference would follow the same route (at this point they are always copied, but the result assembly is not referencing them if we set ProductionDeployment to true), I still have to figure out how to express that properly. Not sure how to apply same condition on the <Reference> elements. Ideas?

Bottom line - nant, rake, powershell, msbuild - it's all good. What is missed is the fact that we have assets we can take advantage, and not redo things that already there.

2 Comments

  • I'm still torn on this, and will be until there is an easy way to drop testing references from the projects. There must be, but they are sprinkled throughout my entire application now.

  • @David,
    dude, resistance is futile. I know deep deep inside you know it's right and can't resist. We shall get back to this conversation in a week when these builds are in your project ;)

Comments have been disabled for this content.