Assembly Versioning With Git Hooks

by jmorris 6. January 2014 17:56

Source code can be found here: https://github.com/jeffrymorris/githook-version-example

Consider the scenario where you wish to base your assembly versioning off of your commit history from Git. Ideally you would want to be able to pull some information from Git regarding the commit you wish to build from, you most definitely would want this information to follow the traditional .NET versioning semantics or something similar like semver.org, and importantly you would want it to be integrated with your build process and automated. Integrated, because once you have your process in place, you probably don’t want to waste time manually changing things every time you do a build and automated, because you don’t want human fingers touching it (and perhaps making human mistakes) every on every build cycle.

Getting Commit Information from Git

Git provides a couple of different ways of getting information regarding the current state of your repository, of prominence are “git-describe”, which will show you the most recent tag that is reachable from a commit[1] and “git-rev-parse” to print out the SHA1 of a given revision.

git describe --long shows you the “nth” commit since the last tag and the shortened SHA1 of that commit. For example, given a tag created with the following command: “$ git tag -a 1.0.0 -m "1.0.0 tag", assuming that two commits have occurred since the tag was created, git-describe with the –long parameter will output: “1.0.0-2-g1089655”:

image

Where 1.0.0 is your tag, 2 is the number of commits since you created the tag, and the 1089655 is a shortened SHA1 of the last commit.

Storing Git Commit Information in your Assembly

.NET Assembly versioning is fairly well documented, in a nutshell it involves the following four values that are included within a special class in your project under the properties subfolder and compiled into the manifest of your assembly:

<major>.<minor>.<build number>.<revision>

All four values are positive integers, which separated by periods: 1.201.344.1 as an example. The .NET runtime uses this information, along with other information (say from an App.config or Web.config file) to ensure that the correct version of an assembly is loaded at runtime.

The special class mentioned previously is the AssemblyInfo.cs class and it contains a number of attributes which when compiled, make up a portion of the assembly manifest, which is a collection of static data describing how the assembly elements related to each other[2].

Of importance to this blog post are the following three attributes contained within the AssemblyInfo.cs class:

  • AssemblyVersion
  • AssemblyInformationalVersion
  • AssemblyFileVersion

For our purposes the AssemblyVersion, which contains the <major>.<minor>.<build number>.<revision> values and the AssemblyInformationalVersion, which is largely a plain-text value will be the attributes, will be what we rely on to version and provide build information to the assembly.

Post Merge Git Hooks

Within every Git repo is a folder called “.git”, by default it is not visible but it’s still accessible via the command line. The “.git” folder contains another set of folders where Git stores information related to the repository:

image

The “hooks” file is a special folder for storing, well, hooks! What are hooks? They are special snippets of code or script that is run when certain events are triggered in git. For example, there are hooks that are run when a commit occurs, after a rebase, etc. A full overview of all of the hooks can be found on the git man pages here.

We want the version information to be updated only when a build is in process and because we only want it updated when git pull happens (otherwise the validity of the version is compromised), we will use the post-merge hook. The post-merge hook fires after a successful pull and merge. This means, however, that if the local is the same as the remote, it will not fire. This is something to consider in your solution.

Creating a post-merge hook is easy: you simply create a file named “post-merge” with no file extension and place it in the .git/hooks directory. The easiest way to do this is probably by just navigating to that folder and doing a touch:

image

Once you have the post-merge file in place, Git will invoke it on every pull request or fetch which results in the local repository being updated with changes from the remote. This workflow fits well in an automated build environment.

Using the Post-Merge Hook to Update the AssemblyInfo.cs File

Once you have the post-merge hook in place you can now write some script to update the version information within your .NET project.

When Git is installed, several bash tools are also installed it. One of those is probably familiar to most Linux developers or administrators is Sed, which translated means “Stream Editor” is utility for parsing and transforming text. In this case, we will use Sed and a regular expression to find the line within the AssemblyInfo.cs file we wish to update and replace it with the updated revision information obtained via the git-describe mentioned previously.

Here is the relevant code:

image

What this does is do a git-describe with the “—always” flag, which will always return something: a shortened SHA1 of the most recent revision if a tag is not present. The script then checks the return value of the git-describe, which is stored in the variable “tag” to see if it has a git tag associated with it. If it does then it splits the value in “tag” and concatenates them into a format compatible with .NET versioning discussed previously. The result of this is stored in another variable “version” and echoed out on the next line. This variable “version” is then swapped with the previous values in the AssemblyVersion and AssemblyFileVersion attributes using a regex and Sed. Finally, the whole git-describe value stored in “tag” is swapped with the previous value of the AssemblyInformationalVersion attribute.

After building the project and right clicking on the assembly generated, this is what we see:

image

The .NET assembly version stored within the assembly manifest will also be 1.0.0.2. As previously discussed this loosely translates to the <major>.<minor>.<build>.<revision> semantics described above. Additionally, if you chose to you could base your tag structure off of semver.org’s guidelines and only use the last digit to designate a non-releasable test build (for example) based off the previous tag and the number of commits since it was created. On release builds you would specify a new tag with the last digit zero and the second to last digit one increment more than the previous or something to that affect.

References

1 https://www.kernel.org/pub/software/scm/git/docs/git-describe.html

2 http://msdn.microsoft.com/en-us/library/51ket42z%28v=vs.110%29.aspx

Tags: , ,

Visual Studio | Git | Versioning

.NET Framework 4 Client Profile: The Devil Itself!

by jmorris 7. January 2011 02:16

I am convinced that Microsoft’s decision to set the build profile of projects created with the Console Application template to “.NET 4 Client Profile” is a work of the devil itself! Why you might ask? Because it is set to this profile by default and because it will cause projects that should rightfully compile to fail, without an adequate explanation of why!

