If files are modified for versioning purposes,
roll back the changes at the end of the build, even if the build had errors;
Satisfies requirement 6.

Technical Details

As far as the versioning goes, there are several version numbers associated with a .Net assembly:

Assembly version, important to the .Net loader - set with AssemblyVersion attribute:
usually in Properties/AssemblyInfo.cs.
Must be in major.minor.build.version format, all numbers, or the compiler
throw a CS7034 error:

error CS7034: The specified version string does not conform to the required format - major[.minor[.build[.revision]]]

File version, a property of the file itself and inspect-able in the Details
section of the file properties dialog is set using the AssemblyFileVersion attribute.
There’s a warning, but not an error
(unless we have \<TreatErrorsAsWarnings>true\</TreatErrorsAsWarnings>, which we should),
if we don’t follow the same format as the assembly version:

warning CS7035: The specified version string does not conform to the recommended format - major.minor.build.revision

Product version is another property of visible in the file properties dialog,
is set using the AssemblyInformationalVersion attribute,
and is the most permissible of the three as it literally accepts any string,
although we should set it to something reasonable and meaningful to
whomever inspects it.

This Stack Overflow answer,
and the ones that follow,
provides really good descriptions of each attribute, its limitations,
and intended use.

Because we want to include the branch name and the commit id (SHA1),
the AssemblyInformationalVersion is the only we can use.

We propose the following format: Major.minor.branch-sha1.

The assembly version can be dynamically versioned by MSBuild using
the format [assembly: AssemblyVersion("1.0.*")] as a way of providing
supplemental information about the date and time of build -
see the Remarks section of the AssemblyVersion docs.

Implementation

We’ll make use of the Cake.Git add-in and Cake’s ability
to generate the assembly information using CreateAssemblyInfo method.

To simplify matters, we’ll split AssemblyInformationalVersion attribute
from the Properties/AssemblyInfo.cs file into its own
Properties/AssemblyInfoVersion.cs. Its content is unimportant,
but we’ll start with a value of:

[assembly: System.Reflection.AssemblyInformationalVersion("1.0.0.0")]

Next we’ll create a Task("Version") in our build.cake file that
creates the AssemblyInfoVersion.cs file, we’ll make the Build
task depend upon it, and we’ll revert the changes at the end of
the build process.

#addinnuget:?package=Cake.Gitvarconfiguration=Argument("configuration","Debug");varthisRepo=MakeAbsolute(Directory("./"));varassemblyInfo=File("./TestAssemblyVersioning/Properties/AssemblyInfoVersion.cs");Task("Version").Does(()=>{varbranch=GitBranchCurrent(thisRepo);// The following is not the best approach// We should use LibGit2Sharp's ObjectDatabase.ShortenObjectId(),// but Cake.Git doesn't currently support it.varsha=branch.Tip.Sha.Substring(0,8);// TODO: branch.FriendlyName produces a name too long when using gitflow,// e.g. "1.0.12fa582d-feature/MYPROJ-2732-title_of_story_or_defect".// There should be an attempt to extract maybe the issue identifier// so that we end with something like "1.0.12fa582d-MYPROJ-2732"// or "1.0.12fa582d-f-title_of_story"CreateAssemblyInfo(assemblyInfo,newAssemblyInfoSettings{InformationalVersion=string.Format("1.0.{0}-{1}",branch.FriendlyName,sha)});});Task("Build").IsDependentOn("Version").IsDependentOn("Restore-NuGet-Packages").Does(()=>{if(IsRunningOnWindows()){MSBuild(sln,settings=>settings.SetConfiguration(configuration));}else{XBuild(sln,settings=>settings.SetConfiguration(configuration));}}).Finally(()=>{// restore assembly.cs filesGitCheckout(thisRepo,newFilePath[]{assemblyInfo});});

That’s it. Now every time we build the project using our build script,
the product version will reflect it accordingly:

Note 1: if we had multiple assemblies, like normal projects do,
we would have a single AssemblyInfoVersion.cs, likely in the root of the project,
and we would link that file into each project to ensure they all get
the same product version:

Note 2: it seems reasonable that we should maybe perform a check
to see if all changes have been committed before the build, otherwise
the build would incorporate the changes on disk while still picking up
the HEAD SHA1.

So? Liked it? Hated it? Thought it was stupid? Thought I was stupid? Deemed it to be informative? Want to lavish excessive praise or cast fiery insults? Contact me and have at it.