Contrôle de version automatique dans Visual Studio 2017 (.NET Core)

112

J'ai passé la majeure partie de quelques heures à essayer de trouver un moyen d'incrémenter automatiquement les versions dans un .NETCoreApp 1.1 (Visual Studio 2017).

Je sais que le AssemblyInfo.cs est créé dynamiquement dans le dossier: obj/Debug/netcoreapp1.1/

Il n'accepte pas l'ancienne méthode de: [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.*")]

Si je configure le projet sur package, je peux y définir des versions, mais cela semble être utilisé pour créer le fichier AssemblyInfo.cs.

Ma question est la suivante: est-ce que quelqu'un a compris comment contrôler la version dans les projets .NET Core (ou .NETStandard d'ailleurs).

Jason H
la source
Je ne sais pas jusqu'où vous en êtes, mais il semble que j'ai posé presque la même question d'une manière différente ( stackoverflow.com/a/43280282/685341 ) - Peut-être que la réponse acceptée à cette question vous aidera; vous pouvez simplement passer le /p:drapeau dotnet msbuilddans votre script de construction et définir la version, la société, les droits d'auteur ... toutes ces bonnes choses.
Jay
2
Merci pour l'info. Cela ouvre simplement des options supplémentaires.
Jason H
Auparavant, * était pris en charge pour AssemblyVersion, pas pour AssemblyFileVersion - voir Puis-je incrémenter automatiquement la version de génération de fichier lors de l'utilisation de Visual Studio?
Michael Freidgeim
4
FWIW, le caractère générique dans la version d'assembly n'est pas pris en charge car pour ces nouveaux projets, le mode «déterministe» du compilateur est actif par défaut. Puisque l'auto-incrémentation briserait le déterminisme (même entrée> même sortie), elle est interdite dans ce mode. Vous pouvez définir <Deterministic>False</Deterministic>dans le csproj pour l'utiliser. (ou utilisez toute autre logique MSbuild pour calculer <VersionPrefix>/ <Version>)
Martin Ullrich

Réponses:

23

Je cherchais un incrémenteur de version pour une application Net Core dans VS2017 en utilisant le format de configuration csproj.

J'ai trouvé un projet appelé dotnet bump qui fonctionnait pour le format project.json, mais j'ai eu du mal à trouver une solution pour le format .csproj. Le rédacteur de la bosse dotnet a en fait proposé la solution pour le format .csproj et cela s'appelle MSBump.

Il existe un projet sur GitHub pour cela à:

https://github.com/BalassaMarton/MSBump

où vous pouvez voir le code et son disponible sur Nuget aussi. Recherchez simplement MSBump sur Nuget.

ravetroll
la source
1
Je recommande d'utiliser la dernière version 2.1.0 de MSBump, elle prend mieux en charge les configurations de commutation et définit également la version de la version actuelle, pas la suivante (comme la version précédente).
Márton Balassa
Je vois qu'il prend désormais également en charge MSBuild alors qu'avant, il nécessitait un studio visuel.
ravetroll
2
Oui, et il prend également en charge les projets multi-ciblage.
Márton Balassa
4
Pensez à utiliser GitVersioning. Il peut être approprié pour fonctionner sur votre environnement CI. github.com/AArnott/Nerdbank.GitVersioning
Henrique
1
MSBump incrémente la version à chaque build même si vous n'avez rien changé, cela pose beaucoup de problèmes à long terme. Et parfois, les versions ne sont pas synchronisées et une version est derrière l'autre.
Konrad
68

Ajouter <Deterministic>False</Deterministic> dans une <PropertyGroup>section de .csproj

La solution de contournement pour que AssemblyVersion * fonctionne est décrite dans «Message d'erreur déroutant pour le caractère générique dans [AssemblyVersion] sur .Net Core # 22660»

Les caractères génériques ne sont autorisés que si la génération n'est pas déterministe, ce qui est la valeur par défaut pour les projets .Net Core. L'ajout  <Deterministic>False</Deterministic> à csproj résout le problème.

Les raisons pour lesquelles les développeurs .Net Core considèrent les Builds déterministes comme bénéfiques décrites dans http://blog.paranoidcoding.com/2016/04/05/deterministic-builds-in-roslyn.html et les compilateurs devraient être déterministes: les mêmes entrées génèrent les mêmes sorties # 372

