We have recently updated our NAnt build script used to build Cart Viper to include the revision number from Subversion. So now when we build the project it will update all the build numbers of the DLLs to have a revision number equal to the revision number from Subversion.

DLL build number as set using NAnt script

In the example above the major, minor and build numbers come from a property we define in the NAnt script, so we just need to change this to increment all the DLLs to the new number.

The revision number of 2250 is the revision number from Subversion, so in the future we now that this DLL was compiled using revision 2250 of our code base. This is automatically read from Subversion using the script below.

Read the Revision Number from Subversion

Note we use TortoiseSVN so we are using a binary from that program to get the revision number.

First we need to commit a special text file to the Subversion repo, this file contains a token which when we output the file from the repo will be replaced with the latest SVN revision number.
The file should just contain the token

$WCREV$

Contents of the rev.txt

Make sure you commit the file into the repo, my file is call rev.txt

For our build process we have a sub folder off the root of the project called build which contains the NAnt script and the revision file.

In the NAnt build script we have the init target which handles updating the build number.

<target name="init">
    <!-- basic verison number to set for the DLLs -->
    <property name="shortVersion" value="1.4.1"/>
    
    <property name="build.version.revision" value="0" />

	<exec program="subwcrev" basedir="C:\Program Files\TortoiseSVN\bin" 
		commandline='./ rev.txt revvalue.txt' failonerror="false"/>

The part that does the work is the exec element, this calls the subwcrev command line tool to output the rev.txt file to a file called revvalue.txt. This will have the effect of replacing the token with the reversion number.

Now we need to read the contents of the file into a property in NAnt.

    <loadfile file="./revvalue.txt" property="build.version.revision"/> 

Updating the AssemblyInfo.cs Files in NAnt

The final thing we need to do is take the version numbers we have and replace these in all the AssemblyInfo.cs files in our project.
To do this we need to use some custom code in the script. Remember we have our build file in a sub folder off the root of the main project file. So we need to move up one level, you may need to change this in relation to the location of the NAnt build file and the project root (see line 12).

<!-- run some custom code to find all the files then 
         update the rev number to the one we've just read from 
         subversion --> 
     <script language="C#"> 
          <references> 
              <include name="System.dll" /> 
          </references> 
          <imports> 
              <import namespace="System.Text.RegularExpressions" /> 
          </imports> 
          <code> 
            <![CDATA[ 
              public static void ScriptMain(Project project) { 
                  DirectoryInfo baseDirectory =  new DirectoryInfo(project.BaseDirectory); 
                  DirectoryInfo rootDirectory = baseDirectory.Parent; 
                  
                  string buildNumber = project.Properties["shortVersion"].Replace("\r\n", ""); 
                  string revisionBuild = project.Properties["build.version.revision"].Replace("\r\n", ""); 
                  StringBuilder buffer = new StringBuilder(); 
                  
                  var files = rootDirectory.EnumerateFiles("AssemblyInfo.cs", SearchOption.AllDirectories); 
                  
                  foreach(FileInfo fi in files){ 
                    string fileContents; 
                  
                    using(FileStream stream = fi.Open(FileMode.Open, FileAccess.ReadWrite )){ 
                      using(StreamReader reader = new StreamReader(stream)){ 
                        fileContents = reader.ReadToEnd(); 
                        
                        //set the assemblyVersion 
                        string assemVersion = Regex.Match(fileContents, @"\[assembly: AssemblyVersion.*").Value; 
                        
                        if(!string.IsNullOrEmpty(assemVersion)){ 
                          buffer.Append(assemVersion.Substring(0, assemVersion.IndexOf('"') + 1)); 
                          buffer.Append(buildNumber); 
                          buffer.Append("."); 
                          buffer.Append(revisionBuild); 
                          buffer.Append("\")]"); 
                          
                          fileContents = fileContents.Replace(assemVersion, buffer.ToString()); 
                          buffer.Clear(); 
                        } 
                        
                        //set the AssemblyFileVersion 
                        string assemFileVersion = Regex.Match(fileContents, @"\[assembly: AssemblyFileVersion.*").Value; 
                        if(!string.IsNullOrEmpty(assemFileVersion)){ 
                          buffer.Append(assemFileVersion.Substring(0, assemFileVersion.IndexOf('"') + 1)); 
                          buffer.Append(buildNumber); 
                          buffer.Append("."); 
                          buffer.Append(revisionBuild); 
                          buffer.Append("\")]"); 
                          fileContents = fileContents.Replace(assemFileVersion, buffer.ToString()); 
                          buffer.Clear(); 
                        } 
                      } 
                    } 
                    
                    using(FileStream stream = fi.Open(FileMode.Truncate, FileAccess.Write)){ 
                      using(StreamWriter writer = new StreamWriter(stream)){ 
                        writer.Write(fileContents); 
                      } 
                    } 
                    
              } 
            } 
            ]]> 
          </code> 
      </script> 
</target>

Now when you build the script the build numbers will be updated automatically.