是否有 C# 命令行单行命令可以帮助我获取应用程序的 GIT 提交哈希?

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

此问题是 this other one 的后续问题。

在那个问题中,有人提到[assembly: AssemblyVersion(...)]对文件AssemblyInfo.cs文件的用法,同时我发现禁止在这一行之前执行任何处理,唯一允许的是:

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

原题:
所以我的问题是:是否有 Namespace.Class.AttributeNamespace.Class.Method() 包含 C# 应用程序的提交哈希(或 sha 或缩短的 sha)?

进一步调查后编辑
与此同时,我了解到命令 git describe --always 为我提供了我正在寻找的信息,所以我需要的是:

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

...但是我该如何执行 Launch()

我已经知道我可以使用 System.Diagnostics.Process() 启动命令行命令,就像这个例子:

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

...但是这种方式无法捕获该命令的结果。

新问题:
那么,有人知道用于启动命令行命令并获取结果的 C# 单行代码吗?

提前致谢

正如 Lasse V. Karslen 已经评论的那样,您的代码将触发编译器错误 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

在构建时添加程序集元数据的方法不止一种……可能不止这五种:

  • 程序集属性
  • dotnet-cli 参数
  • msbuild 参数
  • csproj 配置条目
  • 构建事件/脚本也是实现目标的一种方式,但更麻烦。

使用程序集属性

assembly 属性的问题是它需要是常量表达式。这不是直接实现的,而是 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 在 csproj 中配置到最终装配。

安装 gitinfo

PM> Install-Package GitInfo

在您的 csproj 文件中设置

<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

Add/Create AssemblyInfo.cs

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

使用 dotnet-cli(使用 powershell)

这很简单。

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

使用修改后的 csproj

修改后的 csproj 文件是 ci 中常用的方法。

将 'InformationVersion' 添加到您的 csproj:

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

在构建之前设置环境变量'GitHash'到'git describe --always'的输出:

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

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

资源管理器将在字段 'Product Version' 中显示 informationalVersion 的值。

不是一篇文章,但这篇文章 https://galdin.dev/blog/show-git-commit-sha-in-net-applications/ 展示了一种执行命令和访问结果的简单方法。本文描述的步骤如下,

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;

您现在可以使用 MsBuild 属性来设置版本(以及其他属性),而不是使用 AssemblyVersionAttribute。使用 MsBuild 的优势在于,您可以在构建过程中计算这些值。

这将适用于 any "new style"/"SDK style" project

查看:Assembly attribute properties

你最终会得到这样的结果:

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>

obj 文件夹中生成了一个文件,它自动包含在构建中。您可以在编辑器中打开此文件查看生成的内容:

生成的内容:

//------------------------------------------------------------------------------
// <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.

对我来说,优点是所有逻辑都很好地封装在构建文件本身中,并且不依赖于我在构建之前必须 运行 任何命令或将构建逻辑放入另一个脚本,像 powershell 脚本,Visual Studio 不知道的脚本。

请务必从项目中删除现有的、手动添加的 AssemblyVersion 等属性,否则您最终会收到一条警告,该属性被指定了两次。

这可能不能直接回答问题,运行时间工具更新版本。我将使用 C# 或多或少地更新 AssemblyInfo.cs 文件我不依赖于外部命令并将所有代码库放在一个地方。

首先,我找到了我的项目和具有 git 回购的解决方案的工作路径。

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";

下一步我安装 LibGit2Sharp NuGet 包。现在我使用这个包来获取提交 ID。

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

现在我创建了一个方法(灵感来自 here)读取 AssemblyInfo.cs 并添加提交 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);
    }
}

该方法简单地搜索任何类似于

的东西
[assembly: AssemblyFileVersion("1.0.0.0")]

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

并添加 -bc2050b 或编辑 -bc2050b 为新值(如果更改并保存)。

现在调用VersionWithGitInfo(path, commitId.Substring(0, 7));

和我的

[assembly: AssemblyFileVersion("1.0.0.0")]

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

您当然可以扩展该方法以涵盖其他参数,甚至可以使用它来更新您的版本号。