Automatische Versionierung in Visual Studio 2017 (.NET Core)


112

Ich habe den größten Teil einiger Stunden damit verbracht, einen Weg zu finden, um Versionen in einer .NETCoreApp 1.1 (Visual Studio 2017) automatisch zu inkrementieren.

Ich weiß, dass die AssemblyInfo.cs dynamisch im Ordner erstellt wird: obj/Debug/netcoreapp1.1/

Es akzeptiert nicht die alte Methode von: [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.*")]

Wenn ich das Projekt auf Paket setze, kann ich dort Versionen festlegen, aber dies scheint verwendet zu werden, um die AssemblyInfo.cs-Datei zu erstellen.

Meine Frage ist, hat jemand herausgefunden, wie die Version in .NET Core-Projekten (oder .NETStandard-Projekten) gesteuert werden kann?


Ich weiß nicht, wie weit Sie damit gekommen sind, aber es sieht so aus, als hätte ich fast dieselbe Frage anders gestellt ( stackoverflow.com/a/43280282/685341 ) - Vielleicht hilft Ihnen die akzeptierte Antwort auf diese Frage. Sie können einfach die /p:Flagge dotnet msbuildin Ihrem Build-Skript übergeben und Version, Firma, Urheberrecht ... all diese guten Dinge festlegen.
Jay

2
Danke für die Information. Das eröffnet nur zusätzliche Möglichkeiten.
Jason H

Bisher wurde * für AssemblyVersion unterstützt, nicht für AssemblyFileVersion. Siehe Kann ich die Dateierstellungsversion bei Verwendung von Visual Studio automatisch erhöhen?
Michael Freidgeim

3
FWIW Der Platzhalter in der Assembly-Version wird nicht unterstützt, da für dieses neue Projekt der "deterministische" Modus des Compilers standardmäßig aktiv ist. Da die automatische Inkrementierung den Determinismus unterbrechen würde (gleiche Eingabe> gleiche Ausgabe), ist sie in diesem Modus nicht zulässig. Sie können <Deterministic>False</Deterministic>im csproj festlegen, dass es verwendet werden soll. (oder verwenden Sie eine andere MSbuild-Logik, um <VersionPrefix>/ zu berechnen <Version>)
Martin Ullrich

Antworten:


23

Ich habe nach einem Versionsinkrementierer für eine Net Core-App in VS2017 mit dem Konfigurationsformat csproj gesucht.

Ich fand ein Projekt namens Dotnet Bump, das für das Format project.json funktionierte, aber Schwierigkeiten hatte, eine Lösung für das Format .csproj zu finden. Der Autor des Dotnet-Bumps hat tatsächlich die Lösung für das .csproj-Format entwickelt, die als MSBump bezeichnet wird.

Es gibt ein Projekt auf GitHub dafür unter:

https://github.com/BalassaMarton/MSBump

Hier können Sie den Code und seine Verfügbarkeit auch auf Nuget sehen. Suchen Sie einfach auf Nuget nach MSBump.


1
Ich empfehle die Verwendung der neuesten Version 2.1.0 von MSBump. Sie unterstützt das Umschalten von Konfigurationen besser und legt auch die Version für den aktuellen Build fest, nicht für die nächste (wie die vorherige Version).
Márton Balassa

Ich sehe, dass es jetzt auch MSBuild unterstützt, während es zuvor Visual Studio erforderte.
Ravetroll

2
Ja, und es werden auch Multi-Targeting-Projekte unterstützt.
Márton Balassa

4
Erwägen Sie die Verwendung von GitVersioning. Es kann geeignet sein, in Ihrer CI-Umgebung ausgeführt zu werden. github.com/AArnott/Nerdbank.GitVersioning
Henrique

1
MSBump erhöht die Version bei jedem Build, auch wenn Sie nichts geändert haben. Dies führt langfristig zu vielen Problemen. Und manchmal sind die Versionen nicht mehr synchron und eine Version befindet sich hinter der anderen.
Konrad

68

Fügen Sie <Deterministic>False</Deterministic> innerhalb eines <PropertyGroup>Abschnitts von .csproj hinzu

Die Problemumgehung, damit AssemblyVersion * funktioniert, wird unter „Verwirrende Fehlermeldung für Platzhalter in [AssemblyVersion] auf .Net Core # 22660“ beschrieben.

Platzhalter sind nur zulässig, wenn der Build nicht deterministisch ist. Dies ist die Standardeinstellung für .NET Core-Projekte. Das Hinzufügen  <Deterministic>False</Deterministic> zu csproj behebt das Problem.

Die Gründe, warum .Net Core-Entwickler deterministische Builds für vorteilhaft halten, wie in http://blog.paranoidcoding.com/2016/04/05/deterministic-builds-in-roslyn.html und Compiler beschrieben, sollten deterministisch sein: Dieselben Eingaben erzeugen dieselben Ausgaben # 372

Wenn Sie jedoch TeamCity, TFS oder ein anderes CI / CD-Tool verwenden, ist es wahrscheinlich besser, die Versionsnummer von diesen zu kontrollieren und zu erhöhen und als Parameter zu übergeben (wie in anderen Antworten vorgeschlagen), z

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

Paketnummer für NuGet-Pakete

msbuild /t:pack /p:Version=YourVersionNumber   

Danke dir! Ich wusste, dass es einen versteckten Hebel zum Öffnen der Schatzkammer gab! Ich migriere ein altes Projekt auf das neue .NET SDK und wollte dies unbedingt schnell erledigen, ohne den Aufwand, automatisierte Lösungen für Versionsinkremente zu finden. Je besser mit den alten Methoden kompatibel, desto besser für meinen Fall.
Ivaylo Slavov

Dies ist die beste Antwort IMO. Dadurch kann das Build-Tool ordnungsgemäß funktionieren. Zumindest kann ich jetzt einen externen Mechanismus verwenden, um die Nummer in den Build einzugeben.
Michael Yanni

Bitte erweitern Sie Ihre Antwort noch ein wenig: Der vorgeschlagene Zusatz muss in den Abschnitt <PropertyGroup> von .csproj aufgenommen werden. Und danke natürlich für diese tolle Antwort!
GerardV

1
@gerardv, fertig, aber Sie können die Änderungen selbst verbessern stackoverflow.com/help/editing
Michael Freidgeim

61

Wenn Sie Visual Studio Team Services / TFS oder einen anderen CI-Erstellungsprozess verwenden, um eine integrierte Versionierung zu haben, können Sie das ConditionAttribut von msbuild verwenden , zum Beispiel:

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

Dadurch wird der .NET Core-Compiler angewiesen, alle in der BUILD_BUILDNUMBERUmgebungsvariablen enthaltenen Elemente zu verwenden, sofern diese vorhanden sind, oder darauf zurückzugreifen, 0.0.1-localwenn Sie einen Build auf Ihrem lokalen Computer ausführen.


Schön, ich mag diesen Ansatz, weil die Umgebungsvariablen nur auf dem Build-Server festgelegt werden können, während diese Bedingungen den in den Binärdateien festgelegten Assembly-Satz bestimmen.
jbooker

Scheint bei TFS 2010 nicht zu funktionieren, aber hoffentlich machen wir uns bald auf den Weg!
Mark Adamson

Keine schlechte Lösung, könnte aber ein bisschen Arbeit sein, wenn die Lösung viele Projekte hat.
Tofutim

Gute Lösung. Ich habe allerdings eine Build-Ausnahme bekommen. Ich musste die Konfiguration leicht ändern, um sie zu beheben. stackoverflow.com/a/59858009/106227
Stu Harper

Dies funktioniert hervorragend mit .NET Core 2.1.2 und TFS2017U3
Dave Johnson

15

Ich habe eine Lösung gefunden, die fast genauso funktioniert wie das alte AssemblyVersion- Attribut mit star (*) - AssemblyVersion ("1.0. ") *

Die Werte für AssemblyVersion und AssemblyFileVersion befinden sich in der .csproj- Datei des MSBuild-Projekts (nicht in AssemblyInfo.cs ) als Eigenschaft FileVersion (generiert AssemblyFileVersionAttribute ) und AssemblyVersion (generiert AssemblyVersionAttribute ). Im MSBuild-Prozess verwenden wir unsere benutzerdefinierte MSBuild-Task, um Versionsnummern zu generieren, und überschreiben dann die Werte dieser FileVersion- und AssemblyVersion- Eigenschaften mit neuen Werten aus der Task.

Zuerst erstellen wir unsere benutzerdefinierte MSBuild-Aufgabe 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();
    }
}

