Automatyczne przechowywanie wersji w programie Visual Studio 2017 (.NET Core)

112

Spędziłem większą część kilku godzin, próbując znaleźć sposób na automatyczne zwiększanie wersji w .NETCoreApp 1.1 (Visual Studio 2017).

Wiem, że plik AssemblyInfo.cs jest tworzony dynamicznie w folderze: obj/Debug/netcoreapp1.1/

Nie akceptuje starej metody: [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.*")]

Jeśli ustawię projekt na pakiet, mogę ustawić tam wersje, ale wydaje się, że jest to używane do budowania pliku AssemblyInfo.cs.

Moje pytanie brzmi: czy ktoś wymyślił, jak kontrolować wersję w projektach .NET Core (lub .NETStandard).

Jason H.
źródło
Nie wiem, jak daleko z tym zaszedłeś, ale wygląda na to, że prawie to samo pytanie zadałem w inny sposób ( stackoverflow.com/a/43280282/685341 ) - Może zaakceptowana odpowiedź na to pytanie pomoże ci; możesz po prostu przekazać /p:flagę dotnet msbuildw swoim skrypcie kompilacji i ustawić wersję, firmę, prawa autorskie ... wszystkie te dobre rzeczy.
Jay
2
Dzięki za informację. To tylko otwiera dodatkowe opcje.
Jason H
Wcześniej * był obsługiwany dla AssemblyVersion, a nie dla AssemblyFileVersion - zobacz czy mogę automatycznie zwiększać wersję kompilacji pliku podczas korzystania z programu Visual Studio?
Michael Freidgeim
4
FWIW symbol wieloznaczny w wersji zestawu nie jest obsługiwany, ponieważ dla tych nowych projektów tryb „deterministyczny” kompilatora jest domyślnie aktywny. Ponieważ auto-inkrementacja złamałaby determinizm (to samo wejście> to samo wyjście), jest niedozwolona w tym trybie. Możesz ustawić <Deterministic>False</Deterministic>w csproj, aby go używać. (lub użyj innej logiki MSbuild do obliczenia <VersionPrefix>/ <Version>)
Martin Ullrich

Odpowiedzi:

23

Szukałem programu do zwiększania wersji aplikacji Net Core w VS2017 przy użyciu formatu konfiguracji csproj.

Znalazłem projekt o nazwie dotnet bump, który działał dla formatu project.json, ale miał problem ze znalezieniem rozwiązania dla formatu .csproj. Twórca dotnet bump faktycznie wymyślił rozwiązanie dla formatu .csproj i nazywa się MSBump.

Istnieje projekt na GitHub dla tego pod adresem:

https://github.com/BalassaMarton/MSBump

gdzie możesz zobaczyć kod i jego dostępność również na Nuget. Po prostu wyszukaj MSBump na Nuget.

ravetroll
źródło
1
Polecam korzystanie z najnowszej wersji programu MSBump 2.1.0, lepiej obsługuje konfiguracje przełączania, a także ustawia wersję dla bieżącej kompilacji, a nie następnej (jak poprzednia wersja).
Márton Balassa
Widzę, że teraz obsługuje również MSBuild, podczas gdy wcześniej wymagało to Visual Studio.
ravetroll
2
Tak, a także obsługuje projekty z wieloma celami.
Márton Balassa
4
Rozważ użycie GitVersioning. Może być odpowiednie do uruchomienia w środowisku CI. github.com/AArnott/Nerdbank.GitVersioning
Henrique
1
MSBump zwiększa wersję w każdej kompilacji, nawet jeśli nic nie zmieniłeś, powoduje to wiele problemów w dłuższej perspektywie. Czasami wersje tracą synchronizację i jedna wersja jest za drugą.
Konrad
68

Dodaj <Deterministic>False</Deterministic> wewnątrz <PropertyGroup>sekcji .csproj

Obejście umożliwiające działanie AssemblyVersion * opisano w „Mylący komunikat o błędzie dla symbolu wieloznacznego w [AssemblyVersion] w .Net Core # 22660”

Symbole wieloznaczne są dozwolone tylko wtedy, gdy kompilacja nie jest deterministyczna, co jest wartością domyślną w projektach .Net Core. Dodanie  <Deterministic>False</Deterministic> do csproj rozwiązuje problem.

Powody, dla których programiści .Net Core uważają, że kompilacje deterministyczne są korzystne, opisane w http://blog.paranoidcoding.com/2016/04/05/deterministic-builds-in-roslyn.html i kompilatorach powinny być deterministyczne: te same dane wejściowe generują te same wyniki # 372

Jeśli jednak używasz TeamCity, TFS lub innego narzędzia CI / CD, prawdopodobnie lepiej jest kontrolować i zwiększać numer wersji i przekazywać go jako parametr do kompilacji (jak sugerowano w innych odpowiedziach), np.

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

Numer pakietu dla pakietów NuGet

msbuild /t:pack /p:Version=YourVersionNumber   
Michael Freidgeim
źródło
Dziękuję Ci! Wiedziałem, że jest ukryta dźwignia do otwierania skarbca! Migrację starego projektu do nowego .NET SDK i naprawdę chciałem zrobić to szybko, bez kłopotów ze znalezieniem rozwiązań do automatycznego zwiększania wersji. W rzeczywistości im bardziej kompatybilny ze starymi sposobami, tym lepiej dla mojego przypadku.
Ivaylo Slavov
To najlepsza odpowiedź IMO. Pozwala to na prawidłowe działanie narzędzi kompilacji. Przynajmniej mogę teraz użyć zewnętrznego mechanizmu, aby wprowadzić numer do kompilacji.
Michael Yanni
Proszę rozszerzyć swoją odpowiedź tylko trochę więcej: sugerowany dodatek musi znaleźć się w sekcji <PropertyGroup> w .csproj. I oczywiście dzięki za tę świetną odpowiedź!
GerardV
1
@gerardv, gotowe, ale możesz samodzielnie poprawiać zmiany stackoverflow.com/help/editing
Michael Freidgeim
62

Jeśli używasz programu Visual Studio Team Services / TFS lub innego procesu kompilacji CI, który ma wbudowane przechowywanie wersji, możesz użyć Conditionatrybutu msbuild , na przykład:

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

Dzięki temu kompilator .NET Core ma użyć dowolnej BUILD_BUILDNUMBERzmiennej środowiskowej, jeśli jest obecna, lub cofnąć się, 0.0.1-localjeśli tworzysz kompilację na komputerze lokalnym.

joelsand
źródło
Fajnie, podoba mi się to podejście, ponieważ zmienne środowiskowe można po prostu ustawić na serwerze kompilacji, podczas gdy te warunki warunkowe determinują zestaw zestawu w plikach binarnych.
jbooker
Wydaje się, że nie działa na TFS 2010, ale miejmy nadzieję, że wkrótce się odsuniemy!
Mark Adamson
Niezłe rozwiązanie, choć może wymagać trochę pracy, jeśli rozwiązanie obejmuje wiele projektów.
tofutim
Dobre rozwiązanie. Dostałem jednak wyjątek Build. Musiałem nieco zmienić konfigurację, aby to naprawić. stackoverflow.com/a/59858009/106227
Stu Harper
Działa to świetnie z .NET Core 2.1.2 i TFS2017U3
Dave Johnson
16

Wymyśliłem rozwiązanie, które działało prawie tak samo, jak stary atrybut AssemblyVersion z gwiazdką (*) - AssemblyVersion („1.0. ”) *

Wartości dla AssemblyVersion i AssemblyFileVersion znajdują się w pliku .csproj projektu MSBuild (nie w AssemblyInfo.cs ) jako właściwość FileVersion (generuje AssemblyFileVersionAttribute ) i AssemblyVersion (generuje AssemblyVersionAttribute ). W procesie MSBuild używamy naszego niestandardowego zadania MSBuild do generowania numerów wersji, a następnie zastępujemy wartości tych właściwości FileVersion i AssemblyVersion nowymi wartościami z zadania.

Więc najpierw tworzymy nasze niestandardowe zadanie MSBuild 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();
    }
}

