Je construis une application C # en utilisant Git comme contrôle de version.
Existe-t-il un moyen d'incorporer automatiquement le dernier hachage de validation dans l'exécutable lorsque je construis mon application?
Par exemple, imprimer le hachage de commit sur la console ressemblerait à quelque chose comme:
class PrintCommitHash
{
private String lastCommitHash = ?? // What do I put here?
static void Main(string[] args)
{
// Display the version number:
System.Console.WriteLine(lastCommitHash );
}
}
Notez que cela doit être fait à build time, pas runtime , car mon exécutable déployé n'aura pas le git repo accessible.
Une question connexe pour C++ peut être trouvée ici .
EDIT
Selon la demande de @ mattanja, je poste le script git hook que j'utilise dans mes projets. La mise en place:
Comme mon linux-shelling un peu rouillé, le script lit simplement les 23 premières lignes de AssemblyInfo.cs dans un fichier temporaire, renvoie le hachage git à la dernière ligne et renomme le fichier en AssemblyInfo.cs. Je suis sûr qu'il existe de meilleures façons de le faire:
#!/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
J'espère que cela t'aides.
Nous utilisons des tags dans git pour suivre les versions.
git tag -a v13.3.1 -m "version 13.3.1"
Vous pouvez obtenir la version avec hash de git via:
git describe --long
Notre processus de construction place le hachage git dans l'attribut AssemblyInformationalVersion du fichier AssemblyInfo.cs:
[Assembly: AssemblyInformationalVersion("13.3.1.74-g5224f3b")]
Une fois que vous avez compilé, vous pouvez voir la version à partir de Windows Explorer:
Vous pouvez également l'obtenir par programmation via:
var build = ((AssemblyInformationalVersionAttribute)Assembly
.GetAssembly(typeof(YOURTYPE))
.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false)[0])
.InformationalVersion;
où YOURTYPE est un type quelconque de l'assembly ayant l'attribut AssemblyInformationalVersion.
Vous pouvez incorporer un fichierversion.txtdans l'exécutable, puis lire le fichierversion.txtde l'exécutable. Pour créer le fichierversion.txt, utilisez git describe --long
Voici les étapes:
Cliquez avec le bouton droit sur le projet et sélectionnez Propriétés.
Dans Build Events, ajoutez un événement Pre-Build contenant (notez les guillemets):
"C:\Program Files\Git\bin\git.exe" décrit --long> "$ (ProjectDir)\version.txt"
Cela créera un fichierversion.txtdans le répertoire de votre projet.
Voici un exemple de code permettant de lire la chaîne de version du fichier texte incorporé:
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();
}
}
}
Une autre façon de faire consiste à utiliser NetRevisionTool avec de la magie On-Board Visual Studio. Je vais présenter cela ici pour Visual Studio 2013 Professional Edition, mais cela fonctionnera également avec d'autres versions.
Commencez par télécharger NetRevisionTool . Vous devez inclure NetRevisionTool.exe dans votre PATH ou l’archiver dans votre référentiel et créer une action Visual Studio de pré-génération et post-génération et modifier votre AssemblyInfo.cs.
Un exemple qui ajouterait votre git-hash à votre AssemblyInformationVersion serait le suivant: Dans les paramètres de votre projet:
dans le fichier AssemblyInfo.cs de votre projet, vous modifiez/ajoutez la ligne:
[Assembly: AssemblyInformationalVersion ("1.1. {Dmin: 2015}. {Chash: 6} {!} - {branche}")]
dans la capture d'écran présentée, j'ai vérifié NetRevisionTool.exe dans le dossier External/bin
Après la construction, si vous cliquez avec le bouton droit sur votre binaire et accédez à la propriété, vous devriez voir quelque chose comme ce qui suit:
J'espère que cela aide quelqu'un là-bas
Je pense que cette question mérite de donner une réponse complète, étape par étape. La stratégie à suivre consiste à exécuter un script PowerShell à partir des événements de pré-génération, qui prend en charge un fichier de modèle et génère un fichier AssemblyInfo.cs avec les informations git tag + commit incluses.
Étape 1: créez un fichier AssemblyInfo_template.cs dans le dossier Project\Properties, basé sur votre AssemblyInfo.cs d'origine, mais contenant:
[Assembly: AssemblyVersion("$FILEVERSION$")]
[Assembly: AssemblyFileVersion("$FILEVERSION$")]
[Assembly: AssemblyInformationalVersion("$INFOVERSION$")]
Étape 2: Créez un script PowerShell nommé InjectGitVersion.ps1 dont le source est:
# 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;
}
Étape 3: Enregistrez le fichier InjectGitVersion.ps1 dans le répertoire de votre solution dans un dossier BuildScripts.
Étape 4: / Ajoutez la ligne suivante aux événements de pré-construction du projet
powershell -ExecutionPolicy ByPass -File $(SolutionDir)\BuildScripts\InjectGitVersion.ps1 $(ProjectDir)
Étape 5: Construisez votre projet.
Étape 6: Facultativement, ajoutez AssemblyInfo.cs à votre fichier git ignore
Comme l'autre réponse mentionne déjà le bit git, une fois que vous avez le SHA, vous pouvez envisager de générer le fichier AssemblyInfo.cs
de votre projet dans un hook de pré-construction.
Une façon de procéder consiste à créer un fichier modèle AssemblyInfo.cs.tmpl
avec un espace réservé pour votre SHA dans, par exemple, $$ GITSHA $$, par exemple.
[Assembly: AssemblyDescription("$$GITSHA$$")]
Votre crochet de pré-génération doit alors remplacer cet espace réservé et générer le fichier AssemblyInfo.cs pour que le compilateur C # le récupère.
Pour voir comment cela peut être fait avec SubWCRev for SVN, voir cette réponse . Il ne devrait pas être difficile de faire quelque chose de similaire pour git.
D’autres manières seraient une "étape de création" comme mentionné, c’est-à-dire écrire une tâche MSBuild qui effectue quelque chose de similaire. Une autre solution consiste peut-être à post-traiter la DLL de façon ou d'autre (ildasm + ilasm say), mais je pense que les options mentionnées ci-dessus sont probablement les plus faciles.
Pour une validation de méthode totalement automatisée et flexible https://github.com/Fody/Stamp . Nous l'avons utilisé avec succès pour nos projets Git (ainsi que this version pour les projets SVN)
Une autre méthode consiste à générer un fichier Version.cs à partir d’une étape de pré-construction. J'ai exploré cela dans un petit projet de validation de principe qui imprime son hachage de validation actuel.
Le projet est chargé sur https://github.com/sashoalm/GitCommitHashPrinter .
Le code de lot qui crée le fichier Version.cs est le suivant:
@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
J'utilise une combinaison de la réponse acceptée et d'une petite addition . J'ai l'extension e AutoT4 installée ( https://marketplace.visualstudio.com/items?itemName=BennorMcCarthy.AutoT4 ) exécutez les modèles avant de construire.
J'ai git -C $(ProjectDir) describe --long --always > "$(ProjectDir)git_version.txt"
dans mon événement de pré-génération dans les propriétés du projet . Ajouter git_version.txt et VersionInfo.cs à .gitignore est une bonne idée.
J'ai ajouté un modèle VersionInfo.tt
à mon projet:
<#@ 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"));
}
#>
Maintenant, j'ai mon tag + hash git dans "ProductVersion".
En se référant à une autre réponse ( https://stackoverflow.com/a/44278482/4537127 ), j'ai également utilisé le modèle de texte VersionInfo.tt
pour générer AssemblyInformationalVersion
sans AutoT4.
(Atleast fonctionne dans mon application C # WPF)
Le problème était que les événements de pré-génération étaient exécutés après les transformations de modèles. Ainsi, après le clonage, le fichier git_version.txt
n'était pas présent et la génération échouait. Après l'avoir créé manuellement pour permettre à la transformation de passer une fois, elle a été mise à jour après la transformation et était toujours one commit derrière.
J'ai dû apporter deux modifications au fichier .csproj (ceci s'applique au moins à Visual Studio Community 2017)
1) Importez les cibles de transformation de texte et créez des transformations de modèle pour chaque construction: (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>
et après <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(VSToolsPath)\TextTemplating\Microsoft.TextTemplating.targets" />
2) Exécutez le git describe
avant les transformations de modèle (pour que git_version.txt
soit présent lorsque VersionInfo.tt
est transformé):
<Target Name="PreBuild" BeforeTargets="ExecuteTransformations">
<Exec Command="git -C $(ProjectDir) describe --long --always --dirty > $(ProjectDir)git_version.txt" />
</Target>
..Et le code C # pour obtenir la 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;
}
}
Et ajouter les fichiers générés à .gitignore
VersionInfo.cs
git_version.txt
Vous pouvez utiliser un PowerShell One-Liner pour mettre à jour tous les fichiers Assemblyinfo avec le hash de commit.
$hash = git describe --long --always;gci **/AssemblyInfo.* -recurse | foreach { $content = (gc $_) -replace "\[Assembly: Guid?.*", "$&`n[Assembly: AssemblyMetadata(`"commithash`", `"$hash`")]" | sc $_ }