Die Task-Klasse erbt von der Microsoft.Build.Utilities.Task- Klasse vom Microsoft.Build.Utilities.Core NuGet-Paket. Es übernimmt die BaseVersion-Eigenschaft (optional) für die Eingabe und gibt die generierte Version in der Version-Ausgabeeigenschaft zurück. Die Logik zum Abrufen von Versionsnummern entspricht der automatischen Versionierung von .NET (Build-Nummer ist die Anzahl der Tage seit dem 1.1.2000 und Revision ist eine halbe Sekunde seit Mitternacht).

Zum Erstellen dieser MSBuild-Aufgabe verwenden wir den Projekttyp der .NET Standard 1.3-Klassenbibliothek mit dieser Klasse.

Die .csproj-Datei kann folgendermaßen aussehen:

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

Dieses Aufgabenprojekt ist auch in meinem GitHub holajan / DC.Build.Tasks verfügbar

Jetzt richten wir MSBuild für diese Aufgabe ein und legen die Eigenschaften FileVersion und AssemblyVersion fest . In der .csproj-Datei sieht es so aus:

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

Wichtige Dinge hier:

  • Erwähnt UsingTask importiert die GetCurrentBuildVersion-Task aus DC.Build.Tasks.dll . Es wird davon ausgegangen, dass sich diese DLL-Datei im übergeordneten Verzeichnis Ihrer .csproj-Datei befindet.
  • Unser BeforeBuildActionsProject1- Ziel, das die Aufgabe aufruft, muss einen eindeutigen Namen pro Projekt haben, falls die Lösung mehr Projekte enthält, die die Aufgabe GetCurrentBuildVersion aufrufen.