Zadanie klasa dziedziczy z Microsoft.Build.Utilities.Task klasy z Microsoft.Build.Utilities.Core pakietu Nuget. Pobiera właściwość BaseVersion (opcjonalna) na wejściu i zwraca wygenerowaną wersję we właściwości wyjściowej wersji. Logika uzyskiwania numerów wersji jest taka sama jak w przypadku automatycznego sprawdzania wersji .NET (numer kompilacji to liczba dni od 1 stycznia 2000 r., A wersja to pół sekundy od północy).

Aby zbudować to zadanie MSBuild, używamy typu projektu biblioteki klas .NET Standard 1.3 z tą klasą.

Plik .csproj może wyglądać następująco:

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

Ten projekt zadania jest również dostępny w moim holajan / DC.Build.Tasks w serwisie GitHub

Teraz konfigurujemy program MSBuild do korzystania z tego zadania i ustawiamy właściwości FileVersion i AssemblyVersion . W pliku .csproj wygląda to tak:

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

Ważne rzeczy tutaj:

  • Wspomniany UsingTask importuje zadanie GetCurrentBuildVersion z DC.Build.Tasks.dll . Zakłada się, że ten plik dll znajduje się w katalogu nadrzędnym z pliku .csproj.
  • Nasz obiekt Target BeforeBuildActionsProject1, który wywołuje zadanie, musi mieć unikalną nazwę na projekt w przypadku, gdy mamy więcej projektów w rozwiązaniu, które wywołuje zadanie GetCurrentBuildVersion.

