Friday, October 21, 2011

How to track currently deployed code version (revision from source control)


General rule of thumb is that at any moment in time you should be able to answer question: Which version (revision in svn) of code is currently deployed on production?
 
In this post I will present four approaches which can be used to determine this. I will start from simplest but least recommended ending with recommended but also relatively easy to implement solution. 

Introduction

 To be able to provide answer for question regarding deployed code version you can:
  1. remember version
  2. update svn_revision.txt file on production server
  3. create tag in subversion
  4. store revision in number in assembly

1. Remembering - Storing in human memory
I don’t trust even myself that I will manage remember whether 1789 or 1798 revision was deployed yesterday. If I find someone with better short-time memory than my I still would not be convinced to this approach... Forget this way…
 

2. Updating svn_revision.txt file
You can promise to each other in your team that you will update this file with current revision just after deploying new version to production, but… Remember you should have consistent deployment procedure for each server so don’t forget to update on:

  • production
  • staging
  • acceptance test environment
  • integration environment (where each build is dropped from build server)
It’s not the case if you forget but when you forget to update this. I can bet that when you’re in hurry deploying hotfix to hotfix when site is down you won’t care about such small detail as revision version in text file.
 

3. Creating tag in subversion
It’s common practice to create tag to associate revision with specific application version (check svn book). It can be easily used to track which version goes to production and later any team member can check repository. It seems to be more convenient than storing in text file on server but:

  • if we consistently treat deployment to each environment we should also tag deployment to each of them, It can cause creating many tag for version which has never reached even staging environment
  • It’s hard to track rollbacks on production environment. Even though we have last tag for revision 1701 we can be sure that production environment was not rolled back to version 1700 yesterday during night
  • It requires manual process to create tag or having it done by deployment script, what means we have to access SVN repository from production environment – not recommended and very often not possible.

4. Storing revision number in assembly
This solution assumes revision number is embedded in assembly. Very often we already have version number by AssemblyVersion attribute in AssemblyInfo.cs set to
 

[AssemblyVersion(1.7.2.0)]
 

Common practice is to update it manually: when big release is planned first or second number is upgraded; when minor fix is release only third or fourth number is changed- see semVer).
 

What I propose is to adapt this notation to follow:

Crucial here is that it must be done automatically during build. Only then we can remove human factor and avoid updating this.
 

This approach has following advantages
  • It’s easy to figure out on any environment  what version is currently deployed
  • Even if you rollback or do hotfix current SVN revision is up to date
  • No room for human error, since it’s done automatically
  • Access to SVN is not needed during deployment
  • Revision number can be determined on each environment in same way (production, staging, test etc.)

Implementation
Implementation presented below assumes SVN is used but this approach can be used with virtually any version control system (as long as it has notion of revision/check-in/version number)
 

Msbuild script presented below:
-    Verifies current revision from working copy
-    Updates [AssemblyInfo(…)] attribute
-    Builds project with revision number embedded in assembly

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" >
  <UsingTask TaskName="SvnInfo" AssemblyFile="tools\build\MSBuild.Community.Tasks.dll"/>
  <UsingTask TaskName="AssemblyInfo" AssemblyFile="tools\build\AssemblyInfoTask.dll"/>

  <Target Name="setup-version" >
    <SvnInfo LocalPath="." ToolPath="tools\svn">
      <Output TaskParameter="LastChangedRevision" PropertyName="LastChangedRevision"/>
    </SvnInfo>

    <!-- it will number like 1789 -->
    <Message Text="Last changed revision is: $(LastChangedRevision)"/>

    <AssemblyInfo AssemblyInfoFiles="src\CommonAssemblyInfo.cs" 
           AssemblyRevision="$(LastChangedRevision)"
           AssemblyFileRevision="$(LastChangedRevision)" >
      <Output TaskParameter="MaxAssemblyVersion" 
           PropertyName="MaxAssemblyVersion"/>
    </AssemblyInfo>

    <Message Text="Version: $(MaxAssemblyVersion)"/>
    <!-- it will be like 1.7.0.1789 -->
  </Target>
</Project>

Note: I use MSBuildCommunityTasks to discover revision number and update [AssemblyVersion] attribute
Note: everything what is necessary to build project is stored in repository- in this case we need svninfo.exe so it’s also stored in repository beside source code in directory “tools\svn”

Summary
From four presented approaches how to control revision number deployed on specific environment I would recommend using the last one. Having revision number automatically embedded in assembly has several advantages: simplifies discovery, eliminates chance for human error, does not change current deployment process, etc.