Der Vorteil dieser Lösung besteht darin, dass sie nicht nur mit Builds auf dem Build-Server funktioniert, sondern auch mit manuellen Builds aus Dotnet Build oder Visual Studio.


4
Ich würde empfehlen, DateTime.UtcNowanstelle der DateTime.NowMethode GetCurrentBuildVersionString()in zu verwenden, insbesondere wenn der Code auf automatisierten Build-Maschinen ausgeführt wird. Sie können um 2 Uhr morgens oder 3 Uhr morgens ausgeführt werden, wenn Ihr Computer auf / von Sommerzeit umschaltet. Mit DateTime.Nowin diesem Szenario könnten Sie rückwärts in Bezug auf die Version gehen. Zugegeben, dies ist ein Eckfall und ich gebe auch zu, dass ich wählerisch bin. :-) Außerdem verschwindet das Problem auch, wenn Sie auf allen Build-Maschinen dieselbe Zeitzone konfigurieren und sich nicht an die Sommerzeit anpassen.
Manfred

Gibt es dafür schon ein NuGet-Paket?
Jonathan Allen

@ Jonathan Allen Nein, ich habe keinen Plan für ein Nuget-Paket, da jedes Projekt einen anderen Namen hat. Sie können Build - Task assemby in kompilierten herunterladen github.com/holajan/DC.Build.Tasks/tree/master/dist Ordner
HolaJan

Wir haben eine benutzerdefinierte Konsolen-App verwendet, um unsere Version von einem Server abzurufen und die AssemblyInfo.cs-Datei vor dem Erstellen zu generieren. Dieser Ansatz ist perfekt für das, was wir tun. Konnten Sie mit dieser Methode die Version in "Version" der Pack-Funktion der neuen Projekte verschieben? Es wäre schön, aber ich denke, wir können auch auf nuget.exe zurückgreifen, um zu packen, da wir es auch für die Veröffentlichung benötigen.
David Ritchie

15

Sie können eine MSBuild-Eigenschaftsfunktion verwenden, um das Versionssuffix basierend auf dem aktuellen Datum festzulegen:

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

Dadurch wird ein Paket mit einem Namen wie dem folgenden ausgegeben : PackageName.1.0.0-pre20180807-1711.nupkg .

Weitere Details zu den MSBuild-Eigenschaftsfunktionen: https://docs.microsoft.com/en-us/visualstudio/msbuild/property-functions

Das Versionwird nur aus der Kombination von VersionPrefixund gebildet VersionSuffix, oder wenn VersionSuffixes leer ist VersionPrefix.

<PropertyGroup>
  <VersionPrefix>1.0.0</VersionPrefix>
</PropertyGroup>

Das ist wirklich praktisch
Jerry Nixon

11

Ich habe die obige Antwort akzeptiert, weil @Gigi (ab sofort) korrekt ist, aber ich war verärgert und habe die folgenden PowerShell-Skripte entwickelt.

