Вставить git commit хэш в a.Net dll



Я создаю приложение на C#, используя Git в качестве контроля версий.



есть ли способ автоматически вставлять последний хэш фиксации в исполняемый файл, когда я создаю свое приложение?



например, печать хэша фиксации в консоль будет выглядеть примерно так:



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


обратите внимание, что это должно быть сделано в построить времени, а не runtime, так как мой развернутый исполняемый файл не будет иметь доступ к репозиторию git.



A смежный вопрос для C++ можно найти здесь.


EDIT



По запросу @mattanja я публикую скрипт git hook, который я использую в своих проектах. Настройка:




  • крючки-это скрипты оболочки linux, которые помещаются под: path_to_project.githooks

  • если вы используете msysgit на крючки папка уже содержит некоторые примеры сценариев. Для того, чтобы сделать ГИТ позвони им, убери '.пример ' расширение из имени скрипта.

  • имена скриптов hook соответствуют событию, которое их вызывает. В моем случае, я изменил post-commit и после слияния.

  • мой AssemblyInfo.cs файл находится непосредственно под путем проекта (тот же уровень, что и .ГИТ). Он содержит 23 строки, и я использую git для создания 24-го.


Как мой linux-обстрел немного ржавый, скрипт просто читает первые 23 строки AssemblyInfo.cs во временный файл, повторяет хэш 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


надеюсь, что это помогает.

551   12  

12 ответов:

мы используем теги в Git для отслеживания версий.

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

вы можете получить версию с хэшем от git через:

git describe --long

наш процесс сборки помещает хэш git в атрибут AssemblyInformationalVersion объекта AssemblyInfo.cs файл:

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

после компиляции вы можете просмотреть версию из Проводника windows:

enter image description here

вы также можете получить его программно через:

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

где YOURTYPE-это любой тип сборка, имеющая атрибут AssemblyInformationalVersion.

Вы можете вставить версия.txt файл в исполняемый файл, а затем прочитать версия.txt из исполняемого файла. Чтобы создать версия.txt используйте git describe --long

вот шаги:

используйте событие сборки для вызова git

  • Правой Кнопкой Мыши на проекте и выберите Свойства

  • в событиях сборки добавьте предварительную сборку событие, содержащее (обратите внимание на кавычки):

    "C:\Program файлы\Git\bin\git.exe "describe --long >" $(ProjectDir)\version.txt"

    это создаст версия.txt файл в каталоге проекта.

добавьте версию.txt в исполняемом файле

  • щелкните правой кнопкой мыши на проекте и выберите Добавить существующий элемент
  • добавить версия.txt (изменить фильтр выбора файлов, чтобы вы могли видеть все файлы)
  • после версия.txt добавляется, щелкните правой кнопкой мыши на нем в обозревателе решений и выберите Свойства
  • изменить действие при построении значение внедренный ресурс
  • изменить копировать в выходной каталог значение всегда копировать
  • добавить версия.txt на .gitignore file

чтение встроенного текстового файла строка версии

вот пример кода для чтения строки версии встроенного текстового файла:

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();
        }
    }
}

Я создал простой пакет nuget, который вы можете включить в свой проект, который позаботится об этом для вас:https://www.nuget.org/packages/MSBuildGitHash/

этот пакет nuget реализует "чистое" решение 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", загружает git-хэш в свойство MSBuild с именем BuildHash, it только делает это, если BuildHash еще не определен. Это позволяет передать его в MSBuild в командной строке, если вы предпочитаете. Вы можете передать его в MSBuild следующим образом:

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

вторая цель, "WriteGitHash", запишет хэш-значение в файл во временной папке" obj "с именем" CustomAssemblyInfo.цезий." Этот файл будет содержать строку, которая выглядит например:

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

другой способ сделать это-использовать NetRevisionTool С некоторыми на борту Visual Studio magic. Я продемонстрирую это здесь для Visual Studio 2013 Professional Edition, но это будет работать и с другими версиями.

Итак, сначала загрузите NetRevisionTool. Вы включаете NetRevisionTool.exe в ваш путь или проверить его в свой репозиторий и создать визуальную студию перед построением и после построения действий и изменить свою файле AssemblyInfo.цезий.

An пример, который добавит ваш git-хэш в вашу AssemblyInformationVersion, будет следующим: В настройках Вашего проекта:

enter image description here

в AssemblyInfo.cs вашего проекта вы меняете / добавляете строку:

[сборка: AssemblyInformationalVersion ("1.1.{dmin: 2015}.{chash: 6}{!}- {branch}")]

