Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a C# commandline command one-liner which can help me get the GIT commit hash of an application?

This question is a follow-up of this other one.

In that question, one mentions the usage of [assembly: AssemblyVersion(...)] to the file AssemblyInfo.cs file, and in the meanwhile I've found out that it's forbidden to execute any processing before such a line, the only thing which is allowed is something like:

[assembly: AssemblyVersion("1.0.0.0" + "-" + Namespace.Class.Attribute)], or:
[assembly: AssemblyVersion("1.0.0.0" + "-" + Namespace.Class.Method())]

Original question:
So my question: is there a Namespace.Class.Attribute or Namespace.Class.Method() which contains the commit hash (or sha or shortened sha) of a C# application?

Edit after more investigation
In the meantime I've learnt that the command git describe --always gives me the information I'm looking for, so what I need is something like:

[assembly: AssemblyVersion("1.0.0.0-" + Launch("git describe --always")]

... but how can I execute that Launch()?

I already know that I can launch a commandline command using System.Diagnostics.Process(), like this example:

System.Diagnostics.Process.Start(foldervar + "application.exe", "inputfile.txt");

... but this way does not catch the result of that command.

New question:
So, does anybody know a C# one-liner for launching commandline commands and getting their result?

Thanks in advance

like image 662
Dominique Avatar asked Dec 14 '21 16:12

Dominique


People also ask

Why is there a slash in AC?

Senior Member. You read it as "ei-cee" (no "slash" pronounced). In terms of distinguishing between "air conditioning" and "air conditioner," I can think of an example like "Today, I bought a new air conditioner" ("conditioning" not allowed). I personally would not say "Today, I bought a new AC."

Why is it called AC?

Air conditioning, often abbreviated as A/C or AC, is the process of removing heat from an enclosed space to achieve a more comfortable interior environment (sometimes referred to as 'comfort cooling') and in some cases also strictly controlling the humidity of internal air.

What do you mean by AC?

a/ c is an abbreviation for air-conditioning. Keep your windows up and the a/c on high.

What is C--?

C-- is a "portable assembly language ", designed to ease the implementation of compilers that produce high-quality machine code. This is done by delegating low-level code-generation and program optimization to a C-- compiler.

Does C have references?

Does C have references? Bookmark this question. Show activity on this post. Show activity on this post. No, it doesn't. It has pointers, but they're not quite the same thing. In particular, all arguments in C are passed by value, rather than pass-by-reference being available as in C++.

Is there a language similar to C+?

The closest was called C with Classes, Bjarne Stroustrup's C macro package that eventually evolved into C++ with a full compiler. That said, there have been several parodic languages with names like C+ (and C-, plus two "low-level C" languages called C-- that I know of) and a couple of languages with C+ in the name.

What is the type system in C?

Type system. The C-- type system is deliberately designed to reflect constraints imposed by hardware rather than conventions imposed by higher-level languages. In C--, a value stored in a register or memory may have only one type: bit vector.


4 Answers

As Lasse V. Karslen already commented, your code will trigger a compiler error CS0182. Next problem is the required format for AssemblyVersion - major[.minor[.build[.revision]]], there are other assembly metadata fields that can be used for strings - e.g. InformationalVersion.

There is more than one way to add assembly meta data while building... there are probably more then these five:

  • assembly attribute
  • dotnet-cli parameter
  • msbuild parameter
  • csproj config entry
  • Build Events / Scripting is also a way to reach your goal, but is more fiddeling.

Using assembly attribute

The problem with the assembly attribute is that it need to be constant expression. That is not straight forward to achieve, but Gitinfo managed to serve a solution. An other disadvantage is the need to disable the compiler to generate the AssemblyInfo.cs that will break writing some values configured in csproj to the final assembly.

Install gitinfo

PM> Install-Package GitInfo

Set in your csproj file

<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

Add/Create AssemblyInfo.cs

[assembly: AssemblyInformationalVersion(ThisAssembly.Git.Commit)]

Using dotnet-cli (using powershell)

Thats straight forward.

$GitHash=git describe --always
dotnet build -p:InformationalVersion=$GitHash

Using modified csproj

Modified csproj files are a common approach used in ci.

Add 'InformationVersion' to your csproj:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <InformationalVersion>$(GitHash)</InformationalVersion>
  </PropertyGroup>
</Project>

Set the enviroment variable 'GitHash' before building to the output of 'git describe --always':

$env:GitHash=git describe --always
dotnet build

E.g. GithubactionsHellowWord is a project example that uses github actions built in environment variable to write sha1 hash to the assembly metadata.

The explorer will show the value of informationalVersion in the field 'Product Version'.

Assembly properties

like image 109
stefan.seeland Avatar answered Oct 20 '22 13:10

stefan.seeland


Instead of using the AssemblyVersionAttribute, you can now use MsBuild properties to set the version (among other attributes). The advantage of using MsBuild, is that you can calculate these values as part of the build process.

This will work for any "new style"/"SDK style" project.

Check out: Assembly attribute properties.

You'll end up with something along these lines:

ConsoleApp5.csproj:
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net6.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
    </PropertyGroup>

    <!-- Add the property group and the target below to your project file -->
    <PropertyGroup>
        <GenerateAssemblyVersionAttribute>true</GenerateAssemblyVersionAttribute>
        <GenerateAssemblyFileVersionAttribute>true</GenerateAssemblyFileVersionAttribute>
        <GenerateAssemblyInformationalVersionAttribute>true</GenerateAssemblyInformationalVersionAttribute>
    </PropertyGroup>

    <Target Name="AddGitShaToAssemblyVersions" BeforeTargets="GetAssemblyVersion" Returns="AssemblyVersion, FileVersion, InformationalVersion">
        <Exec ConsoleToMsBuild="true" Command="git describe --always">
            <Output TaskParameter="ConsoleOutput" PropertyName="GitSha" />
        </Exec>

        <PropertyGroup>
            <AssemblyVersion>1.1.1.1</AssemblyVersion>
            <FileVersion>1.1.1.1-$(GitSha)</FileVersion>
            <InformationalVersion>1.1.1.1-$(GitSha)</InformationalVersion>
        </PropertyGroup>
    </Target>

    <!-- Ignore the warning generated for the AssemblyFileVersion -->
    <PropertyGroup>
      <NoWarn>$(NoWarn);7035</NoWarn>
    </PropertyGroup>
</Project>

A file is generated in the obj folder and it's automatically included in the build. You can open this file in your editor to look at the generated content:

enter image description here

Generated content:

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System;
using System.Reflection;

[assembly: System.Reflection.AssemblyCompanyAttribute("ConsoleApp5")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.1.1.1-3654148")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.1.1.1-3654148")]
[assembly: System.Reflection.AssemblyProductAttribute("ConsoleApp5")]
[assembly: System.Reflection.AssemblyTitleAttribute("ConsoleApp5")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.1.1.1")]

// Generated by the MSBuild WriteCodeFragment class.

To me the advantage is that all of the logic is nicely encapsulated in the build files themselves and won't depend on my having to run any commands prior to build or putting build logic into another script, like a powershell script, scripts that Visual Studio isn't aware of.

Do make sure you remove your existing, manually added, AssemblyVersion etc attributes from your project, or you'll end up with a warning the attribute was specified twice.

like image 27
jessehouwing Avatar answered Oct 20 '22 12:10

jessehouwing


Not a one liner, but this article https://galdin.dev/blog/show-git-commit-sha-in-net-applications/ shows a simple way to execute the command and access the result. The steps described in this article are as follows,

To do this we create a pre-build event that'll execute a git command and save it in a text file. We then add that generated text file as a string resource. The resource can will now be accessible from C#.

  1. Right click on the web application and click on properties.

  2. Go to the build events tab and type the following in the Pre-build event command line:

    git rev-parse HEAD --short > "$(ProjectDir)\CurrentCommit.txt"
    

    The command can obviously be replaced by anything you see fit.

  3. Save and build the project. (Ctrl+Shift+S, Ctrl+Shift+B)

  4. A new file called CurrentCommit.txt should be created in the root of your project.

  5. Go ahead and exclude it from Source Control

  6. In the projects properties page, go to the Resources tab and Add Existing File CurrentCommit.txt as a resource.

The contents of the generated file can now be accessed as:

Your.NameSpace.Properties.Resources.CurrentCommit;
like image 29
Hem Bhagat Avatar answered Oct 20 '22 12:10

Hem Bhagat


This might not answer the question directly, a running time tooling to update version. I will use C# to update the AssemblyInfo.cs file more or less I am not depending on external commands and have all codebases in one place.

First I find where is my working path for my project and for the solution that has git repo in.

string workingDirectory = Environment.CurrentDirectory;
var root = Directory.GetParent(workingDirectory)?.Parent;
var repositoryPath = $@"{root?.Parent?.FullName}\.git";
string projectDirectory = root?.FullName;
string path = $@"{projectDirectory}\Properties\AssemblyInfo.cs";

Next step I install LibGit2Sharp NuGet package. Now I use this package to get the commit id.

string commitId;
using (var repo = new Repository(repositoryPath))
{
    var headCommit = repo.Head.Commits.First();
    commitId = headCommit.Id.Sha;
}

Now I create a method (inspired from here) that read AssemblyInfo.cs and add commit id.

static void VersionWithGitInfo(string path, string commitId)
{
    if (File.Exists(path))
    {
        var file = File.ReadAllText(path);
        var newVersion = Regex.Replace(
            file,
            @"(?<=\[assembly: AssemblyFileVersion\(""[0-9]*.[0-9]*.[0-9]*.[0-9]*)(-[a-z0-9]{0,7})?(?=""\)\])",
            m => $"-{commitId}"
                );
        File.WriteAllText(path, newVersion);
    }
}

The method simply search for any thing similar to

[assembly: AssemblyFileVersion("1.0.0.0")]

Or

[assembly: AssemblyFileVersion("1.0.0.0-bc2050b")]

And add -bc2050b or edit -bc2050b to new value if it changes and save it.

Now lets call VersionWithGitInfo(path, commitId.Substring(0, 7));

and my

[assembly: AssemblyFileVersion("1.0.0.0")]

to

[assembly: AssemblyFileVersion("1.0.0.0-bc2050b")]

You can of course extend the method to cover other parameters, or even use it to update your version number.

like image 30
Maytham Avatar answered Oct 20 '22 12:10

Maytham