Custom Functions with NAnt

I am not a build engineer, but I do enjoy architecting systems to help make the software build process better. I work in a start up for various reasons, one of which is the opportunity to solve wide ranging business problems. Recently, I put on my build engineer’s hat and dedicated some time to improving our software build process, stepping outside of my immediate comfort zone.

I rely on a number of tools for our continuous integration practices. One of which is CruiseControl.NET, the other is NAnt. Both of these tools use .NET technologies and are ports from their Java projects, CruiseControl and Ant. Besides Lucene.Net, what .NET projects are not better than their Java cousins? Just kidding, take it easy. In addition, CruiseControl.NET integrates with a number of technologies to improve the build process. NAnt, MSBuild, NUnit, FxCop, and FitNesse are just a few. With NAnt and MSBuild, we can call more applications as well, like TypeMock, BeyondCompare, and other necessary applications for our system.

As I mentioned, I am not a build engineer, but I get the opportunity to play the role. Our continuous integration process uses a number of free and open-source projects because they are widely supported and proven technologies, and the price is right. As our developers commit code into our SCM system (we use Subversion), the CruiseControl server checks for updates and begins the build and verification process. Helping with this process is NAnt, an extremely helpful .NET build tool.

What I like most about NAnt, and probably the primary reason for this post, is that I can leverage my knowledge of C# to write functions to aid in the process of building better products. CruiseControl uses XML config files, where projects are created, properties are configured, dependencies are defined, and much more. In my scenario, I have the CruiseControl config file calling my NAnt build scripts, which are also written in XML. Fortunately, I feel confident in my XML skills, so this is easy for building basic projects and adding to them.

The NAnt build scripts are used to define how the project is built. As NAnt is executed, it calls a build script. A typical scenario of actions defined in the script could be to check out the latest code, clean the build environment, build the project, test the project, and deploy the project with necessary configuration files (app.config, web.config, ect.). CruiseControl notifies the development team immediately on the build’s status - pass or fail.

What I set out to do, and where NAnt helped me the most, is with versioning my assemblies and deploying to a common location. Versioning of the assemblies requires more control over my build scripts. In this instance it requires incrementing the Major.Minor.Build.Revision version in my AssemblyInfo.cs files for all projects before the build, and rolling these changes back anywhere during the process if the build should fail.

Discovering how to call C# functions within NAnt increased my ability to do more and saved time. NAnt has a number of predefined functions that can be used to make life easier, and it also has the ability to create custom functions that can be written in any number of .NET languages. The ability to write custom functions made my life much easier and gave me the control I needed to do more for my automated build system.

Defining custom functions looks like the following.

   1: <script language=”C#” prefix=”CSharp”>
   1: 
   2:   <code>
   3:     <![CDATA[
   4: 
   5:       [Function("HelloWorld")]
   6:       public static string HelloWorld()
   7:       {
   8:         return “Hello World”;
   9:       }
  10: 
  11:       [Function("GetIncrementedBuildVersion")]
  12:       public static string GetIncrementedBuildVersion(string buildVersionFile, string svnRevision)
  13:       {
  14:         // Read in a file
  15:         System.IO.FileStream fs = new System.IO.FileStream(buildVersionFile, … (more code here)
  16: 
  17:         // Increment file version number
  18:         version++; // you get the idea
  19: 
  20:         // Return incremented version
  21:         return version;
  22:       }
  23:     ]]>
  24:   </code>

</script>

Calling the custom functions now looks like this in NAnt scripts. I am using an “echo” element simply to call my method, HelloWorld, and echo “Hello World” back to the screen. I use a “property” element to return the value of my GetIncrementedBuildVersion method and save this for latter use in my scripts.

   1: <echo message=”My Hello World Message is ${CSharp::HelloWorld()}”/>
   2: <property name=”incremented.build.version” value=”${CSharp::GetIncrementedBuildVersion(master.build.version,svn.revision)}” />

Custom functions are pretty powerful and they certainly saved me a good deal of time, and in a start up, this is gold. Being a build engineer is a fulltime position and I quickly learned this over the past two weeks. These are a few of the tools I chose to use to help me improve our software build process.If you would like more detailed examples of CruiseControl configs or NAnt scripts, I would be happy to provide those, just email me. I did not want to become that detailed in this post.

kick it on DotNetKicks.com

3 Responses to “Custom Functions with NAnt”

  1. Hey Alex - I agree that some dotnet ports are better than their java counterpart, but remember that the java version was usually created *first*, so calling them “cousins” is incorrect (unless we’re talking about in-breeding.) More like second generation in my book. :-)
    Nonetheless, I agree with your post, but to me we’re missing a key element in this space — release management. Pushing the right bits live to the right servers at the right time, etc. We built up our own structure around Subversion, MSBuild/Nant, Trac and (eventually) CruiseControl.Net. Builds are one thing, but release deployment quite another. And, every release requires a build, so this was a natural extension for us.

    I would like to see (from the community) programmatic expansion (under NAnt seems logical) into the release/deployment side of operations.

  2. Thanks for the response. When you say programmatic expansion, are you referring to a tool that would target release management from start to finish, versus an agglomeration of tools aiding in the process? It would certainly be easier to have one tool with the ability to customize, meeting our needs in different environments.

  3. [...] comes with a lot of built in tags, functions and properties. You can even create your own functions using C#. There is also create documentation that comes with NANT. Another great resource is [...]

Leave a Reply

Close
E-mail It