3

I'm using a PowerShell script to call msbuild and pass in a version number to OctopusDeploy like this:

msbuild "Xyz.sln" /t:Rebuild /p:Configuration=Release /p:RunOctoPack=true /p:OctopackPackageVersion=$versionNumber

... where $versionNumber is generated in the PS script. What I want to do is add the first 16 characters of the Git commit hash to the end of the version string so it will end up looking like:

2.yyyyMMdd.HHmmss-git-6d34e44340f95c2a

How can I do this? Can I get msbuild or Visual Studio to return the current git commit hash somehow, considering they now have built-in Git support?

1
  • If you want to manage versioning with git and .Net, feel free to have a look to GitVersion github.com/GitTools/GitVersion that help you do semantic versioning (good practice!). There is even a msbuild task... Time stamp is not a very good practice and you should prefer git topology (that gitversion help you to achieve easily) Commented May 14, 2017 at 17:49

3 Answers 3

14

You can actually do this directly in msbuild so that it works from VS and most CI systems without any extra steps (e.g. PowerShell scripts), even on the cross-platform dotnet CLI and mono.

You can create a file named Directory.Build.targets in the project or solution (> affects all projects) directory with the following contents (assuming MSBuild 15 / VS 2017. if lower, you'll need manual imports or insert this target into every project)

<Project>
  <Target Name="DetermineOctopackVersion" BeforeTargets="Build" Condition=" '$(RunOctoPack)' == 'true' ">
    <Exec Command="git rev-parse HEAD" ConsoleToMSBuild="true" StandardOutputImportance="low">
      <Output TaskParameter="ConsoleOutput" PropertyName="GitCommitHash" />
    </Exec>
    <PropertyGroup>
      <VersionDatePart>$([System.DateTime]::get_Now().ToString(yyyyMMdd.HHmmss))</VersionDatePart>
      <OctopackPackageVersion>2.$(VersionDatePart)-git-$(GitCommitHash.Substring(0,16))</OctopackPackageVersion>
    </PropertyGroup>
  </Target>
</Project>

If you want the property to be set on every build, not only when RunOctoPack is true, simply remove the Condition attribute.

But if you need to do it in PowerShell, you can call the git command and capture its output:

$commitHash = (git rev-parse HEAD).Substring(0,16)
$versionDatePart = [System.DateTime]::Now.ToString('yyyyMMdd.HHmmss')
$version = "1.$versionDatePart-git-$commitHash"

If you really want to avoid calling into git (though no decent build system setup is complete without a git installation..) you can also use [System.IO.File]::ReadAllText(".git\refs\heads\master") both in PS or MSBuild to read from the git directory (on detached state, .git\HEAD will contain the hash, when a branch is used it will contain the location of the file to look for the hash).

Sign up to request clarification or add additional context in comments.

4 Comments

Am I right in thinking that both of your solutions require git.exe to be installed on the machine? That's not an assumption I can make in this scenario.
best practice is to use the version of git used to set up the build.. you can load libgit# like in the other version or look for the files yourself but i strongly suggest using the git.exe approach is it is the most cross-platform one (personally, i don't consider an environment without a git installation not to be a dev or build environment)
E.g. if you use dotnet msbuild, there's no way to download and resolve a LibGit# version that is guaranteed to work in the host runtime (since VS doesn't need to be installed and you could be running on linux)
What do you mean the git version that is used to "set up the build"?
1

As you wanted to avoid calling git.exe as per here and you want to have the commit processing in PowerShell you can covert the C# solution to PowerShell like this.

[System.Reflection.Assembly]::LoadFrom("C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\CommonExtensions\\Microsoft\\TeamFoundation\\Team Explorer\\LibGit2Sharp.dll") | Out-Null

$repo = [LibGit2Sharp.Repository]::new("C:\MyRepo")
$repo.Commits | Select-Object -First 1

This will return the LibGit2Sharp commit object with data like this

Message      : Further harden mutex closing process

MessageShort : Further harden mutex closing process
Encoding     : UTF-8
Author       : 
Committer    : 
Tree         : {.gitattributes, .gitignore, Build, Doc...}
Parents      : {fe26fc1a476f18bfa8a70c315fdbd96f1434d29c}
Notes        : {}
Id           : 1ba7bce90444a323fa9079cb06e5921afd0c3cd8
Sha          : 1ba7bce90444a323fa9079cb06e5921afd0c3cd8
Repository   : LibGit2Sharp.Repository

You need to invoke this with the 32-bit (x86) PowerShell.exe.

3 Comments

Why does this require the 32-bit version, and is there any way to do it without?
Note that with VS 2017, the might will be different for each installation depending on the edition of VS (community, enterprise,.. and released/preview), all of which can be installed side-by-side
Because this version of Visual Studio is 32-bit.
0

What I did in the end was just bundle NGit next to my Powershell script (files NGit.dll, Sharpen.dll, and ICSharpCode.SharpZipLib.dll) then use some code like this to generate the version number with git hash suffixed:

[System.Reflection.Assembly]::LoadFrom("Ngit.dll") | Out-Null
[System.Reflection.Assembly]::LoadFrom("Sharpen.dll") | Out-Null
[System.Reflection.Assembly]::LoadFrom("ICSharpCode.SharpZipLib.dll") | Out-Null

# *** Git repo base path (should contain .sln file) ***
$repoPath = "C:\Path\To\Repo"

# *** OctopusDeploy API key for publishing ***
$octoApiKey = "API-[PublishKey]"

#######################################################

# *** Get and process current Git commit hash ***
$sharpenRepoPath = New-Object -TypeName Sharpen.FilePath -ArgumentList "$($repoPath)\.git"
$repoBuilder = New-Object -TypeName NGit.RepositoryBuilder
$repo = $repoBuilder.SetGitDir($sharpenRepoPath).Build()
$headHash = $repo.Resolve("HEAD").Name.Substring(0,12)

# *** Version when pushing to OctopusDeploy NuGet ***
$versionNumber = "2." + [datetime]::now.tostring("yyyyMMdd.HHmmss") + "-git-" + $headHash

# *** Pause before publish ****
Write-Host "About to publish to OctopusDeploy NuGet with version number:"
Write-Host "    $($versionNumber)"
cmd /c pause

# *** OctopusDeploy build and push ***
msbuild "$repoPath\MySolution.sln" /t:Rebuild /p:Configuration=Release /p:RunOctoPack=true /p:OctopackPackageVersion=$versionNumber /p:OctoPackPublishPackageToHttp=https://my.nuget.server/nuget/packages /p:OctoPackPublishApiKey=$octoApiKey

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.