I've seen a few examples on how to do build deployment, however I have something unique that I'd like to do:
Has anyone done this before with .NET projects using NAnt + CruiseControl.net?
Deploying a build to a folder with the build number is pretty straightforward. CruiseControl.NET's NAnt task automatically passes a number of properties to your NAnt script. The CCNetLabel property is the one you'd use to create your deployment directory. There's actually a slightly out of date example NAnt script in the CruiseControl.NET documentation that does just that. Here's a nicer version of it:
<target name="publish">
<if test="${not property::exists('CCNetLabel')}">
<fail message="CCNetLabel property not set, so can't create labelled distribution files" />
</if>
<property name="publishDirectory" value="D:\Public\Project\Builds\${CCNetLabel}" />
<mkdir dir="${publishDirectory}" />
<copy todir="${publishDirectory}">
<fileset basedir="${buildDirectory}\bin">
<include name="*.dll" />
</fileset>
</copy>
</target>
As far as versioning your binaries goes, I find the following approach much cleaner and easier than trying to alter your AssemblyInfo.cs files. Basically I create a CommonAssemblyInfo.cs file that lives outside of any projects, in the same directory as your solution file. This file includes things that are common to all assemblies I'm building, like company name, copyright info, and of course - version. This file is linked in each project in Visual Studio, so each project includes this info (along with a much smaller AssemblyInfo.cs file that includes assembly-specific info like assembly title).
When projects are built locally, either through Visual Studio or NAnt, that CommonAssemblyInfo.cs file is used. However, when projects are built by CruiseControl.NET, I use NAnt to replace that file via the <asminfo>
task. Here's what the NAnt script looks like:
<target name="version">
<property name="commonAssemblyInfo" value="${buildDirectory}\CommonAssemblyInfo.cs" />
<!-- If build is initiated manually, copy standard CommonAssemblyInfo.cs file. -->
<if test="${not property::exists('CCNetLabel')}">
<copy file=".\src\CommonAssemblyInfo.cs" tofile="${commonAssemblyInfo}" />
</if>
<!-- If build is initiated by CC.NET, create a custom CommonAssemblyInfo.cs file. -->
<if test="${property::exists('CCNetLabel')}">
<asminfo output="${commonAssemblyInfo}" language="CSharp">
<imports>
<import namespace="System" />
<import namespace="System.Reflection" />
</imports>
<attributes>
<attribute type="AssemblyCompanyAttribute" value="My Company" />
<attribute type="AssemblyCopyrightAttribute" value="Copyright © 2008 My Company" />
<attribute type="AssemblyProductAttribute" value="My Product" />
<attribute type="AssemblyVersionAttribute" value="1.0.0.${CCNetLabel}" />
<attribute type="AssemblyInformationalVersionAttribute" value="1.0.0.${CCNetLabel}" />
</attributes>
<references>
<include name="System.dll" />
</references>
</asminfo>
</if>
</target>
<target name="build-my-project" depends="version">
<csc target="library" output="${buildDirectory}\bin\MyProject.dll">
<sources>
<include name=".\src\MyProject\*.cs"/>
<include name=".\src\MyProject\**\*.cs"/>
<include name="${commonAssemblyInfo}"/>
</sources>
</csc>
</target>
Note where the AssemblyVersionAttribute and AssemblyInformationalVersionAttribute values are set in the version target. The CCNetLabel property is inserted into the version numbers. For added benefit, you could use a CruiseControl.NET plugin like the previously mentioned SvnRevisionLabeller. Using that, we get builds with labels like "2.1.8239.0", where the "8239" corresponds to the Subversion revision number we're building from. We dump this build number directly into our AssemblyVersionAttribute and AssemblyInformationalVersionAttributes, and our build numbers and the version numbers on our assemblies can all be easily traced back to a specific revision in our version control system.