Zaletą tego rozwiązania jest to, że działa nie tylko z kompilacji na serwerze kompilacji, ale także w kompilacjach ręcznych z kompilacji dotnet lub programu Visual Studio.

HolaJan
źródło
4
Polecam użycie metody DateTime.UtcNowzamiast in, zwłaszcza jeśli kod jest wykonywany na automatach do kompilacji. Mogą działać o 2 lub 3 nad ranem, kiedy komputer przełącza się na / z czasu letniego. W tym scenariuszu możesz cofać się pod względem wersji. Trzeba przyznać, że jest to sprawa narożna i przyznaję też, że jestem wybredna. :-) Ponadto problem znika również, jeśli skonfigurujesz tę samą strefę czasową na wszystkich maszynach do budowania i nie dostosujesz się do czasu letniego. DateTime.NowGetCurrentBuildVersionString()DateTime.Now
Manfred
Czy istnieje już pakiet NuGet do tego?
Jonathan Allen,
@Jonathan Allen Nie, nie mam planu dotyczącego pakietu nuget, ponieważ każdy projekt ma inną nazwę. Można przesyłać skompilowany build zadanie assemby w github.com/holajan/DC.Build.Tasks/tree/master/dist Folder
HolaJan
Używaliśmy niestandardowej aplikacji konsoli, aby pobrać naszą wersję z serwera i wygenerować plik AssemblyInfo.cs przed kompilacją. To podejście jest idealne do tego, co robimy. Czy byłeś w stanie użyć tej metody, aby przekazać wersję w „wersji” funkcji pakietu nowych projektów? Byłoby miło, ale myślę, że możemy wrócić do używania nuget.exe również do pakowania, ponieważ będziemy potrzebować go również do opublikowania.
David Ritchie,
15

Można użyć funkcji właściwości programu MSBuild, aby ustawić sufiks wersji na podstawie bieżącej daty:

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

Spowoduje to wyświetlenie pakietu o nazwie takiej jak: NazwaPakietu.1.0.0-pre20180807-1711.nupkg .

Więcej szczegółów na temat funkcji właściwości MSBuild: https://docs.microsoft.com/en-us/visualstudio/msbuild/property-functions

VersionPowstaje z połączenia VersionPrefixi VersionSuffix, lub jeśli VersionSuffixjest pusty, VersionPrefixtylko.

<PropertyGroup>
  <VersionPrefix>1.0.0</VersionPrefix>
</PropertyGroup>
Fabricio Godoy
źródło
To jest naprawdę przydatne
Jerry Nixon
12

Przyjąłem powyższą odpowiedź, ponieważ @Gigi jest poprawne (na razie), ale byłem zirytowany i wymyśliłem następujące skrypty PowerShell.

Najpierw mam skrypt w folderze mojego rozwiązania (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)