Cependant, si vous utilisez TeamCity, TFS ou un autre outil CI / CD, il est probablement préférable de garder le numéro de version contrôlé et incrémenté par eux et de passer à la construction en tant que paramètre (comme cela a été suggéré dans d'autres réponses), par exemple

msbuild /t:build /p:Version=YourVersionNumber /p:AssemblyVersion=YourVersionNumber

Numéro de package pour les packages NuGet

msbuild /t:pack /p:Version=YourVersionNumber   
Michael Freidgeim
la source
Je vous remercie! Je savais qu'il y avait un levier caché pour ouvrir la salle du trésor! Je migre un ancien projet vers le nouveau SDK .NET, et je voulais vraiment le faire rapidement, sans avoir à trouver des solutions automatisées d'incrémentation de version. En fait, plus c'est compatible avec les anciennes méthodes, mieux c'est pour mon cas.
Ivaylo Slavov
C'est la meilleure réponse de l'OMI. Cela permet à l'outillage de construction de fonctionner correctement. Au moins, je peux utiliser un mécanisme externe pour introduire le numéro dans la construction maintenant.
Michael Yanni
Veuillez développer votre réponse un peu plus: l'ajout suggéré doit aller dans la section <PropertyGroup> de .csproj. Et merci pour cette excellente réponse, bien sûr!
GerardV
1
@gerardv, c'est fait, mais vous pouvez améliorer vous-même les modifications stackoverflow.com/help/editing
Michael Freidgeim
62

Si vous utilisez Visual Studio Team Services / TFS ou un autre processus de génération de CI pour intégrer le contrôle de version, vous pouvez utiliser l' Conditionattribut de msbuild , par exemple:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <Version Condition=" '$(BUILD_BUILDNUMBER)' == '' ">0.0.1-local</Version>
    <Version Condition=" '$(BUILD_BUILDNUMBER)' != '' ">$(BUILD_BUILDNUMBER)</Version>
    <TargetFramework>netcoreapp1.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Folder Include="wwwroot\" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.0" />
    <PackageReference Include="Microsoft.AspNetCore" Version="1.1.2" />
    <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="1.1.2" />
  </ItemGroup>

</Project>

Cela indiquera au compilateur .NET Core d'utiliser tout ce qui se trouve dans la BUILD_BUILDNUMBERvariable d'environnement si elle est présente, ou de revenir en arrière 0.0.1-localsi vous effectuez une compilation sur votre ordinateur local.

Joelsand
la source
Bien, j'aime cette approche car les variables d'environnement peuvent simplement être définies sur le serveur de construction, tandis que ces conditions déterminent le jeu d'assemblage dans les binaires.
jbooker
Cela ne semble pas fonctionner sur TFS 2010, mais j'espère que nous partirons bientôt!
Mark Adamson
Ce n'est pas une mauvaise solution, mais cela pourrait être un peu de travail si la solution a beaucoup de projets.
tofutim le
Bonne solution. J'ai cependant obtenu une exception de construction. J'ai dû modifier légèrement la configuration pour y remédier. stackoverflow.com/a/59858009/106227
Stu Harper
Cela fonctionne très bien avec .NET Core 2.1.2 et TFS2017U3
Dave Johnson
16

J'ai trouvé une solution qui fonctionnait presque de la même manière que l'ancien attribut AssemblyVersion avec étoile (*) - AssemblyVersion ("1.0. ") *

Les valeurs pour AssemblyVersion et AssemblyFileVersion se trouvent dans le fichier .csproj du projet MSBuild (pas dans AssemblyInfo.cs ) en tant que propriété FileVersion (génère AssemblyFileVersionAttribute ) et AssemblyVersion (génère AssemblyVersionAttribute ). Dans le processus MSBuild, nous utilisons notre tâche MSBuild personnalisée pour générer les numéros de version, puis nous remplaçons les valeurs de ces FileVersion et AssemblyVersion propriétés par les nouvelles valeurs de task.

Nous créons donc d'abord notre tâche MSBuild personnalisée GetCurrentBuildVersion :

public class GetCurrentBuildVersion : Task
{
    [Output]
    public string Version { get; set; }
 
    public string BaseVersion { get; set; }
 
    public override bool Execute()
    {
        var originalVersion = System.Version.Parse(this.BaseVersion ?? "1.0.0");
 
        this.Version = GetCurrentBuildVersionString(originalVersion);
 
        return true;
    }
 
    private static string GetCurrentBuildVersionString(Version baseVersion)
    {
        DateTime d = DateTime.Now;
        return new Version(baseVersion.Major, baseVersion.Minor,
            (DateTime.Today - new DateTime(2000, 1, 1)).Days,
            ((int)new TimeSpan(d.Hour, d.Minute, d.Second).TotalSeconds) / 2).ToString();
    }
}

Hériter de la classe de tâche Microsoft.Build.Utilities.Task classe de Microsoft.Build.Utilities.Core package NuGet. Il prend la propriété BaseVersion (facultative) en entrée et renvoie la version générée dans la propriété de sortie Version. La logique pour obtenir les numéros de version est la même que celle du contrôle de version automatique .NET (le numéro de build correspond au nombre de jours depuis le 1/1/2000 et la révision est d'une demi-seconde depuis minuit).

Pour créer cette tâche MSBuild, nous utilisons le type de projet de bibliothèque de classes .NET Standard 1.3 avec cette classe.

Le fichier .csproj peut ressembler à ceci:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard1.3</TargetFramework>
    <AssemblyName>DC.Build.Tasks</AssemblyName>
    <RootNamespace>DC.Build.Tasks</RootNamespace>
    <PackageId>DC.Build.Tasks</PackageId>
    <AssemblyTitle>DC.Build.Tasks</AssemblyTitle>
  </PropertyGroup>
 
  <ItemGroup>
    <PackageReference Include="Microsoft.Build.Framework" Version="15.1.1012" />
    <PackageReference Include="Microsoft.Build.Utilities.Core" Version="15.1.1012" />
  </ItemGroup>
</Project>

Ce projet de tâche est également disponible dans mon GitHub holajan / DC.Build.Tasks

Nous configurons maintenant MSBuild pour utiliser cette tâche et définissons les propriétés FileVersion et AssemblyVersion . Dans le fichier .csproj, cela ressemble à ceci:

<Project Sdk="Microsoft.NET.Sdk">
  <UsingTask TaskName="GetCurrentBuildVersion" AssemblyFile="$(MSBuildThisFileFullPath)\..\..\DC.Build.Tasks.dll" />
 
  <PropertyGroup>
    ...
    <AssemblyVersion>1.0.0.0</AssemblyVersion>
    <FileVersion>1.0.0.0</FileVersion>
  </PropertyGroup>
 
  ...
 
  <Target Name="BeforeBuildActionsProject1" BeforeTargets="BeforeBuild">
    <GetCurrentBuildVersion BaseVersion="$(FileVersion)">
      <Output TaskParameter="Version" PropertyName="FileVersion" />
    </GetCurrentBuildVersion>
    <PropertyGroup>
      <AssemblyVersion>$(FileVersion)</AssemblyVersion>
    </PropertyGroup>
  </Target>
 
</Project>

Choses importantes ici:

  • Mentioned UsingTask importe la tâche GetCurrentBuildVersion à partir de DC.Build.Tasks.dll . Il suppose que ce fichier dll se trouve sur le répertoire parent à partir de votre fichier .csproj.
  • Notre cible BeforeBuildActionsProject1 qui appelle la tâche doit avoir un nom unique par projet au cas où nous aurions plus de projets dans la solution qui appelle la tâche GetCurrentBuildVersion.

L'avantage de cette solution est qu'elle fonctionne non seulement à partir de builds sur le serveur de build, mais également dans les builds manuels de dotnet build ou de Visual Studio.

HolaJan
la source
4
Je recommanderais d'utiliser à la DateTime.UtcNowplace de la DateTime.Nowméthode GetCurrentBuildVersionString()en particulier si le code est exécuté sur des machines de construction automatisées. Ils peuvent fonctionner à 2 heures du matin ou à 3 heures du matin lorsque votre ordinateur passe à l'heure d'été ou à l'heure d'été. Dans DateTime.Nowce scénario, vous pourriez reculer en termes de version. Certes, c'est un cas de coin et j'avoue aussi que je suis pointilleux. :-) En outre, le problème disparaît également si vous configurez le même fuseau horaire sur toutes les machines de construction et ne pas vous ajuster à l'heure d'été.
Manfred
Existe-t-il encore un package NuGet pour cela?
Jonathan Allen
@Jonathan Allen Non, je n'ai pas de plan pour le paquet nuget, à cause du nom différent dans chaque projet. Vous pouvez télécharger compilé construire tâche dans assemby github.com/holajan/DC.Build.Tasks/tree/master/dist dossier
HolaJan
Nous avons utilisé une application de console personnalisée pour extraire notre version d'un serveur et générer le fichier AssemblyInfo.cs avant les builds. Cette approche est parfaite pour ce que nous faisons. Avez-vous pu utiliser cette méthode pour pousser la version en "Version" de la fonctionnalité pack des nouveaux projets? Ce serait bien, mais je suppose que nous pouvons revenir à l'utilisation de nuget.exe pour créer un package car nous en aurons besoin pour publier également.
David Ritchie
15

Vous pouvez utiliser une fonction de propriété MSBuild pour définir le suffixe de version en fonction de la date actuelle:

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
  <VersionSuffix>pre$([System.DateTime]::UtcNow.ToString(yyyyMMdd-HHmm))</VersionSuffix>
</PropertyGroup>

Cela affichera un package avec un nom comme: PackageName.1.0.0-pre20180807-1711.nupkg .

Plus de détails sur les fonctions de propriété MSBuild: https://docs.microsoft.com/en-us/visualstudio/msbuild/property-functions

Le Versionest formé à partir de la combinaison de VersionPrefixet VersionSuffix, ou si VersionSuffixest vide, VersionPrefixuniquement.

<PropertyGroup>
  <VersionPrefix>1.0.0</VersionPrefix>
</PropertyGroup>
Fabricio Godoy
la source
C'est vraiment pratique
Jerry Nixon
12

J'ai accepté la réponse ci-dessus parce que @Gigi est correct (à partir de maintenant) mais j'ai été ennuyé et j'ai proposé les scripts PowerShell suivants.

J'ai d'abord le script dans mon dossier de solution (UpdateBuildVersion.ps1):

#Get Path to csproj
$path = "$PSScriptRoot\src\ProjectFolder\ProjectName.csproj"

#Read csproj (XML)
$xml = [xml](Get-Content $path)

#Retrieve Version Nodes
$assemblyVersion = $xml.Project.PropertyGroup.AssemblyVersion
$fileVersion = $xml.Project.PropertyGroup.FileVersion

#Split the Version Numbers
$avMajor, $avMinor, $avBuild  = $assemblyVersion.Split(".")
$fvMajor, $fvMinor, $fvBuild = $fileVersion.Split(".")

#Increment Revision
$avBuild = [Convert]::ToInt32($avBuild,10)+1
$fvBuild = [Convert]::ToInt32($fvBuild,10)+1

#Put new version back into csproj (XML)
$xml.Project.PropertyGroup.AssemblyVersion = "$avMajor.$avMinor.$avBuild"
$xml.Project.PropertyGroup.FileVersion = "$fvMajor.$fvMinor.$fvBuild"

#Save csproj (XML)
$xml.Save($path)

J'ai ajouté ceci au fichier csproj:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <AssemblyVersion>0.0.1</AssemblyVersion>
    <FileVersion>0.0.1</FileVersion>
    <PreBuildEvent>powershell.exe NonInteractive ExecutionPolicy Unrestricted -command "& {$(SolutionDir)UpdateBuildVersion.ps1}"</PreBuildEvent>
  </PropertyGroup>
</Project>

Même si son ensemble est un PreBuildEvent, le fait est que les numéros de version ne sont pas mis à jour avant que le fichier n'ait été chargé en mémoire, de sorte que le numéro de version ne sera pas reflété jusqu'à la prochaine génération. En fait, vous pourriez le changer en un PostBuildEvent et cela aurait le même effet.

J'ai également créé les deux scripts suivants: (UpdateMinorVersion.ps1)

#Get Path to csproj
$path = "$PSScriptRoot\src\ProjectFolder\ProjectName.csproj"

#Read csproj (XML)
$xml = [xml](Get-Content $path)

#Retrieve Version Nodes
$assemblyVersion = $xml.Project.PropertyGroup.AssemblyVersion
$fileVersion = $xml.Project.PropertyGroup.FileVersion

#Split the Version Numbers
$avMajor, $avMinor, $avBuild  = $assemblyVersion.Split(".")
$fvMajor, $fvMinor, $fvBuild = $fileVersion.Split(".")

#Increment Minor Version - Will reset all sub nodes
$avMinor = [Convert]::ToInt32($avMinor,10)+1
$fvMinor = [Convert]::ToInt32($fvMinor,10)+1
$avBuild = 0
$fvBuild = 0

#Put new version back into csproj (XML)
$xml.Project.PropertyGroup.AssemblyVersion = "$avMajor.$avMinor.$avBuild"
$xml.Project.PropertyGroup.FileVersion = "$fvMajor.$fvMinor.$fvBuild"

#Save csproj (XML)
$xml.Save($path)

(UpdateMajorVersion.ps1)

#Get Path to csproj
$path = "$PSScriptRoot\src\ProjectFolder\ProjectName.csproj"

#Read csproj (XML)
$xml = [xml](Get-Content $path)

#Retrieve Version Nodes
$assemblyVersion = $xml.Project.PropertyGroup.AssemblyVersion
$fileVersion = $xml.Project.PropertyGroup.FileVersion

#Split the Version Numbers
$avMajor, $avMinor, $avBuild  = $assemblyVersion.Split(".")
$fvMajor, $fvMinor, $fvBuild = $fileVersion.Split(".")

#Increment Major Version - Will reset all sub nodes
$avMajor = [Convert]::ToInt32($avMajor,10)+1
$fvMajor = [Convert]::ToInt32($fvMajor,10)+1
$avMinor = 0
$fvMinor = 0
$avBuild = 0
$fvBuild = 0

#Put new version back into csproj (XML)
$xml.Project.PropertyGroup.AssemblyVersion = "$avMajor.$avMinor.$avBuild"
$xml.Project.PropertyGroup.FileVersion = "$fvMajor.$fvMinor.$fvBuild"

#Save csproj (XML)
$xml.Save($path)
Jason H
la source
10

dotnet build /p:AssemblyVersion=1.2.3.4

Je répondais à: "Quelqu'un at-il trouvé comment contrôler la version dans les projets .NET Core (ou .NETStandard d'ailleurs)." J'ai trouvé cette question en essayant de résoudre ce problème dans le contexte d'une construction CI. Je voulais définir la version de l'assembly sur le numéro de version CI.

Chris McKenzie
la source
1
Le titre dit «Contrôle de version automatique dans Visual Studio 2017 (.NET Core)». Où exactement le construire manuellement est-il conforme à «Visual Studio 2017»?
JCKödel
4
Je répondais à: "Quelqu'un at-il trouvé comment contrôler la version dans les projets .NET Core (ou .NETStandard d'ailleurs)." J'ai trouvé cette question en essayant de résoudre ce problème dans le contexte d'une construction CI. Je voulais définir la version de l'assembly sur le numéro de version CI. Je suis désolé si vous pensez que cela ne correspond pas à la question posée.
Chris McKenzie
C'est un élément utile pour moi merci. Je vais l'utiliser dans le cadre d'une solution CI
Mark Adamson
1
@ChrisMcKenzie: votre commentaire doit être inclus dans votre réponse pour que votre intention soit claire
Michael Freidgeim
** cela ne fonctionne pas pour moi sur les projets netstandard lorsque assemblyinfo.cs n'est pas spécifié et que la version est dans le csproj ...
tofutim
9

Ces valeurs sont maintenant définies dans le .csprojfichier:

<PropertyGroup>
    <TargetFramework>netcoreapp1.1</TargetFramework>
    <AssemblyVersion>1.0.6.0</AssemblyVersion>
    <FileVersion>1.0.6.0</FileVersion>
    <Version>1.0.1</Version>
</PropertyGroup>

Ce sont les mêmes valeurs que vous voyez si vous allez dans l' onglet Package dans les paramètres du projet. Bien que je ne pense pas que vous puissiez utiliser *pour auto-incrémenter la version, ce que vous pouvez faire est d'introduire une étape de post-traitement qui remplace les versions pour vous (par exemple dans le cadre de votre intégration continue).

Gigi
la source
6
J'avais peur que ce soit la réponse. Je vais voir si je peux faire une étape de pré-construction pour l'incrémenter.
Jason H
3
Comme indiqué dans un autre thread, le nouveau format csproj vous permet de désactiver la génération automatique du fichier assemblyinfo et de spécifier le vôtre. J'ai suivi les conseils de la réponse de natemcmaster ici et utilisé un fichier AssemblyInfo.cs standard: stackoverflow.com/questions/42138418/…
James Eby
5
Pourquoi ont-ils supprimé l'incrémentation automatique? Cela a très bien fonctionné et très simplement pour moi pendant des années. Je pousse le maître, les builds et les incréments CI, puis la version est lue directement à partir de la DLL construite à l'aide d'un script PS, puis j'utilise cette version comme argument lors de la transmission à NuGet. Si simple. Maintenant cassé.
Luke Puplett
1
@LukePuplett pareil ici. Si frustrant!
Shimmy Weitzhandler
@LukePuplett: Voir [«Message d'erreur déroutant pour le caractère générique dans AssemblyVersion sur .Net Core # 22660»] ( github.com/dotnet/roslyn/issues/22660 ), Les raisons pour lesquelles ils considèrent les Builds déterministes comme bénéfiques décrites dans blog.paranoidcoding.com / 2016/04/05 /… et les compilateurs doivent être déterministes: les mêmes entrées génèrent les mêmes sorties # 372 < github.com/dotnet/roslyn/issues/372 >
Michael Freidgeim
5

J'ai créé un outil CLI simple pour définir les chaînes de version .csproj .NET Core ici . Vous pouvez le combiner avec des outils comme GitVersion pour le changement de version automatique pendant les builds CI, si c'est ce que vous recherchez.

Tagc
la source
@JasonH Merci, faites-moi savoir si vous rencontrez des problèmes.
Tagc
putain de génie. aimer!
pms1969
4

Pour activer la gestion des versions de votre .Net Core / .Net Quel que soit le projet basé sur votre configuration GIT, en utilisant la fonctionnalité balises / describe de GIT.

J'utilise un fichier Prebuild.targets.xml qui se trouve dans le dossier racine du projet et inclus dans le fichier csproj comme:

<Project Sdk="Microsoft.NET.Sdk">
  <Import Project="PreBuild.targets.xml" />
  ...
  <PropertyGroup>
    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>

Utilisez la balise "GenerateAssembyInfo" pour désactiver la génération automatique d'informations d'assemblage.

Ensuite, Prebuild.targets.xml générera un fichier CommonAssemblyInfo.cs dans lequel vous pourrez inclure les balises de version souhaitées en fonction de votre version GIT

REMARQUE: j'ai trouvé le Prebuilds.targets.xml ailleurs, donc je n'ai pas pris la peine de le nettoyer.)

Le fichier Prebuild.targets.xml:

    <?xml version="1.0" encoding="utf-8" ?>
    <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

      <UsingTask
        TaskName="GetVersion"
        TaskFactory="CodeTaskFactory"
        AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >
        <ParameterGroup>
          <VersionString ParameterType="System.String" Required="true" />
          <Version ParameterType="System.String" Output="true" />
          <Commit ParameterType="System.String" Output="true" />
          <VersionSuffix ParameterType="System.String" Output="true" />
        </ParameterGroup>
        <Task>
          <!--<Reference Include="" />-->
          <Using Namespace="System"/>
          <Using Namespace="System.IO"/>
          <Using Namespace="System.Text.RegularExpressions" />
          <Code Type="Fragment" Language="cs">
            <![CDATA[
              var match = Regex.Match(VersionString, @"^(?<major>\d+)\.(?<minor>\d+)(\.?(?<patch>\d+))?-(?<revision>\d+)-(?<commit>[a-z0-9-]+)$");
              int major, minor, patch, revision;
              Int32.TryParse(match.Groups["major"].Value, out major);
              Int32.TryParse(match.Groups["minor"].Value, out minor);
              Int32.TryParse(match.Groups["patch"].Value, out patch);
              Int32.TryParse(match.Groups["revision"].Value, out revision);
              _Version = new Version(major, minor, patch, revision).ToString();
              _Commit = match.Groups["commit"].Value;
            ]]>
          </Code>
        </Task>
      </UsingTask>

      <UsingTask
        TaskName="GitExistsInPath"
        TaskFactory="CodeTaskFactory"
        AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >
        <ParameterGroup>
          <Exists ParameterType="System.Boolean" Output="true" />
        </ParameterGroup>
        <Task>
          <!--<Reference Include="" />-->
          <Using Namespace="System"/>
          <Using Namespace="System.IO"/>
          <Using Namespace="System.Text.RegularExpressions" />
          <Code Type="Fragment" Language="cs">
            <![CDATA[
            var values = Environment.GetEnvironmentVariable("PATH");
            foreach (var path in values.Split(';')) {
                var exeFullPath = Path.Combine(path, "git.exe");
                if (File.Exists(exeFullPath)) {
                    Exists = true;
                    return true;
                }
                var cmdFullPath = Path.Combine(path, "git.cmd");
                if (File.Exists(cmdFullPath)) {
                    Exists = true;
                    return true;
            }
            }
            Exists = false;
            ]]>
          </Code>
        </Task>
      </UsingTask>

      <Target Name="CreateCommonVersionInfo" BeforeTargets="CoreCompile">
        <Message Importance="high" Text="CreateCommonVersionInfo" />

        <GitExistsInPath>
          <Output TaskParameter="Exists" PropertyName="GitExists"/>
        </GitExistsInPath>
        <Message Importance="High" Text="git not found!" Condition="!$(GitExists)"/>

        <Exec Command="git describe --tags --long --dirty > $(ProjectDir)version.txt" Outputs="$(ProjectDir)version.txt" WorkingDirectory="$(SolutionDir)" IgnoreExitCode="true" Condition="$(GitExists)">
          <Output TaskParameter="ExitCode" PropertyName="ExitCode" />
        </Exec>
        <Message Importance="high" Text="Calling git failed with exit code $(ExitCode)" Condition="$(GitExists) And '$(ExitCode)'!='0'" />

        <ReadLinesFromFile File="$(ProjectDir)version.txt" Condition="$(GitExists) And '$(ExitCode)'=='0'">
          <Output TaskParameter="Lines" ItemName="OutputLines"/>
        </ReadLinesFromFile>
        <Message Importance="High" Text="Tags: @(OutputLines)" Condition="$(GitExists) And '$(ExitCode)'=='0'"/>

        <Delete Condition="Exists('$(ProjectDir)version.txt')" Files="$(ProjectDir)version.txt"/>

        <GetVersion VersionString="@(OutputLines)" Condition="$(GitExists) And '$(ExitCode)'=='0'">
          <Output TaskParameter="Version" PropertyName="VersionString"/>
          <Output TaskParameter="Commit" PropertyName="Commit"/>
        </GetVersion>

        <PropertyGroup>
          <VersionString Condition="'$(VersionString)'==''">0.0.0.0</VersionString>
        </PropertyGroup>

        <Message Importance="High" Text="Creating CommonVersionInfo.cs with version $(VersionString) $(Commit)" />

        <WriteLinesToFile Overwrite="true" File="$(ProjectDir)CommonAssemblyInfo.cs" Encoding="UTF-8" Lines='using System.Reflection%3B

    // full version: $(VersionString)-$(Commit)

    [assembly: AssemblyVersion("$(VersionString)")]
    [assembly: AssemblyInformationalVersion("$(VersionString)")] 
    [assembly: AssemblyFileVersion("$(VersionString)")]' />

      </Target>
    </Project>

EDIT: Si vous construisez avec MSBUILD, le

 $(SolutionDir)

Pourrait vous causer des ennuis, utilisez

 $(ProjectDir)

au lieu

Tue Skeltved
la source
Agréable! Est-ce que VersionSuffix finit par être configuré ou utilisé? Cela ne semble pas être
Mark Adamson
4

Vous pouvez faire ce qui suit, dans le fichier csproj. Je n'ai pas compris le calcul. J'ai trouvé ça ailleurs sur stackoverflow. Mais cela fonctionne et vous donnera quelque chose de similaire à 1.0. * Pour la version.

<PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <FileVersion>1.0.$([System.DateTime]::UtcNow.Date.Subtract($([System.DateTime]::Parse("2000-01-01"))).TotalDays).$([System.Math]::Floor($([MSBuild]::Divide($([System.DateTime]::UtcNow.TimeOfDay.TotalSeconds), 1.32))))</FileVersion>
    <Version>1.0.$([System.DateTime]::UtcNow.Date.Subtract($([System.DateTime]::Parse("2000-01-01"))).TotalDays)</Version>
</PropertyGroup>
Clarke76
la source
3

L'extension Versions automatiques pour Visual Studio prend désormais en charge l'auto-incrémentation .Net Core et .Net Standard dans une interface utilisateur simple.

https://marketplace.visualstudio.com/items?itemName=PrecisionInfinity.AutomaticVersions

madame
la source
1
J'ai fait un test rapide avec la solution de démonstration (application Windows) et cela fonctionne, également avec le projet standard .net. C'était un test rapide, il faut donc plonger plus profondément pour vérifier si tout ce que nous voulons. Mais vous pouvez certainement essayer celui-ci.
ArieKanarie
3

Merci à @joelsand de m'avoir orienté dans la bonne direction.

J'ai dû modifier légèrement sa réponse car lorsque la construction DevOps a été exécutée, j'ai eu l'exception suivante

The specified version string does not conform to the recommended format - major.minor.build.revision

J'ai dû ajouter le $ (BUILD_BUILDNUMBER) à la fin de la section major.minor.build. Pour dédupliquer la version actuelle, j'utilise également un préfixe de version:

<PropertyGroup>
    <VersionPrefix>1.0.3</VersionPrefix>
    <Version Condition=" '$(BUILD_BUILDNUMBER)' == '' ">$(VersionPrefix)-local</Version>
    <Version Condition=" '$(BUILD_BUILDNUMBER)' != '' ">$(VersionPrefix)-$(BUILD_BUILDNUMBER)</Version>
</PropertyGroup>
Stu Harper
la source
J'ai eu exactement le même problème et votre réponse l'a résolu. Je vous remercie.
Participant à la réunion le
2

Nous pouvons utiliser un paramètre spécial pour dotnet publish -- version-suffix 1.2.3

Pour la version de fichier:

<AssemblyVersion Condition=" '$(VersionSuffix)' == '' ">0.0.1.0</AssemblyVersion>
<AssemblyVersion Condition=" '$(VersionSuffix)' != '' ">$(VersionSuffix)</AssemblyVersion>

Pour la version:

<Version Condition=" '$(VersionSuffix)' == '' ">0.0.1</Version>
<Version Condition=" '$(VersionSuffix)' != '' ">$(VersionSuffix)</Version>

https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish?tabs=netcore21

--version-suffix <VERSION_SUFFIX>     Defines the value for the $(VersionSuffix) property in the project.
Anatoli Klamer
la source
1

Je pense que cette réponse de @joelsand est la bonne réponse pour définir le numéro de version pour dotnet core fonctionnant sur VSTS

Pour ajouter plus d'informations sur cette réponse,

BUILD_BUILDNUMBERest en fait une variable prédéfinie .

Il s'avère qu'il existe 2 versions de variable prédéfinie.

L'un est build.xxxx, l'autre est BUILD_XXXX.

Vous ne pouvez utiliser que Environment Variable Namedans cproj.

maxisam
la source
N'est-il pas build.xxxxutilisé sur le front-end pour le référencement dans un pipeline et BUILD_XXXXest-ce la même valeur mais avec une syntaxe légèrement modifiée requise pour référencer la variable dans PS?
dst3p le