damageboy / daemaged.gitinfoplanter

Plant Git Information into .NET Assemblies using Mono.Cecil
MIT License
11 stars 2 forks source link

Plant git repo information in .NET assemblies

gitinfoplanter.exe automates the process of reading your git repo status and embedding it as an easy to use string in an assembly level attribute of your .NET executable.

30 Second Intro

Current project build status

The build is generously hosted and run on the CodeBetter TeamCity infrastructure.

Branch Status of last build
master master

Git Repo String

So how does a version string look?
The best way to answer this is to simply run the info planter with --version to see a sample:

$ ./daemaged.gitinfoplanter.exe --version
daemaged.gitinfoplanter version "1.1.0.0.4658/1.1/20/1e5356fd2bdbde4b5c82552844e6eb5ed6d5a9f2"

The version string is the part that says: 1.1.0.0.4658/1.1/20/1e5356fd2bdbde4b5c82552844e6eb5ed6d5a9f2
but what does it really mean?

Where/How does this get embedded?

The git info planter uses cecil to re-write the assembly and embed two assembly level attributes:

So, you can think of the resulting assemblly as-if someone went back to your code, and edited you AssemblyInfo.cs file from this:

using System.Reflection;

[assembly: AssemblyTitle("Daemaged.GitInfoPlanter")]
[assembly: AssemblyDescription("Plant git information into .NET assemblies")]
[assembly: AssemblyCompany("Damage INC.")]
[assembly: AssemblyProduct("Daemaged.GitInfoPlanter")]
[assembly: AssemblyCopyright("Copyright (C) Dan Shechter, Inc. 2010")]
[assembly: AssemblyVersion("1.1.0.0")]

To this:

using System.Reflection;

[assembly: AssemblyTitle("Daemaged.GitInfoPlanter")]
[assembly: AssemblyDescription("Plant git information into .NET assemblies")]
[assembly: AssemblyCompany("Damage INC.")]
[assembly: AssemblyProduct("Daemaged.GitInfoPlanter")]
[assembly: AssemblyCopyright("Copyright (C) Dan Shechter, Inc. 2010")]
[assembly: AssemblyVersion("1.1.0.0")]
[assembly: AssemblyFileVersionAttribute("1.1.0.0.4658")]
[assembly: AssemblyInformationalVersionAttribute("1.1.0.0.4658/1.1/20/1e5356fd2bdbde4b5c82552844e6eb5ed6d5a9f2")]

Of course, no real changes to the code were actually made, however the resulting binary will contain the additional attributes

.NET 4.5 specific attributes

If you are targeting the .NET 4.5 framework, there's an additional attribute called [AssemblyMetadataAttribute] that's available from 4.5 onwards, which is used to insert each part of the metada separately like this:

using System.Reflection;

[assembly: AssemblyTitle("Daemaged.GitInfoPlanter")]
[assembly: AssemblyDescription("Plant git information into .NET assemblies")]
[assembly: AssemblyCompany("Damage INC.")]
[assembly: AssemblyProduct("Daemaged.GitInfoPlanter")]
[assembly: AssemblyCopyright("Copyright (C) Dan Shechter, Inc. 2010")]
[assembly: AssemblyVersion("1.1.0.0")]
[assembly: AssemblyFileVersionAttribute("1.1.0.0.4658")]
[assembly: AssemblyInformationalVersionAttribute("1.1.0.0.4658/master/20/1e5356fd2bdbde4b5c82552844e6eb5ed6d5a9f2")]
[assembly: AssemblyMetadata("Branch", "master")]
[assembly: AssemblyMetadata("Revision #", "20")]
[assembly: AssemblyMetadata("Ahead By", "0")]
[assembly: AssemblyMetadata("Contains Local Modifications", "False")]
[assembly: AssemblyMetadata("CommitId", "1e5356fd2bdbde4b5c82552844e6eb5ed6d5a9f2")]
[assembly: AssemblyMetadata("Build Date", "2012-06-09")]
[assembly: AssemblyMetadata("Build Day", "4658")]

How do I retrieve these attributes at runtime?

Well, it's obviously a very idea to be able to actually read these things when displaying an about dialog, or when a --version option is perhaps specified of command-line...
It's a very simple chore to accomplish, in c# for example, all that one needs to do is:

var versionInfo = 
  asm.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false)
     .Cast<AssemblyInformationalVersionAttribute>().FirstOrDefault();
var versionString = 
  versionInfo == null ? 
   "No specific version info embedded" : 
   versionInfo.InformationalVersion;
Console.WriteLine("MyProduct - {0}", versionString);

OK, I'm sold, how do I put this in my build process?

Two ways:

Nuget

The GitInfoPlanter nuget package (when installed with NuGet 2.5 and above) automatically hooks itself into the build process to plant the git information into the assembly. This is by far the easiest method to get started.

To install the package:

Right Click your project → Select Manage NuGet Packages → Select Online on the left pane → type gitinfoplanter into the search → select Install and you done!

Manually

The manual way would be to simply add it as an after build step in Visual Studio / MonoDevelop / MSBuild.

To do this you need to follow this "recipe":

  1. Get gitinfoplanter.exe and place somewhere in your project
    • The easiet method by far is to add "gitinfoplanter" through nuget
    • Next best way is to use the published latest gitinfoplanter.exe
    • If you really feel like it, clone the project/download the zip and compile it yourself
  2. Edit your .csproj file and add an <AfterBuild> target and the end of the file, a generic one would look like this:
<AfterBuild>
  <Exec Command="$(ProjectDir)../packages/GitInfoPlanter.X.Y/tools/gitinfoplanter.exe --search-path &quot;$(TargetFrameworkDirectory)&quot; --basedate 2000-01-01 --repo $(ProjectDir) $(TargetPath) $(TargetPath)"/>
</AfterBuild>