Setting environment dependant properties in nAnt

This is a little something that I discovered recently while writing some nAnt scripts.  I love to have One Script to Compile Them All so that I can ensure that the build server and all the developers are compiling and executing the tests in the exact same manner.  One of the things that you will find is that you'll have some variable values getting set one way for the local build and another way for the build on the build server.  A really good example of this is what I was showing in my recent post on versioning assemblies using nAnt.  In that post I showed a technique for setting a property to hold a version number that is only available when CruiseControl.NET is launching the build script.

    <property name="version" value="0.0.0.0"/>
    <if test="${property::exists('CCNetLabel')}">
      <property name="version" value="${CCNetLabel}"/>
    </if>

Usually you would think of it existing in the script like this

    <project>
        <property name="version" value="0.0.0.0"/>
        <task name="compile">
            <if test="${property::exists('CCNetLabel')}">
                <property name="version" value="${CCNetLabel}"/>
            </if>
        </task>
    </project>

This ensures that there always is a version number (0.0.0.0 in this case) and that it will be changed when compile is launched by CruiseControl.NET.  In my most recent scripting endevour I was faced with a lot of values being set in this manner.  At one point I had refactored all the variable setting out into its own task.  Every time that I had to add another variable that required this type of treatment, I felt a little bit dirtier about the script.  If I had to change the "version" variable, it would potentially need to be changed in two places.  That's when I figured out that this will work in nAnt.

    <project>
        <property name="version" value="0.0.0.0"/>
   <if test="${property::exists('CCNetLabel')}">
       <property name="version" value="${CCNetLabel}"/>
   </if>
        <task name="compile">
            <!-- do compile stuff in here -->
        </task>
    </project>

You can add conditional statement to a nAnt script outside of the task elements.  All of the property setting and conditionals are executed immediately when the script is loaded by nAnt.  This has allowed me to do all of my CruiseControl.NET dependent variable changes within the main block of the script and not have to worry about them being run when a task is called.

It's amazing what a little thing like this can do to help clean up a script.

Posted By: Donald Belcham

Published at

Comments

Tim Goodwin
01/23/2008 08:19 AM by
Tim Goodwin

Here's another alternative to a similar concept. It doesn't work with your CCNetLabel example because CCNetLabel doesn't allow you to overwrite it but it works well with the local.properties.xml.template style approach.

In this example, by default you'd expect to send the email, unless the developer would prefer not to while doing his development.

In that case, in his local.properties.xml he'd provide an overwrite by having:

defined.

Find this keeps my build file cleaner. just a set of property declarations and not requiring multiple many many <if test=".." /if> checks that can quickly get ugly.

NOTE: i solve the issue of the ccnet label issue about by using a bootstrap file for the cruise build