Dodałem to do pliku 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>

Nawet jeśli ustawiono go jako zdarzenie PreBuildEvent, faktem jest, że numery wersji nie są aktualizowane, dopóki plik nie zostanie załadowany do pamięci, więc numer wersji nie będzie widoczny do następnej kompilacji. W rzeczywistości możesz zmienić to na PostBuildEvent i miałoby to ten sam efekt.

Stworzyłem również dwa następujące skrypty: (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.
źródło
10

dotnet build /p:AssemblyVersion=1.2.3.4

Odpowiadałem na pytanie: „czy ktoś wymyślił, jak kontrolować wersję w projektach .NET Core (lub .NETStandard)”. Znalazłem to pytanie, próbując rozwiązać ten problem w kontekście kompilacji CI. Chciałem ustawić wersję zestawu na numer kompilacji CI.

Chris McKenzie
źródło
1
Tytuł zawiera tekst „Automatyczne przechowywanie wersji w programie Visual Studio 2017 (.NET Core)”. Gdzie dokładnie kompilowanie go ręcznie jest zgodne z „Visual Studio 2017”?
JCKödel
4
Odpowiadałem na pytanie: „czy ktoś wymyślił, jak kontrolować wersję w projektach .NET Core (lub .NETStandard)”. Znalazłem to pytanie, próbując rozwiązać ten problem w kontekście kompilacji CI. Chciałem ustawić wersję zestawu na numer kompilacji CI. Przykro mi, jeśli uważasz, że to nie miało związku z obecnym pytaniem.
Chris McKenzie
To dla mnie pomocny element, dzięki. Użyję tego jako części rozwiązania CI
Mark Adamson
1
@ChrisMcKenzie: Twój komentarz powinien być zawarty w odpowiedzi, aby jasno wyrazić zamiar
Michael Freidgeim
** to nie działa dla mnie w projektach netstandard, gdy nie określono assemblyinfo.cs, a wersja znajduje się w csproj ...
tofutim
9

Te wartości są teraz ustawione w .csprojpliku:

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

Są to te same wartości, które widzisz, jeśli przejdziesz na kartę Pakiet w ustawieniach projektu. Chociaż nie wydaje mi się, abyś mógł użyć funkcji *autoinkrementacji wersji, to co możesz zrobić, to wprowadzić etap przetwarzania końcowego, który zastępuje wersje za Ciebie (np. Jako część ciągłej integracji).

Gigi
źródło
6
Bałem się, że to będzie odpowiedź. Zobaczę, czy uda mi się wykonać krok przed kompilacją, aby go zwiększyć.
Jason H
3
Jak wskazano w innym wątku, nowy format csproj pozwala wyłączyć automatyczne generowanie pliku assemblyinfo i określić własny. Postępowałem zgodnie z radą odpowiedzi natemcmaster tutaj i użyłem standardowego pliku AssemblyInfo.cs: stackoverflow.com/questions/42138418/…
James Eby
5
Dlaczego usunęli autoinkrementację? To działało bardzo dobrze i bardzo prosto przez lata. Wypycham master, kompiluje i inkrementuje CI, a następnie wersja jest odczytywana bezpośrednio z wbudowanej biblioteki DLL przy użyciu skryptu PS, a następnie używam tej wersji jako argumentu podczas wypychania do NuGet. Tak prosty. Teraz zepsuty.
Luke Puplett
1
@LukePuplett to samo tutaj. bardzo frustrujące!
Shimmy Weitzhandler
@LukePuplett: Zobacz [„Mylący komunikat o błędzie dla symboli wieloznacznych w AssemblyVersion na .Net Core # 22660”] ( github.com/dotnet/roslyn/issues/22660 ), Powody, dla których uważają, że Deterministic Builds są korzystne opisane w blog.paranoidcoding.com / 2016/04/05 /… i kompilatory powinny być deterministyczne: te same dane wejściowe generują te same wyniki # 372 < github.com/dotnet/roslyn/issues/372 >
Michael Freidgeim
5

Zrobiłem proste narzędzie CLI do ustawiania .csproj NET podstawowych ciągów wersja tutaj . Możesz połączyć to z narzędziami takimi jak GitVersion do automatycznego przełączania wersji podczas kompilacji CI, jeśli tego szukasz.

Tagc
źródło
@JasonH Dzięki, daj mi znać, jeśli masz z tym jakieś problemy.
Tagc
cholerny geniusz. kocham to!
pms1969
4

Aby umożliwić wersjonowanie twojego .Net Core / .Net Niezależnie od projektu opartego na twojej konfiguracji GIT, używając tagów / opisz funkcjonalność GIT.

Używam pliku Prebuild.targets.xml, który znajduje się w folderze głównym projektu i jest zawarty w pliku csproj, na przykład:

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

Użyj tagu „GenerateAssembyInfo”, aby wyłączyć automatyczne generowanie informacji o zestawie.

Następnie plik Prebuild.targets.xml wygeneruje plik CommonAssemblyInfo.cs, w którym możesz dołączyć żądane znaczniki wersji na podstawie wersji GIT

UWAGA: Znalazłem plik Prebuilds.targets.xml gdzie indziej, więc nie zawracałem sobie głowy czyszczeniem).

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

EDYCJA: Jeśli tworzysz przy użyciu programu MSBUILD, plik

 $(SolutionDir)

Może sprawić ci kłopoty, użyj

 $(ProjectDir)

zamiast

Tue Skeltved
źródło
Miły! Czy VersionSuffix zostaje skonfigurowany lub używany? Wydaje się, że tak nie jest
Mark Adamson
4

Możesz wykonać poniższe czynności w pliku csproj. Nie rozgryzłem matematyki. Znalazłem to gdzieś indziej na stackoverflow. Ale to działa i da ci coś podobnego do 1.0. * Dla wersji.

<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
źródło
3

Rozszerzenie Automatic Versions dla programu Visual Studio obsługuje teraz funkcję autoinkrementacji .Net Core i .Net Standard w prostym interfejsie użytkownika.

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

pani
źródło
1
Zrobiłem szybki test z rozwiązaniem demo (aplikacja Windows) i działa, również ze standardowym projektem .net. To był szybki test, więc musimy zagłębić się głębiej, aby sprawdzić, czy robi wszystko, co chcemy. Ale na pewno możesz spróbować tego.
ArieKanarie
3

Dziękuję @joelsand za wskazanie mi właściwego kierunku.

Musiałem nieco zmienić jego odpowiedź, ponieważ po uruchomieniu kompilacji DevOps dostałem następujący wyjątek

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

Musiałem dodać $ (BUILD_BUILDNUMBER) na końcu sekcji major.minor.build. Aby usunąć duplikaty aktualnej wersji, używam również prefiksu wersji:

<PropertyGroup>
    <VersionPrefix>1.0.3</VersionPrefix>
    <Version Condition=" '$(BUILD_BUILDNUMBER)' == '' ">$(VersionPrefix)-local</Version>
    <Version Condition=" '$(BUILD_BUILDNUMBER)' != '' ">$(VersionPrefix)-$(BUILD_BUILDNUMBER)</Version>
</PropertyGroup>
Stu Harper
źródło
Miałem dokładnie ten sam problem i twoja odpowiedź go rozwiązała. Dziękuję Ci.
Uczestnik spotkania
2

Możemy użyć specjalnego parametru dla dotnet publish -- version-suffix 1.2.3

Wersja pliku:

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

Wersja:

<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
źródło
1

Myślę, że ta odpowiedź od @joelsand jest poprawną odpowiedzią na ustawienie numeru wersji rdzenia dotnet działającego na VSTS

Aby dodać więcej informacji do tej odpowiedzi,

BUILD_BUILDNUMBERjest właściwie predefiniowaną zmienną .

Okazuje się, że istnieją 2 wersje predefiniowanej zmiennej.

Jeden to build.xxxx, drugi to BUILD_XXXX.

Możesz używać tylko Environment Variable Namew cproj.

maxisam
źródło
Nie jest build.xxxxużywany w interfejsie użytkownika do odwoływania się w potoku i BUILD_XXXXma tę samą wartość, ale z nieznacznie zmodyfikowaną składnią wymaganą do odwoływania się do zmiennej w PS?
dst3p