developer tip

.NET DLL에 git 커밋 해시 포함

copycodes 2020. 10. 7. 07:47
반응형

.NET DLL에 git 커밋 해시 포함


Git을 버전 제어로 사용하여 C # 애플리케이션을 구축하고 있습니다.

애플리케이션을 빌드 할 때 실행 파일에 마지막 커밋 해시를 자동으로 포함하는 방법이 있습니까?

예를 들어, 커밋 해시를 콘솔에 인쇄하는 것은 다음과 같습니다.

class PrintCommitHash
{
    private String lastCommitHash = ?? // What do I put here?
    static void Main(string[] args)
    {
        // Display the version number:
        System.Console.WriteLine(lastCommitHash );
    }
}

배포 된 실행 파일은 git repo에 액세스 할 수 없으므로 이는 runtime이 아닌 빌드 타임에 수행 해야합니다.

C ++ 관련 질문은 여기 에서 찾을 수 있습니다 . @mattanja의 요청에 따라

편집

내 프로젝트에서 사용하는 git hook 스크립트를 게시하고 있습니다. 설정:

  • 후크는 Linux 쉘 스크립트이며 path_to_project \ .git \ hooks 아래에 있습니다.
  • msysgit 을 사용 하는 경우 hooks 폴더에는 이미 몇 가지 샘플 스크립트가 포함되어 있습니다. git에서 호출하도록하려면 스크립트 이름에서 '.sample'확장자를 제거하십시오.
  • 후크 스크립트의 이름은이를 호출하는 이벤트와 일치합니다. 제 경우에는 post-commitpost-merge를 수정 했습니다 .
  • AssemblyInfo.cs 파일은 프로젝트 경로 바로 아래에 있습니다 ( .git 폴더 와 동일한 수준 ). 여기에는 23 줄이 포함되어 있으며 git을 사용하여 24 번째 줄을 생성합니다.

내 리눅스 쉘링이 약간 녹슬었기 때문에 스크립트는 AssemblyInfo.cs 의 처음 23 줄을 임시 파일로 읽고 git 해시를 마지막 줄에 에코 한 다음 파일 이름을 다시 AssemblyInfo.cs로 바꿉니다 . 이 작업을 수행하는 더 좋은 방법이 있다고 확신합니다.