на показанном скриншоте я проверил NetRevisionTool.exe в папке External/bin

после сборки, если вы затем щелкните правой кнопкой мыши двоичный файл и заходим в свойства, то вы должны увидеть примерно следующее:

enter image description here

надеюсь, что это поможет кому-то там

Я думаю, что этот вопрос стоит дать полный шаг за шагом ответ. Стратегия здесь заключается в запуске сценария powershell из событий предварительной сборки, который принимает файл шаблона и создает AssemblyInfo.cs-файл с включенной информацией о количестве фиксаций git tag+.

Шаг 1: сделать AssemblyInfo_template.cs-файл в папке Project\Properties, основанный на исходном AssemblyInfo.cs но содержащий:

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

Шаг 2: Создайте сценарий powershell с именем InjectGitVersion. ps1, источником которого является:

# 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: дополнительно добавьте AssemblyInfo.cs в ваш файл git ignore

поскольку другой ответ уже упоминает бит git, как только у вас есть SHA, вы можете рассмотреть возможность создания AssemblyInfo.cs файл вашего проекта в крючке предварительной сборки.

один из способов сделать это является создание AssemblyInfo.cs.tmpl файл шаблона, с местозаполнителем для вашего ша, скажем, $$GITSHA$$, например,

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

ваш крючок предварительной сборки затем должен заменить этот заполнитель и вывести AssemblyInfo.cs-файл для компилятора C#, чтобы забрать.

чтобы увидеть, как это можно сделать использование SubWCRev для SVN см. ответ. Это не должно быть трудно сделать что-то подобное для Git.

другие способы были бы" сделать этап", как уже упоминалось, т. е. написать задачу MSBuild, которая делает что-то подобное. Еще один способ может заключаться в том, чтобы как-то обработать DLL (ildasm+ilasm say), но я думаю, что упомянутые выше варианты, вероятно, проще всего.

для полностью автоматизированной и гибкой проверки метода https://github.com/Fody/Stamp. мы успешно использовали это для наших проектов Git (а также эта версия для проектов SVN)

вы можете использовать однострочную оболочку powershell для обновления всех файлов assemblyinfo с помощью хэша фиксации.

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

Я использую комбинацию принятого ответа и небольшого дополнения. У меня установлено расширение Th AutoT4 (https://marketplace.visualstudio.com/items?itemName=BennorMcCarthy.AutoT4) для повторного запуска шаблонов перед сборкой.

получение версии от GIT

у меня есть git -C $(ProjectDir) describe --long --always > "$(ProjectDir)git_version.txt" в моем предварительном событии в свойствах проекта. Добавление git_version.txt и VersionInfo.cs to .gitignore-это довольно хорошая идея.

внедрение версии в метаданные

я добавил 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"));
}

#>

Теперь у меня есть мой git тег + хэш в "ProductVersion".

ссылаясь на другой ответ (https://stackoverflow.com/a/44278482/4537127) я также использовал VersionInfo.tt текстовый шаблон для создания AssemblyInformationalVersion без AutoT4.

(по крайней мере, работает в моем приложении C# WPF)

проблема заключалась в том, что события предварительной сборки запускались после преобразований шаблона, поэтому после клонирования git_version.txt файл не был там и построить не удается. После его создания вручную, чтобы разрешить преобразование пройти один раз, он был обновлен после превращения, так и было всегда один коммит за.

мне пришлось внести две корректировки .csproj файл (это относится, по крайней мере, для Visual Studio Community 2017)

1) импортируйте целевые объекты преобразования текста и выполняйте преобразования шаблонов для каждой сборки: (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>

и после <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

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

2) Сделать git describe run перед преобразованиями шаблона (так что git_version.txt когда VersionInfo.tt преобразована) :

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

..И код C#, чтобы получить 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;
    }
}

..И добавьте сгенерированные файлы .gitignore

VersionInfo.cs
git_version.txt

другой способ-создать версию.cs-файл с этапа предварительной сборки. Я исследовал это в небольшом проекте proof-of-concept, который печатает свой текущий хэш фиксации.

Tha проект загружен на https://github.com/sashoalm/GitCommitHashPrinter.

пакетный код, который создает версию.cs файл это:

@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-репозитории (и вы используете теги, разве это не более описательно и читаемо, чем git rev-parse), вывод может быть получен из git describe (в то время как также успешно используется позже в git checkout)

вы можете вызвать rev-parse / описать в:

Comments

    Ничего не найдено.