Вставить git commit hash в .Net dll
Я создаю приложение С#, используя Git как мой контроль версий.
Есть ли способ автоматически вставлять последний хеш фиксации в исполняемый файл при создании моего приложения?
Например, печать хэша commit на консоли будет выглядеть примерно так:
class PrintCommitHash
{
private String lastCommitHash = ?? // What do I put here?
static void Main(string[] args)
{
// Display the version number:
System.Console.WriteLine(lastCommitHash );
}
}
Обратите внимание, что это нужно делать в строить время, а не время выполнения, так как мой развернутый исполняемый файл не будет иметь доступ к репозиторию Git.
Соответствующий вопрос для С++ можно найти здесь .
ИЗМЕНИТЬ
По запросу @mattanja я отправляю Git hook script, который я использую в своих проектах. Настройка:
- Крючки - это скрипты linux shell, которые помещаются под: path_to_project \.git\hooks
- Если вы используете msysgit, папка hooks уже содержит некоторые примеры скриптов. Чтобы сделать их Git, удалите расширение ".sample" из имени script.
- Имена скриптов hook совпадают с вызывающим их событием. В моем случае я модифицировал post-commit и post-merge.
- Мой файл AssemblyInfo.cs находится непосредственно под контуром проекта (тот же уровень, что и папка .git). Он содержит 23 строки, и я использую Git для генерации 24-го.
Поскольку мой linux-обход немного ржавый, script просто считывает первые 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
Надеюсь, что это поможет.
Ответы
Ответ 1
Мы используем теги в 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.
Ответ 2
Вы можете вставить файл version.txt в исполняемый файл, а затем прочитать version.txt из исполняемого файла. Чтобы создать файл version.txt, используйте git describe --long
Вот шаги:
Используйте событие Build для вызова git
-
Щелкните правой кнопкой мыши проект и выберите "Свойства"
-
В событиях сборки добавьте событие Pre-Build, содержащее (обратите внимание на кавычки):
"C:\Program Files\ Git\bin\git.exe" описать -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();
}
}
}
Ответ 3
Другой способ сделать это - использовать NetRevisionTool с помощью встроенной магии Visual Studio. Я продемонстрирую это здесь для Visual Studio 2013 Professional Edition, но это будет работать и с другими версиями.
Итак, сначала загрузите NetRevisionTool.
Вы включаете NetRevisionTool.exe в свой PATH или проверяете его в своем репозитории и создаете предварительную сборку визуальной студии и действие после сборки и меняете AssemblyInfo.cs.
Примером, который добавит ваш git -hash в AssemblyInformationVersion, будет следующее:
В настройках вашего проекта:
![enter image description here]()
в AssemblyInfo.cs вашего проекта вы меняете/добавляете строку:
[сборка: AssemblyInformationalVersion ( "1.1. {dmin: 2015}. {chash: 6} {!} - {branch}" )]
в показанном скриншоте, который я проверил в NetRevisionTool.exe в папке External/bin
После сборки, если вы затем щелкните правой кнопкой мыши свой двоичный файл и перейдите к свойствам, вы увидите следующее:
![enter image description here]()
Надеюсь, это поможет кому-то там.
Ответ 4
Я думаю, что этот вопрос стоит дать полный пошаговый ответ. Стратегия здесь - запустить powershell script из событий предварительной сборки, которые принимают файл шаблона и генерирует файл AssemblyInfo.cs с включенной меткой git. +/.
Шаг 1: создайте файл AssemblyInfo_template.cs в папке Project\Properties на основе вашего исходного AssemblyInfo.cs, но содержащий:
[assembly: AssemblyVersion("$FILEVERSION$")]
[assembly: AssemblyFileVersion("$FILEVERSION$")]
[assembly: AssemblyInformationalVersion("$INFOVERSION$")]
Шаг 2: Создайте файл powershell script с именем 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: Добавьте следующую строку в проект. События Pre-Build
powershell -ExecutionPolicy ByPass -File $(SolutionDir)\BuildScripts\InjectGitVersion.ps1 $(ProjectDir)
Шаг 5: Создайте свой проект.
Шаг 6: При необходимости добавьте AssemblyInfo.cs в свой файл git ignore
Ответ 5
Я создал простой пакет 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 > $(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, он делает это только в том случае, если BuildHash еще не определен. Это позволяет передать его в MSBuild в командной строке, если хотите. Вы можете передать его в MSBuild следующим образом:
MSBuild.exe myproj.csproj /p:BuildHash=MYHASHVAL
Вторая цель, "WriteGitHash", напишет хэш-значение для файла во временной папке "obj" с именем "CustomAssemblyInfo.cs". Этот файл будет содержать строку, которая выглядит так:
[assembly: AssemblyMetadata("GitHash", "MYHASHVAL")]
Этот файл CustomAssemblyInfo.cs будет скомпилирован в вашу сборку, поэтому вы можете использовать отражение для поиска AssemblyMetadata
во время выполнения.
Некоторые преимущества этого дизайна заключаются в том, что он не касается каких-либо файлов в папке проекта, все мутированные файлы находятся в папке "obj". Ваш проект также будет построен идентично из Visual Studio или из командной строки. Он также может быть легко настроен для вашего проекта и будет контролироваться исходным кодом вместе с вашим файлом csproj.
Ответ 6
Поскольку в другом ответе уже упоминается бит git, после того, как у вас есть SHA, вы можете подумать о создании файла AssemblyInfo.cs
вашего проекта в предварительном сборке.
Один из способов сделать это - создать файл шаблона AssemblyInfo.cs.tmpl
, с помощью заполнителя для вашего SHA, например $$ GITSHA $$, например.
[assembly: AssemblyDescription("$$GITSHA$$")]
Затем вы должны заменить этот заполнитель и вывести файл AssemblyInfo.cs для компилятора С#.
Чтобы узнать, как это можно сделать с помощью SubWCRev для SVN, см. этот ответ. Не должно быть трудно сделать что-то подобное для git.
Другими способами может быть "этап выполнения", как упомянуто, т.е. написать задачу MSBuild, которая делает что-то подобное. Еще один способ - как-то обработать DLL (ildasm + ilasm say), но я думаю, что упомянутые выше варианты, вероятно, самые простые.
Ответ 7
Для полностью автоматизированного и гибкого метода проверки https://github.com/Fody/Stamp. Мы успешно использовали это для наших проектов Git (а также эта версия для проектов SVN)
Ответ 8
Вы можете использовать однострочный файл powershell для обновления всех файлов assemblyinfo с помощью хэша commit.
$hash = git describe --long --always;gci **/AssemblyInfo.* -recurse | foreach { $content = (gc $_) -replace "\[assembly: Guid?.*", "$&`n[assembly: AssemblyMetadata(`"commithash`", `"$hash`")]" | sc $_ }
Ответ 9
Я использую комбинацию принятого ответа и небольшого дополнения.
У меня установлено расширение AutoT4 (https://marketplace.visualstudio.com/items?itemName=BennorMcCarthy.AutoT4), чтобы повторно запустить шаблоны перед сборкой.
получение версии от GIT
У меня есть git -C $(ProjectDir) describe --long --always > "$(ProjectDir)git_version.txt"
в событии pre-build в свойствах проекта.
Добавление git_version.txt и VersionInfo.cs в .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 tag + hash в "ProductVersion".
Ответ 10
Ссылаясь на другой ответ (fooobar.com/questions/106463/...), я также использовал текстовый шаблон VersionInfo.tt
для генерации AssemblyInformationalVersion
без AutoT4.
(Atleast работает в моем приложении WPF на С#)
Проблема заключалась в том, что события Pre-build выполнялись после трансформаций шаблонов, поэтому после клонирования, файл git_version.txt
не был там, и сборка завершилась неудачей.
После его создания вручную, чтобы преобразование прошло один раз, оно было обновлено после преобразования и всегда было одним фиксатором.
Мне пришлось внести две корректировки в файл .csproj(это применимо, по крайней мере, для сообщества Visual Studio 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
перед трансформацией шаблона (так что git_version.txt
существует, когда VersionInfo.tt
преобразуется):
<Target Name="PreBuild" BeforeTargets="ExecuteTransformations">
<Exec Command="git -C $(ProjectDir) describe --long --always --dirty > $(ProjectDir)git_version.txt" />
</Target>
.. И код С#, чтобы получить AssemblyInformationalVersion
(Ref fooobar.com/questions/106468/...)
public string AppGitHash
{
get
{
AssemblyInformationalVersionAttribute attribute = (AssemblyInformationalVersionAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false).FirstOrDefault();
return attribute.InformationalVersion;
}
}
.. И добавьте сгенерированные файлы в .gitignore
VersionInfo.cs
git_version.txt
Ответ 11
- Надеюсь, вы знаете, как вызывать внешние программы и перехватывать выходные данные во время сборки.
- Надеюсь, вы знаете, как в рабочем каталоге git игнорировать неверсированные файлы.
Как отмечено в @learath2, вывод git rev-parse HEAD
даст вам простой хеш.
Если вы используете теги в Git -repository (и используете теги, не более ли описательные и читаемые, чем git rev-parse
), вывод может быть получен от git describe
(в то же время успешно используется позже в git checkout
)
Вы можете вызвать rev-parse | описать в:
- некоторые стадии выполнения
- в цепочке после фиксации
- в smudge filter, если вы выберете smudge/clean filters способ реализации