#!/bin/sh
cmt=$(git rev-list --max-count=1 HEAD)
head -23 AssemblyInfo.cs > AssemblyInfo.cs.tmp
echo [assembly: AssemblyFileVersion\(\"$cmt\"\)] >> AssemblyInfo.cs.tmp
mv AssemblyInfo.cs.tmp AssemblyInfo.cs

도움이 되었기를 바랍니다.


버전을 추적하기 위해 git에서 태그를 사용합니다.

git tag -a v13.3.1 -m "version 13.3.1"

다음을 통해 git에서 해시 버전을 가져올 수 있습니다.

git describe --long

빌드 프로세스는 AssemblyInfo.cs 파일의 AssemblyInformationalVersion 특성에 git 해시를 넣습니다.

[assembly: AssemblyInformationalVersion("13.3.1.74-g5224f3b")]

컴파일 한 후에는 Windows 탐색기에서 버전을 볼 수 있습니다.

여기에 이미지 설명 입력

다음을 통해 프로그래밍 방식으로 가져올 수도 있습니다.

var build = ((AssemblyInformationalVersionAttribute)Assembly
  .GetAssembly(typeof(YOURTYPE))
  .GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false)[0])
  .InformationalVersion;

여기서 YOURTYPE은 AssemblyInformationalVersion 특성이있는 어셈블리의 모든 유형입니다.


version.txt 파일을 실행 파일에 포함시킨 다음 실행 파일에서 version.txt 를 읽을 수 있습니다 . version.txt 파일 을 생성하려면git describe --long

단계는 다음과 같습니다.

빌드 이벤트를 사용하여 git 호출

  • 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 속성을 선택합니다.

  • 빌드 이벤트에서 다음을 포함하는 빌드 전 이벤트를 추가하십시오 (따옴표에 유의하십시오).

    "C : \ Program Files \ Git \ bin \ git.exe"describe --long> "$ (ProjectDir) \ version.txt"

    그러면 프로젝트 디렉토리에 version.txt 파일 이 생성됩니다 .

실행 파일에 version.txt 포함

  • 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 기존 항목 추가를 선택합니다.
  • version.txt 파일 추가 (모든 파일을 볼 수 있도록 파일 선택기 필터 변경)
  • version.txt 를 추가 한 후 솔루션 탐색기에서 마우스 오른쪽 단추로 클릭하고 속성을 선택합니다.
  • 빌드 작업을 포함 된 리소스로 변경
  • 항상 복사하도록 출력 디렉토리로 복사 변경
  • 추가 의 version.txt 당신에 .gitignore의 파일

포함 된 텍스트 파일 버전 문자열 읽기

다음은 포함 된 텍스트 파일 버전 문자열을 읽는 몇 가지 샘플 코드입니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;

namespace TryGitDescribe
{
    class Program
    {
        static void Main(string[] args)
        {
            string gitVersion= String.Empty;
            using (Stream stream = Assembly.GetExecutingAssembly()
                    .GetManifestResourceStream("TryGitDescribe." + "version.txt"))
            using (StreamReader reader = new StreamReader(stream))
            {
                gitVersion= reader.ReadToEnd();
            }

            Console.WriteLine("Version: {0}", gitVersion);
            Console.WriteLine("Hit any key to continue");
            Console.ReadKey();
        }
    }
}

프로젝트에 포함 할 수있는 간단한 너겟 패키지를 만들었습니다. https://www.nuget.org/packages/MSBuildGitHash/

이 너겟 패키지는 "순수한"MSBuild 솔루션을 구현합니다. nuget 패키지에 의존하지 않으려면 이러한 대상을 csproj 파일에 복사하기 만하면되며 사용자 지정 어셈블리 속성으로 git 해시를 포함해야합니다.

<Target Name="GetGitHash" BeforeTargets="WriteGitHash" Condition="'$(BuildHash)' == ''">
  <PropertyGroup>
    <!-- temp file for the git version (lives in "obj" folder)-->
    <VerFile>$(IntermediateOutputPath)gitver</VerFile>
  </PropertyGroup>

  <!-- write the hash to the temp file.-->
  <Exec Command="git -C $(ProjectDir) describe --long --always --dirty &gt; $(VerFile)" />

  <!-- read the version into the GitVersion itemGroup-->
  <ReadLinesFromFile File="$(VerFile)">
    <Output TaskParameter="Lines" ItemName="GitVersion" />
  </ReadLinesFromFile>
  <!-- Set the BuildHash property to contain the GitVersion, if it wasn't already set.-->
  <PropertyGroup>
    <BuildHash>@(GitVersion)</BuildHash>
  </PropertyGroup>    
</Target>

<Target Name="WriteGitHash" BeforeTargets="CoreCompile">
  <!-- names the obj/.../CustomAssemblyInfo.cs file -->
  <PropertyGroup>
    <CustomAssemblyInfoFile>$(IntermediateOutputPath)CustomAssemblyInfo.cs</CustomAssemblyInfoFile>
  </PropertyGroup>
  <!-- includes the CustomAssemblyInfo for compilation into your project -->
  <ItemGroup>
    <Compile Include="$(CustomAssemblyInfoFile)" />
  </ItemGroup>
  <!-- defines the AssemblyMetadata attribute that will be written -->
  <ItemGroup>
    <AssemblyAttributes Include="AssemblyMetadata">
      <_Parameter1>GitHash</_Parameter1>
      <_Parameter2>$(BuildHash)</_Parameter2>
    </AssemblyAttributes>
  </ItemGroup>
  <!-- writes the attribute to the customAssemblyInfo file -->
  <WriteCodeFragment Language="C#" OutputFile="$(CustomAssemblyInfoFile)" AssemblyAttributes="@(AssemblyAttributes)" />
</Target>

여기에는 두 가지 목표가 있습니다. 첫 번째 "GetGitHash"는 BuildHash라는 MSBuild 속성에 git 해시를로드합니다 . BuildHash가 아직 정의되지 않은 경우 에만 이 작업을 수행합니다. 이렇게하면 원하는 경우 명령 줄에서 MSBuild에 전달할 수 있습니다. 다음과 같이 MSBuild에 전달할 수 있습니다.

MSBuild.exe myproj.csproj /p:BuildHash=MYHASHVAL

두 번째 대상인 "WriteGitHash"는 "CustomAssemblyInfo.cs"라는 임시 "obj"폴더의 파일에 해시 값을 기록합니다. 이 파일에는 다음과 같은 줄이 포함됩니다.

[assembly: AssemblyMetadata("GitHash", "MYHASHVAL")]

이 CustomAssemblyInfo.cs 파일은 어셈블리로 컴파일되므로 리플렉션을 사용 AssemblyMetadata하여 런타임 에 찾을 수 있습니다 . 다음 코드는 AssemblyInfo클래스가 동일한 어셈블리에 포함될 때이를 수행하는 방법을 보여줍니다 .

using System.Linq;
using System.Reflection;

public static class AssemblyInfo
{
    /// <summary> Gets the git hash value from the assembly
    /// or null if it cannot be found. </summary>
    public static string GetGitHash()
    {
        var asm = typeof(AssemblyInfo).Assembly;
        var attrs = asm.GetCustomAttributes<AssemblyMetadataAttribute>();
        return attrs.FirstOrDefault(a => a.Key == "GitHash")?.Value;
    }
}

이 디자인의 몇 가지 이점은 프로젝트 폴더의 파일을 건드리지 않고 모든 변경된 파일이 "obj"폴더 아래에 있다는 것입니다. 프로젝트는 Visual Studio 내에서 또는 명령 줄에서도 동일하게 빌드됩니다. 또한 프로젝트에 맞게 쉽게 사용자 정의 할 수 있으며 csproj 파일과 함께 소스 제어됩니다.


이를 수행하는 또 다른 방법은 On-Board Visual Studio 마법과 함께 NetRevisionTool 을 사용하는 입니다. Visual Studio 2013 Professional Edition에 대해 여기에서 보여줄 것이지만 다른 버전에서도 작동합니다.

따라서 먼저 NetRevisionTool을 다운로드하십시오. PATH에 NetRevisionTool.exe를 포함하거나 리포지토리에 체크인하고 Visual Studio 사전 빌드 및 사후 빌드 작업을 만들고 AssemblyInfo.cs를 변경합니다.

AssemblyInformationVersion에 git-hash를 추가하는 예는 다음과 같습니다. 프로젝트 설정에서 :

여기에 이미지 설명 입력

프로젝트의 AssemblyInfo.cs에서 다음 줄을 변경 / 추가합니다.

[어셈블리 : AssemblyInformationalVersion ( "1.1. {dmin : 2015}. {chash : 6} {!}-{branch}")]

표시된 스크린 샷에서 External / bin 폴더의 NetRevisionTool.exe에서 확인했습니다.

빌드 후 바이너리를 마우스 오른쪽 버튼으로 클릭하고 속성으로 이동하면 다음과 같은 내용이 표시됩니다.

여기에 이미지 설명 입력

이것이 누군가를 돕기를 바랍니다.


이 질문은 단계별 답변을 제공 할 가치가 있다고 생각합니다. 여기서 전략은 템플릿 파일을 가져 와서 git 태그 + 커밋 수 정보가 포함 된 AssemblyInfo.cs 파일을 생성하는 빌드 전 이벤트에서 powershell 스크립트를 실행하는 것입니다.

1 단계 : 원본 AssemblyInfo.cs를 기반으로하지만 다음을 포함하는 Project \ Properties 폴더에 AssemblyInfo_template.cs 파일을 만듭니다.

[assembly: AssemblyVersion("$FILEVERSION$")]
[assembly: AssemblyFileVersion("$FILEVERSION$")]
[assembly: AssemblyInformationalVersion("$INFOVERSION$")]

2 단계 : 소스가 다음과 같은 InjectGitVersion.ps1이라는 powershell 스크립트를 만듭니다.

# InjectGitVersion.ps1
#
# Set the version in the projects AssemblyInfo.cs file
#


# Get version info from Git. example 1.2.3-45-g6789abc
$gitVersion = git describe --long --always;

# Parse Git version info into semantic pieces
$gitVersion -match '(.*)-(\d+)-[g](\w+)$';
$gitTag = $Matches[1];
$gitCount = $Matches[2];
$gitSHA1 = $Matches[3];

# Define file variables
$assemblyFile = $args[0] + "\Properties\AssemblyInfo.cs";
$templateFile =  $args[0] + "\Properties\AssemblyInfo_template.cs";

# Read template file, overwrite place holders with git version info
$newAssemblyContent = Get-Content $templateFile |
    %{$_ -replace '\$FILEVERSION\$', ($gitTag + "." + $gitCount) } |
    %{$_ -replace '\$INFOVERSION\$', ($gitTag + "." + $gitCount + "-" + $gitSHA1) };

# Write AssemblyInfo.cs file only if there are changes
If (-not (Test-Path $assemblyFile) -or ((Compare-Object (Get-Content $assemblyFile) $newAssemblyContent))) {
    echo "Injecting Git Version Info to AssemblyInfo.cs"
    $newAssemblyContent > $assemblyFile;       
}

3 단계 : InjectGitVersion.ps1 파일을 BuildScripts 폴더의 솔루션 디렉터리에 저장합니다.

4 단계 : 프로젝트의 빌드 전 이벤트에 다음 줄 추가

powershell -ExecutionPolicy ByPass -File  $(SolutionDir)\BuildScripts\InjectGitVersion.ps1 $(ProjectDir)

5 단계 : 프로젝트를 빌드합니다.

6 단계 : 선택적으로 git ignore 파일에 AssemblyInfo.cs 추가


다른 답변에서 이미 git 비트를 언급했듯이 SHA가 있으면 AssemblyInfo.cs사전 빌드 후크에서 프로젝트 파일을 생성하는 것을 고려할 수 있습니다 .

이를 수행하는 한 가지 방법은 AssemblyInfo.cs.tmpl예를 들어 $$ GITSHA $$와 같이 SHA에 대한 자리 표시자가 있는 템플릿 파일 을 만드는 것입니다.

[assembly: AssemblyDescription("$$GITSHA$$")]

그런 다음 사전 빌드 후크가이 자리 표시자를 대체하고 C # 컴파일러가 선택할 수 있도록 AssemblyInfo.cs 파일을 출력해야합니다.

SVN 용 SubWCRev를 사용하여이 작업을 수행하는 방법을 보려면 이 답변을 참조하십시오 . git에게 비슷한 일을하는 것은 어렵지 않습니다.

다른 방법은 언급 한대로 "만들기 단계"입니다. 즉, 유사한 작업을 수행하는 MSBuild 작업을 작성합니다. 또 다른 방법은 DLL을 어떻게 든 처리하는 것입니다 (ildasm + ilasm 말).하지만 위에서 언급 한 옵션이 아마도 가장 쉬울 것 같습니다.


완전히 자동화되고 유연한 방법 체크 아웃 https://github.com/Fody/Stamp . 우리는 이것을 Git 프로젝트에 성공적으로 사용했습니다 ( SVN 프로젝트에도이 버전 ).


powershell one-liner를 사용하여 커밋 해시로 모든 assemblyinfo 파일을 업데이트 할 수 있습니다.

$hash = git describe --long --always;gci **/AssemblyInfo.* -recurse | foreach { $content = (gc $_) -replace "\[assembly: Guid?.*", "$&`n[assembly: AssemblyMetadata(`"commithash`", `"$hash`")]" | sc $_ }