The reason this happens is because VS 2010 will allow you to reference projects and/or DLLs compiled under the “.NET 4 Framework” target, which may contain references to resources excluded by the “.NET 4 Client Profile” without complaining or warning the user. What a horrible, frustrating “feature”…

Here is a formal description from MSDN:

“The .NET Framework 4 Client Profile is a subset of the .NET Framework 4 that is optimized for client applications. It provides functionality for most client applications, including Windows Presentation Foundation (WPF), Windows Forms, Windows Communication Foundation (WCF), and ClickOnce features. This enables faster deployment and a smaller install package for applications that target the .NET Framework 4 Client Profile.”MSDN

Here is an example of a compile time error caused by this:

image 

The weird, confusing part is that while typing in the using statement for the namespace, intellisense will show you the namespaces and the object viewer will confirm that they exist. However, when you go to compile it will fail! Very frustrating!!!

This fix is very easy, simply right click on the project and select properties and then in the “Target Framework” dropdown, select “.NET 4 Framework” and your good to go. I am hoping that this will be fixed or changed in VS2010 SP1 that should be released soon.

Tags: , , , ,

rant | Visual Studio

More VS2008 to VS2010 Blues

by jmorris 21. October 2010 09:32

I ran into another problem today while updating my VS2008 projects to VS2010. Instead of using the typical Visual Studio Conversion wizard, I wanted to refactor some of my projects into a single project so I created the projects first and then manually copied the files over changing namespaces as I went along. After creating a project for a tool that runs as a console application and moving over the file with the main() method, I got the following exception:

“The referenced assembly ‘D:\XXX.Prism.dll’ could not be resolved because it has a dependency on ‘System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’ which is not in the currently targeted framework ‘.NETFramework,Version=v4.0,Profile=Client’. Please remove references to assemblies not in the targeted framework or consider retargeting your project.    XXX.Prism.Damsole”

Whoa, kinda strange…I checked Framework Target on the Properties page and saw that it was:

image

.NET Framework 4 Client Profile? What’s that? A quick google gave me the answer:

“The .NET Framework 4 Client Profile is a subset of the .NET Framework 4 that is optimized for client applications. It provides functionality for most client applications, including Windows Presentation Foundation (WPF), Windows Forms, Windows Communication Foundation (WCF), and ClickOnce features. This enables faster deployment and a smaller install package for applications that target the .NET Framework 4 Client Profile.”

-http://msdn.microsoft.com/en-us/library/cc656912.aspx

image

It turns out that the project I was referencing had a reference to System.Web and since by default VS2010 sets the Target Framework for console applications to the .NET 4 Framework Client Profile, which excludes the following features:

  • ASP.NET
  • Advanced Windows Communication Foundation (WCF) functionality
  • .NET Framework Data Provider for Oracle
  • MSBuild for compiling

Resolution was simple, I just changed the Target Framework to .NET Framework Profile and all was good. It seems kind of strange that MS would default that kind of behavior when it seems to me to be more of an optimization more than anything else and can cause quit a bit of confusion.

Tags: , ,

Visual Studio

Upgrading ASP.NET Projects from VS2008 to VS2010

by jmorris 15. October 2010 17:44

I recently upgraded several solutions/projects from VS2008 to VS2010 and ran into a few snags. The following covers some of the issues I have run into and how I fixed them.

First thing I did was use the Visual Conversion  Wizard to convert the solution and projects from VS2008 to VS2010, which is pretty simple. Just write click on the solutions and select “Open with Microsoft Visual Studio 2010”:

image

You will be prompted with by the Visual Studio Conversion Wizard:

image

Select “Next” and then “Finish”. You will then be prompted with a dialog wanting to know if you want to upgrade Web sites that were configured to run under the an earlier version of VS (in this case 2008):

image

What this does is add the targetFramework entry to your Web.Config file to “4.0”, so that IIS knows to which version of .NET to run under:

image

After you answer “Yes” to these dialogs and assuming nothing went wrong with your conversion, the “Conversion Complete” dialog will appear:

image

Thus far, for me everything went according to plan, however when I went to build the solution I ran into some errors:

image

For some reason two of the references were not resolved, so using the “Add References” dialog I added the two references thinking they must have just become “unreferenced” and got the following error:

image

What the heck? Didn’t I just upgrade those to VS2010 (.NET 4.0)? Well, actually it turns out I did, however the other assemblies (this one included) were still compiling under .NET 3.5. So, pretty easy to fix, just right click on each project and select “Properties” and then on the “Application” tab select the appropriate .NET Framework:

image

You have to do this for each project in the solution. Now thinking that everything has been resolved, I built the projects and while I was expected a nice “Build succeeded” message, I got:

image

Yikes, that was not what I expected to see! Notice that all of the error’s were of the form:

“The type name 'X' could not be found. This type has been forwarded to assembly 'System.Web.ApplicationServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. Consider adding a reference to that assembly.”

All of the errors were related to code referencing ASP.NET’s Membership and Role API’s and the “This type has been forwarded to assembly ‘System.Web.ApplicationServices’ was a huge, massive hint as to what was going on. So I added a reference to System.Web.ApplicationServices:

image

And then I did another build which completed successfully.

Summary

The conversion in my opinion was pretty straight forward, even though I ran into a few scenarios that the Conversion Wizard could not handle. I am pretty experienced with  updating solutions/projects from previous versions of .NET; I could see where a somebody less experienced with VS projects and solutions would run into some trouble, but for the most part it was pain-free. As long as you read the error messages and consider what may be causing them, you shouldn’t run into to many problems.

Tags: , , ,

Visual Studio

Jeff Morris

Tag cloud

Month List

Page List