Managaging assembly versioning in NAnt

Recently I ran a lab for the Denver Visual Studio User Group on open source tools NAnt, NUnit, Subversion, and Cruise Control.Net, tools that significantly improve the development cycle in .Net. I briefly touched on the NAnt feature allowing C#, VB, or J# code to be included in your NAnt file, and dynamically compiled and run by NAnt during a build. I use this feature to handle versioning of assemblies the way I want the versioning to work. One of the lab participants requested a copy of this code. As always, feel free to provide feedback!

I realize that today's version of NAnt allows an assemblyinfo.cs file to be built dynamically in the script using the <asminfo> task, providing some flexibility in how versioning and signing is handled during the build. When I put this together, either that feature didn't exist or I wasn't aware of it. Thus, my approach involves parsing assemblyinfo.cs files and substituting version numbers at build time - you may be able to improve on this. As I look at it, there are other things I could do to improve and simply it, but I'll just include the currently working copy for now, and let you adapt it to your needs.

My versioning model is based on a control file containing the last-used version number. I increment the third portion of the number during a build, and commit this change to a Subversion repository if the build was successful. This way version numbers are only assigned to successful builds, and I don't waste version numbers on builds that failed. Of course, failed builds never leave the build server.

The first target is getversion, which pulls the portions of the version number out of the version.txt file into properties:

<target name="getversion" description="Populate the version properties based on the version.txt file">
  <echo message="${nant.project.basedir}"/>
  <script language="C#">
   <code><![CDATA[
    public static void ScriptMain(Project project)
    {
     // parse version document to get version information
     string fileName = Path.Combine(project.BaseDirectory, project.Properties["build.version.filename"]);
     StreamReader reader = new StreamReader(fileName);
     string versionInfo = reader.ReadLine();
     reader.Close();
     Regex pattern = new Regex("[0-9]+");
     MatchCollection matches = pattern.Matches(versionInfo);
     if (matches.Count != 4)
      throw new Exception(string.Format("Version number {0} in {1} has incorrect format.", versionInfo, fileName));
     int major = int.Parse(matches[0].Value);
     int minor = int.Parse(matches[1].Value);
     int build = int.Parse(matches[2].Value);
     int revision = int.Parse(matches[3].Value);
     project.Properties.Add("build.version.major", major.ToString());
     project.Properties.Add("build.version.minor", minor.ToString());
     project.Properties.Add("build.version.build", build.ToString());
     project.Properties.Add("build.version.revision", revision.ToString());
    }
   ]]></code>
  </script>
  <call target="setversionstring" />
 </target>
 
 
This calls setversionstring, which simply combines the seperate properties into a single versionstring property:
 
 <target name="setversionstring" description="Set the build.version.versionstring property">
  <script language="C#">
   <code><![CDATA[
    public static void ScriptMain(Project project)
    {
     string versionString = string.Format("{0}.{1}.{2}.{3}",
      project.Properties["build.version.major"],
      project.Properties["build.version.minor"],
      project.Properties["build.version.build"],
      project.Properties["build.version.revision"]
     );
     project.Properties["build.version.versionstring"] = versionString;
     project.Log(Level.Info, versionString);
    }
   ]]></code>
  </script>
 </target>

 
The incrementbuildnumber target is called from server builds (not developer-machine builds) to increment the third section of the number:
 
 <target name="incrementbuildnumber" description="Increment the build number and write to version.txt file">
  <script language="C#">
   <code><![CDATA[
    public static void ScriptMain(Project project)
    {
     string fileName = Path.Combine(project.BaseDirectory, project.Properties["build.version.filename"]);
     int major = int.Parse(project.Properties["build.version.major"]);
     int minor = int.Parse(project.Properties["build.version.minor"]);
     int build = int.Parse(project.Properties["build.version.build"]);
     int revision = int.Parse(project.Properties["build.version.revision"]);
     build++;
     string versionString = string.Format("{0}.{1}.{2}.{3}", major, minor, build, revision);
     project.Properties["build.version.build"] = build.ToString();
     
     StreamWriter writer = new StreamWriter(fileName, false);
     writer.WriteLine(versionString);
     writer.Close();
    }
   ]]></code>
  </script>
  <call target="setversionstring" />
 </target>

 
Finally, setversion is used to update the assemblyinfo.cs files with the updated version number:
 
 <target name="setversion" description="Stamp the version info onto assemblyinfo.cs files">
  <foreach item="File" property="filename">
   <in>
    <items basedir="application">
     <include name="**\AssemblyInfo.cs"></include>
    </items>
   </in>
   <do>
    <script language="C#">
     <code><![CDATA[
     public static void ScriptMain(Project project)
     {
      //FileStream file = File.Open(project.Properties["filename"], FileMode.Open, FileAccess.ReadWrite);
      StreamReader reader = new StreamReader(project.Properties["filename"]);
      string contents = reader.ReadToEnd();
      reader.Close();
      string replacement = string.Format(
       "[assembly: AssemblyVersion(\"{0}.{1}.{2}.{3}\")]",
       project.Properties["build.version.major"],
       project.Properties["build.version.minor"],
       project.Properties["build.version.build"],
       project.Properties["build.version.revision"]
      );
      string newText = Regex.Replace(contents, @"\[assembly: AssemblyVersion\("".*""\)\]", replacement);
      StreamWriter writer = new StreamWriter(project.Properties["filename"], false);
      writer.Write(newText);
      writer.Close();
     }
     ]]>
     </code>
    </script>
   </do>
  </foreach>
 </target>
 