나는 받아 들여지는 대답과 작은 adition의 조합을 사용하고 있습니다. 빌드 전에 템플릿을 다시 실행하기 위해 AutoT4 확장 프로그램 ( https://marketplace.visualstudio.com/items?itemName=BennorMcCarthy.AutoT4 )을 설치했습니다 .

GIT에서 버전 가져 오기

나는이 git -C $(ProjectDir) describe --long --always > "$(ProjectDir)git_version.txt"프로젝트 속성에서 내 빌드 전 이벤트. .gitignore에 git_version.txt 및 VersionInfo.cs를 추가하는 것은 좋은 생각입니다.

메타 데이터에 버전 포함

VersionInfo.tt내 프로젝트에 템플릿을 추가했습니다 .

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ output extension=".cs" #>

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

<#
if (File.Exists(Host.ResolvePath("git_version.txt")))
{
    Write("[assembly: AssemblyInformationalVersion(\""+ File.ReadAllText(Host.ResolvePath("git_version.txt")).Trim() + "\")]");
}else{
    Write("// version file not found in " + Host.ResolvePath("git_version.txt"));
}

#>

Now I have my git tag + hash in "ProductVersion".


Referring to the another answer (https://stackoverflow.com/a/44278482/4537127) i also utilised the VersionInfo.tt text template to generate AssemblyInformationalVersion without AutoT4.

(Atleast works in my C# WPF application)

Problem was that the Pre-build events were run after template transformations, so after cloning, the git_version.txt file was not there and build fails. After creating it manually to allow transformation to pass once, it was updated after transformation, and was always one commit behind.

I had to make two adjustments to the .csproj file (this applies at least for Visual Studio Community 2017)

1) Import the Text Transformation Targets and make template transformations to run on every build: (Ref https://msdn.microsoft.com/en-us/library/ee847423.aspx)

<PropertyGroup>
    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
    <TransformOnBuild>true</TransformOnBuild>
    <TransformOutOfDateOnly>false</TransformOutOfDateOnly>
</PropertyGroup>

and after <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

<Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" />

2) Make the git describe run before template transformations (so that git_version.txt is there when VersionInfo.tt is transformed) :

<Target Name="PreBuild" BeforeTargets="ExecuteTransformations">
  <Exec Command="git -C $(ProjectDir) describe --long --always --dirty &gt; $(ProjectDir)git_version.txt" />
</Target>

..And the C# code to get the AssemblyInformationalVersion (Ref https://stackoverflow.com/a/7770189/4537127)

public string AppGitHash
{
    get
    {
        AssemblyInformationalVersionAttribute attribute = (AssemblyInformationalVersionAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false).FirstOrDefault();

        return attribute.InformationalVersion;
    }
}

..And add the generated files to .gitignore

VersionInfo.cs
git_version.txt

Another way would be to generate a Version.cs file from a Pre-Build step. I explored this in a little proof-of-concept project which prints out its current commit hash.

Tha project is uploaded on https://github.com/sashoalm/GitCommitHashPrinter.

The batch code which creates the Version.cs file is this:

@echo off

echo "Writing Version.cs file..."

@rem Pushd/popd are used to temporarily cd to where the BAT file is.
pushd $(ProjectDir)

@rem Verify that the command succeeds (i.e. Git is installed and we are in the repo).
git rev-parse HEAD || exit 1

@rem Syntax for storing a command's output into a variable (see https://stackoverflow.com/a/2340018/492336).
@rem 'git rev-parse HEAD' returns the commit hash.
for /f %%i in ('git rev-parse HEAD') do set commitHash=%%i

@rem Syntax for printing multiline text to a file (see https://stackoverflow.com/a/23530712/492336).
(
echo namespace GitCommitHashPrinter
echo {
echo     class Version
echo     {
echo         public static string CommitHash { get; set; } = "%commitHash%";
echo     }
echo }
)>"Version.cs"

popd    

  1. 빌드시 외부 프로그램을 호출하고 출력을 가로채는 방법을 알고 있기를 바랍니다.
  2. git의 작업 디렉토리에서 버전이 지정되지 않은 파일을 무시하는 방법을 알고 있기를 바랍니다.

@ learath2에서 언급했듯이의 출력은 git rev-parse HEAD일반 해시를 제공합니다.

당신이 망할 놈의-저장소에 태그를 사용하는 경우 (당신이 태그를 사용, 그것은 더 자세한 설명과 이상 읽을 수없는 git rev-parse), 출력에서 수신 할 수있다 git describe(도 성공적으로 나중에 사용하면서 git checkout)

다음에서 rev-parse | describe를 호출 할 수 있습니다.

  • 일부는 무대를 만든다
  • 커밋 후 후크
  • 얼룩 필터에서 얼룩 / 청소 필터 구현 방식을 선택하는 경우

참고 URL : https://stackoverflow.com/questions/15141338/embed-git-commit-hash-in-a-net-dll

반응형