Zuerst habe ich das Skript in meinem Lösungsordner (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)

Ich habe dies zur csproj-Datei hinzugefügt:

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

Selbst wenn es sich um ein PreBuildEvent handelt, werden die Versionsnummern erst aktualisiert, nachdem die Datei in den Speicher geladen wurde, sodass die Versionsnummer erst beim nächsten Build wiedergegeben wird. Tatsächlich könnten Sie es in ein PostBuildEvent ändern und es hätte den gleichen Effekt.

Ich habe auch die folgenden zwei Skripte erstellt: (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)

10

dotnet build /p:AssemblyVersion=1.2.3.4

Ich antwortete: "Hat jemand herausgefunden, wie die Version in .NET Core-Projekten (oder .NETStandard-Projekten) gesteuert werden kann?" Ich fand diese Frage beim Versuch, dieses Problem im Kontext eines CI-Builds zu lösen. Ich wollte die Assembly-Version auf die CI-Build-Nummer setzen.


1
Der Titel lautet "Automatische Versionierung in Visual Studio 2017 (.NET Core)". Wo genau entspricht das manuelle Erstellen "Visual Studio 2017"?
JCKödel

4
Ich antwortete: "Hat jemand herausgefunden, wie die Version in .NET Core-Projekten (oder .NETStandard-Projekten) gesteuert werden kann?" Ich habe diese Frage beim Versuch gefunden, dieses Problem im Kontext eines CI-Builds zu lösen. Ich wollte die Assembly-Version auf die CI-Build-Nummer setzen. Es tut mir leid, wenn Sie der Meinung sind, dass dies für die vorliegende Frage nicht relevant ist.
Chris McKenzie

Es ist eine hilfreiche Komponente für mich, danke. Ich werde dies als Teil einer CI-Lösung verwenden
Mark Adamson

1
@ ChrisMcKenzie: Ihr Kommentar sollte in Ihrer Antwort enthalten sein, um Ihre Absicht klar zu machen
Michael Freidgeim

** Dies funktioniert nicht für mich bei Netstandard-Projekten, wenn Assemblyinfo.cs nicht angegeben ist und die Version im csproj ...
tofutim

9

Diese Werte werden jetzt in der .csprojDatei festgelegt:

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

Dies sind die gleichen Werte, die Sie sehen, wenn Sie in den Projekteinstellungen auf die Registerkarte Paket gehen . Ich glaube nicht, dass Sie *die Version automatisch inkrementieren können. Sie können jedoch einen Nachbearbeitungsschritt einführen, der die Versionen für Sie ersetzt (z. B. im Rahmen Ihrer kontinuierlichen Integration).


6
Ich hatte Angst, dass dies die Antwort sein würde. Ich werde sehen, ob ich einen vorgefertigten Schritt ausführen kann, um ihn zu erhöhen.
Jason H

3
Wie in einem anderen Thread erwähnt, können Sie mit dem neuen csproj-Format die automatische Generierung der Assemblyinfo-Datei deaktivieren und Ihre eigene angeben. Ich folgte dem Rat der Antwort von natemcmaster hier und verwendete eine Standard-AssemblyInfo.cs-Datei: stackoverflow.com/questions/42138418/…
James Eby

5
Warum haben sie das automatische Inkrement entfernt? Es hat jahrelang sehr gut und sehr einfach für mich funktioniert. Ich drücke Master, CI-Builds und Inkremente, dann wird die Version mit einem PS-Skript direkt aus der erstellten DLL gelesen und verwende diese Version dann als Argument, wenn ich auf NuGet pushe. So einfach. Jetzt kaputt.
Luke Puplett

1
@LukePuplett gleich hier. so frustrierend!
Shimmy Weitzhandler

@LukePuplett: Siehe ["Verwirrende Fehlermeldung für Platzhalter in AssemblyVersion auf .Net Core # 22660"] ( github.com/dotnet/roslyn/issues/22660 ). Die Gründe, warum sie deterministische Builds für vorteilhaft halten, sind in blog.paranoidcoding.com beschrieben / 2016/04/05 /… und Compiler sollten deterministisch sein: Gleiche Eingaben erzeugen gleiche Ausgaben # 372 < github.com/dotnet/roslyn/issues/372 >
Michael Freidgeim

5