This way, when the project compiles, our version number will be used on each assembly. For developer builds, I hard-code the "build.version.build" to 0, so that I can identify the build as a developer build. This is accomplished with the following task, called after getversion:
 
  <property name="build.version.build" value="0" />
 
I trust that this will be helpful!
 
- Josh
Published Tue, Jul 26 2005 9:56 PM by Joshua Langemann
Filed under:

Comments

Friday, July 29, 2005 7:11 AM by Joshua Langemann

# Link to lab materials

The materials from the lab can be found at this URL: ftp://66.180.109.178/pub/VBSig/Labs/2005/07_22_2005
Wednesday, October 18, 2006 2:52 PM by Bite my bytes

# Setting version number in AssemblyInfo files with NAnt

Sunday, November 05, 2006 7:34 PM by C# .Net Tales

# Release Management

I&#39;ve been looking into Release management and versioning assemblies in .Net 2.0. Joshua shows a good

Wednesday, September 05, 2007 10:38 PM by Mirrored Blogs

# Release Management

Body: I&#39;ve been looking into Release management and versioning assemblies in .Net 2.0. Joshua shows

# Migrating from CruiseControl.NET to TeamCity 3.1 | voodude.ch/blog

Pingback from  Migrating from CruiseControl.NET to TeamCity 3.1 | voodude.ch/blog

Saturday, November 21, 2009 10:37 AM by SharePoint Development Blog by Jeremy Thake in Perth, Australia

# Release Management

I've been looking into Release management and versioning ass ...

# Toyota T100 Radiator Replacement One Ton Cyl L, T1000 Used Call Sun Fire V210

Pingback from  Toyota T100 Radiator Replacement One Ton Cyl L, T1000 Used Call Sun Fire V210

Friday, May 21, 2010 2:38 PM by 1 Ion Radiator Saturn Sc2, Sc2 Part Save Saturn Sc1

# 1 Ion Radiator Saturn Sc2, Sc2 Part Save Saturn Sc1

Pingback from  1 Ion Radiator Saturn Sc2, Sc2 Part Save Saturn Sc1

# Nikon D50 Flash Sync Problem, Auto Zone Dodge D50 Pickup

Pingback from  Nikon D50 Flash Sync Problem, Auto Zone Dodge D50 Pickup

Saturday, May 22, 2010 4:15 AM by Aerio Tube Shock Absorber, Aerio Purchase Cost

# Aerio Tube Shock Absorber, Aerio Purchase Cost

Pingback from  Aerio Tube Shock Absorber, Aerio Purchase Cost

# 260z Substitute Digital, Axxess Parts Stanza Nissan 260z

Pingback from  260z Substitute Digital, Axxess Parts Stanza Nissan 260z

Saturday, May 22, 2010 8:07 AM by Citation Ii Sell Chevrolet Chevette, Chevette For Kids

# Citation Ii Sell Chevrolet Chevette, Chevette For Kids

Pingback from  Citation Ii Sell Chevrolet Chevette, Chevette For Kids

Saturday, May 22, 2010 12:27 PM by X90l Auction, Bx900r Review

# X90l Auction, Bx900r Review

Pingback from  X90l Auction, Bx900r Review

Saturday, May 22, 2010 12:43 PM by 535is Wrist, Music Video 535is

# 535is Wrist, Music Video 535is

Pingback from  535is Wrist, Music Video 535is

Saturday, May 22, 2010 5:16 PM by Aviator Sale Miami Lincoln Mkx, Parts 2009 Lincoln Mkx

# Aviator Sale Miami Lincoln Mkx, Parts 2009 Lincoln Mkx

Pingback from  Aviator Sale Miami Lincoln Mkx, Parts 2009 Lincoln Mkx

# Mercedes Benz 280c Taillight Cl65 Amg, R63 Parts C63 Cl65 Amg

Pingback from  Mercedes Benz 280c Taillight Cl65 Amg, R63 Parts C63 Cl65 Amg

# 2004 Honda Accord Autozone Replacement, 05 Accord Projector Headlight

Pingback from  2004 Honda Accord Autozone Replacement, 05 Accord Projector Headlight

# Mercedes Benz Ml500 Horsepower Liter V8, Ml55 Amg Diagram Ml500 - 304.an74.com

Pingback from  Mercedes Benz Ml500 Horsepower Liter V8, Ml55 Amg Diagram Ml500 - 304.an74.com

# 250sl Distributor Autohaus, 250sl Discount Auto Parts Suspension - 3.an74.com