Ich habe ein einfaches CLI - Tool CSPROJ .NET Core - Version Strings für die Einstellung hier . Sie können es mit Tools wie GitVersion für das automatische Versions-Bumping während CI-Builds kombinieren, wenn Sie danach suchen.


@ JasonH Danke, lass es mich wissen, wenn du irgendwelche Probleme damit hast.
Tagc

verdammtes Genie. Liebe es!
pms1969

4

So aktivieren Sie die Versionierung Ihres .Net Core / .Net Whatever-Projekts basierend auf Ihrem GIT-Setup mithilfe der Tags / Description-Funktionen von GIT.

Ich habe eine Prebuild.targets.xml-Datei verwendet, die sich im Stammordner des Projekts befindet und in der csproj-Datei enthalten ist, wie:

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

Verwenden Sie das Tag "GenerateAssembyInfo", um die automatische Generierung von Baugruppeninformationen zu deaktivieren.

Anschließend generiert die Datei Prebuild.targets.xml eine CommonAssemblyInfo.cs-Datei, in die Sie die gewünschten Versions-Tags basierend auf Ihrer GIT-Version einfügen können

HINWEIS: Ich habe die Prebuilds.targets.xml woanders gefunden, habe mich also nicht darum gekümmert, sie zu bereinigen.)

Die Datei 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>

BEARBEITEN: Wenn Sie mit MSBUILD erstellen, wird die

 $(SolutionDir)

Könnte Ihnen Probleme bereiten

 $(ProjectDir)

stattdessen


Nett! Wird VersionSuffix eingestellt oder verwendet? Es scheint nicht zu sein
Mark Adamson

4

Sie können das Folgende in der csproj-Datei tun. Ich habe die Mathematik nicht herausgefunden. Ich habe das irgendwo anders im Stackoverflow gefunden. Dies funktioniert jedoch und gibt Ihnen etwas Ähnliches wie 1.0. * Für die 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>

3

Die Erweiterung "Automatische Versionen" für Visual Studio unterstützt jetzt die automatische Inkrementierung von .Net Core und .Net Standard in einer einfachen Benutzeroberfläche.

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


1
Ich habe einen kurzen Test mit der Demo-Lösung (Windows App) durchgeführt und es funktioniert auch mit dem .net-Standardprojekt. Es war ein schneller Test, also müssen Sie tiefer eintauchen, um zu überprüfen, ob wir alles tun, was wir wollen. Aber Sie könnten es sicher versuchen.
ArieKanarie

2

Wir können spezielle Parameter für verwenden dotnet publish -- version-suffix 1.2.3

Für die Dateiversion:

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

Für die 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.

2

Vielen Dank an @joelsand, der mich in die richtige Richtung gelenkt hat.

Ich musste seine Antwort leicht ändern, da ich beim Ausführen des DevOps Build die folgende Ausnahme bekam

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

Ich musste das $ (BUILD_BUILDNUMBER) am Ende des Abschnitts major.minor.build hinzufügen. Um die aktuelle Version zu de-duplizieren, verwende ich auch ein Versionspräfix:

<PropertyGroup>
    <VersionPrefix>1.0.3</VersionPrefix>
    <Version Condition=" '$(BUILD_BUILDNUMBER)' == '' ">$(VersionPrefix)-local</Version>
    <Version Condition=" '$(BUILD_BUILDNUMBER)' != '' ">$(VersionPrefix)-$(BUILD_BUILDNUMBER)</Version>
</PropertyGroup>

Ich hatte genau das gleiche Problem und Ihre Antwort hat es behoben. Danke dir.
Meeting Attender

1

Ich denke, diese Antwort von @joelsand ist die richtige Antwort zum Festlegen der Versionsnummer für den auf VSTS laufenden Dotnet-Kern

Um weitere Informationen zu dieser Antwort hinzuzufügen,

BUILD_BUILDNUMBERist eigentlich eine vordefinierte Variable .

Es stellt sich heraus, dass es 2 Versionen der vordefinierten Variablen gibt.

Einer ist build.xxxx, der andere ist BUILD_XXXX.

Sie können nur Environment Variable Namein cproj verwenden.


Wird build.xxxxam Frontend nicht zum Referenzieren innerhalb einer Pipeline verwendet und BUILD_XXXXhat denselben Wert, jedoch mit leicht modifizierter Syntax, die zum Referenzieren der Variablen in PS erforderlich ist?
dst3p
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.