Pingback from  250sl Distributor Autohaus, 250sl Discount Auto Parts Suspension - 3.an74.com

# Somerset Regal Metal Halide, Regal Menu - 367.codebluehacks.org

Pingback from  Somerset Regal Metal Halide, Regal Menu - 367.codebluehacks.org

# Bmw 325 Brake Light Stays On, Repair 1987 325e Bmw E30 - 310.cmanager.org

Pingback from  Bmw 325 Brake Light Stays On, Repair 1987 325e Bmw E30 - 310.cmanager.org

# 70 71 Mercury Montego, 2002 Sport 2000 Mitsubishi Montero - 211.zapstreaming.com

Pingback from  70 71 Mercury Montego, 2002 Sport 2000 Mitsubishi Montero - 211.zapstreaming.com

# Cavalier Antique Dealers, 1984 Chevrolet Cavalier Wagon - 213.akemet.com

Pingback from  Cavalier Antique Dealers, 1984 Chevrolet Cavalier Wagon - 213.akemet.com

# Pb100 Headlight Lamps Gran Fury, Pb100 Auction Music - 246.defutbolazo.com

Pingback from  Pb100 Headlight Lamps Gran Fury, Pb100 Auction Music - 246.defutbolazo.com

# 2008 - 1990 @ Sc Ep Student Temporary Employment Program Step, Tempo Ultra View - 338.luna-atra.net

Pingback from  2008 - 1990 @ Sc Ep Student Temporary Employment Program Step, Tempo Ultra View - 338.luna-atra.net

# 2002 - 1980 @ Datsun 260z Owners Club, 280z Episode Datsun 260z - 283.rkwrh.com

Pingback from  2002 - 1980 @ Datsun 260z Owners Club, 280z Episode Datsun 260z - 283.rkwrh.com

# 1993 - 1983 @ Reno Sierra Resort Circus Circus, Chevrolet Colorado Used Gmc Sierra - 223.tvshowzone.com

Pingback from  1993 - 1983 @ Reno Sierra Resort Circus Circus, Chevrolet Colorado Used Gmc Sierra - 223.tvshowzone.com

# 1992 - 1989 @ Enchantment Sedona Country, Black Country Motorcycle - 72.tgrconversions.com

Pingback from  1992 - 1989 @ Enchantment Sedona Country, Black Country Motorcycle - 72.tgrconversions.com

# 2002 - 1980 @ Silverado 1500 Mpg Pickup Trucks Toyota Tundra, Prius Dealers Oem Parts Toyota Tundra - 392.rkwrh.com

Pingback from  2002 - 1980 @ Silverado 1500 Mpg Pickup Trucks Toyota Tundra, Prius Dealers Oem Parts Toyota Tundra - 392.rkwrh.com

# 1999 - 1998 @ B1500 Promotion Guide, B1500 Aftermarket Long Dodge Stealth - 27.myipgirl.com

Pingback from  1999 - 1998 @ B1500 Promotion Guide, B1500 Aftermarket Long Dodge Stealth - 27.myipgirl.com

# 1981 - 2003 @ Hid Free Us 1990 Bmw 735i, 735i Accessories Prices - 195.zapstreaming.com

Pingback from  1981 - 2003 @ Hid Free Us 1990 Bmw 735i, 735i Accessories Prices - 195.zapstreaming.com

# 1994 - 1993 @ Mirada Taillight Auto Parts Dodge Coronet, Coronet Sold - 103.renters.ws

Pingback from  1994 - 1993 @ Mirada Taillight Auto Parts Dodge Coronet, Coronet Sold - 103.renters.ws

# 1992 - 1989 @ Aod150 Price Acer Extensa, 100 Used Ford E Econoline - 461.mfbattle.com

Pingback from  1992 - 1989 @ Aod150 Price Acer Extensa, 100 Used Ford E Econoline - 461.mfbattle.com

# 1984 - 2003 @ Sale Aurora Saddle Rock Golf, Odyssey F7 Putter Callaway Golf - 380.ja3ra.com

Pingback from  1984 - 2003 @ Sale Aurora Saddle Rock Golf, Odyssey F7 Putter Callaway Golf - 380.ja3ra.com

Wednesday, August 17, 2011 9:42 AM by Datsun v210 | Infomcgconsult

# Datsun v210 | Infomcgconsult

Pingback from  Datsun v210 | Infomcgconsult

Thursday, March 07, 2013 1:09 PM by nhbcyz

# re: Managaging assembly versioning in NAnt

Thanks,I read the code,but I don't know how to use?Please give me a perfect example.

my expression is not good,Please help!!

my email:

nihongbo1987@163.com

Thank you.

Thursday, March 07, 2013 1:10 PM by nhbcyz

# re: Managaging assembly versioning in NAnt

Thanks,I read the code,but I don't know how to use?Please give me a perfect example.

my expression is not good,Please help!!

my email:

nihongbo1987@163.com

Thank you.

Leave a Comment

(required) 
(required) 
(optional)
(required) 
Please add 3 and 1 and type the answer here: