Автоматическое управление версиями в Visual Studio 2017 (.NET Core)

Я потратил большую часть нескольких часов, пытаясь найти способ автоматического увеличения версий в a .NETCoreApp 1.1 (Visual Studio 2017).

Я знаю AssemblyInfo.cs создается динамически в папке:obj/Debug/netcoreapp1.1/

Он не принимает старый метод: [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.*")]

Если я установил проект в пакет, я могу установить там версии, но это, похоже, используется для создания AssemblyInfo.cs файл.

мой вопрос в том, есть ли кто-нибудь выяснил, как управлять версией в .NET Core (или .NETStandard, если на то пошло) проекты.

13 ответов


Я искал инкремент версии для приложения Net Core в VS2017, используя формат конфигурации csproj.

Я нашел проект под названием dotnet bump, который работал для проекта.формат json, но изо всех сил пытался найти решение для .формат csproj. Писатель The dotnet bump на самом деле придумал решение для этого .формат csproj и называется MSBump.

для него есть проект на GitHub at:

https://github.com/BalassaMarton/MSBump

где вы можете увидеть код и его доступный на Nuget тоже. Просто найдите MSBump на Nuget.


если вы используете Visual Studio Team Services/TFS или какой-либо другой процесс сборки CI для встроенного управления версиями, вы можете использовать msbuild's


добавить <Deterministic>False</Deterministic> внутри часть .csproj файл

обходной путь для создания AssemblyVersion * работа описана в "запутанное сообщение об ошибке для подстановочного знака в [AssemblyVersion] на .Net Core #22660"

подстановочные знаки допускаются только в том случае, если сборка не является детерминированной, что значение по умолчанию для проектов .Net Core. Добавление <Deterministic>False</Deterministic> для csproj исправляет вопрос.

причины .Чистая Основные разработчики считают детерминированные сборки полезными, описанными вhttp://blog.paranoidcoding.com/2016/04/05/deterministic-builds-in-roslyn.html и компиляторы должны быть детерминированными: одни и те же входы генерируют одни и те же выходы #372

однако, если вы используете TeamCity, TFS или другой инструмент CI / CD, вероятно, лучше контролировать номер версии и увеличивать их и передавать для сборки в качестве параметра (как было предложено в других ответах) , например,

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

номер пакета для пакетов NuGet

msbuild /t:pack /p:Version=YourVersionNumber   

Я придумал решение, которое работает почти так же, как старый AssemblyVersion (не AssemblyInfo.cs) в собственность FileVersion (генерирует AssemblyFileVersionAttribute) и AssemblyVersion (генерирует AssemblyVersionAttribute). В процессе MSBuild мы используем нашу пользовательскую задачу MSBuild для генерации номеров версий, а затем переопределяем значения этих FileVersion и AssemblyVersion свойства с новыми значениями из задач.

Итак, сначала мы создаем нашу пользовательскую задачу 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();
    }
}

класс задачи наследуется от Microsoft.Строить.Коммунальные услуги.Задача класса от Microsoft.Строить.Коммунальные услуги.Ядро пакета NuGet. Он принимает свойство BaseVersion (необязательно) на входе и возвращает сгенерированную версию в свойстве вывода версии. Логика получения номеров версий такая же, как автоматическое управление версиями .NET (Номер сборки-количество дней с 1/1/2000, а версия-половина секунды с полуночи).

чтобы построить эту задачу MSBuild, мы используем .NET Standard 1.3 библиотека классов тип проекта с этим классом.

.файл csproj может выглядеть вот так:

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

этот проект задачи также доступен в моем GitHub holajan / DC.Строить.Задачи

Теперь мы настроим MSBuild, чтобы использовать эту задачу и установить FileVersion и AssemblyVersion свойства. В.файл csproj выглядит так:

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

Importtant вещи здесь:

  • указано UsingTask импорт задачи GetCurrentBuildVersion из DC.Строить.Задачи.dll файлы. Предполагается ,что этот dll-файл находится в Родительском каталоге из вашего.файл csproj.
  • наши BeforeBuildActionsProject1 цель, которая вызывает задачу, должна иметь уникальное имя для каждого проекта, если у нас есть больше проектов в решении, которое вызывает задачу GetCurrentBuildVersion.

преимущество этого решения заключается в том, что оно работает не только из сборок на сервере сборки, но и в ручных сборках из dotnet ограничителя build или Visual Studio.


эти значения теперь установлены в :

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

это те же значения, если вы идете в пакета вкладка в настройках проекта. Хотя я не думаю, что вы можете использовать * для автоинкремента версии, что вы можете сделать, это ввести шаг после обработки, который заменяет версии для вас (например, как часть вашей непрерывной интеграции).


сборка dotnet /p:AssemblyVersion=1.2.3.4

Я отвечал: "кто-нибудь выяснил, как управлять версией в .NET Core (или .NETStandard, если на то пошло) проекты."Я нашел этот вопрос пытаются решить эту проблему в контексте сборки CI. Я хотел установить версию сборки на номер сборки CI.


Я сделал простой инструмент CLI для настройки .строки версии csproj .NET Core здесь. Вы можете объединить его с такими инструментами, как GitVersion для автоматической версии во время сборки CI, если это то, что вам нужно.


Я принял приведенный выше ответ, потому что @Gigi верен (на данный момент), но я был раздражен и придумал следующие сценарии PowerShell.

сначала у меня есть скрипт в папке решения (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)

Я добавил Это в файл 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>

даже через его набор, чтобы быть PreBuildEvent, факт, что номера версий не обновляются до тех пор, пока файл не будет загружен в память, так что номер версии не будет отражать до следующей сборки. Фактически, вы можете изменить его на PostBuildEvent, и он будет иметь тот же эффект.

Я создал следующие два сценария: (UpdateMinorVersion.пс1)

#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.пс1)

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

чтобы включить управление версиями вашего .Net Core / .Net любого проекта на основе вашей установки GIT, используя теги / описать функциональность GIT.

Я использую Prebuild.цели.xml-файл, который находится в корневой папке проекта и включен в файл csproj, например:

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

используйте тег "GenerateAssembyInfo", чтобы отключить автоматическое создание информации о сборке.

затем Prebuild.цели.XML будет генерировать CommonAssemblyInfo.cs файл, где вы можете включить теги версии, которые вы хотите на основе вашей версии GIT

примечание: Я нашел Prebuilds.цели.xml где-то еще, поэтому не удосужился его очистить .)

Prebuild.цели.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: если вы строите с помощью MSBUILD

 $(SolutionDir)

может вызвать у вас проблемы, используйте

 $(ProjectDir)

вместо


расширение автоматические версии для Visual Studio теперь поддерживает .Net Core и .Net Standard autoincrementing в простом пользовательском интерфейсе.

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


Я думаю, что это ответ from @joelsand-правильный ответ для установки номера версии для ядра dotnet, работающего на VSTS

чтобы добавить дополнительную информацию для этого ответа,

BUILD_BUILDNUMBER на самом деле предопределенная переменная.

оказывается, есть 2 версии предопределенной переменной.

строится.xxxx, другой-BUILD_XXXX.

вы можете использовать только Environment Variable Name в cproj.


вы можете использовать функцию свойства MSBuild для установки суффикса версии на основе текущей даты:

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

это выведет пакет с именем типа:имя пакета.1.0.0-pre20180807-1711.nupkg по.

подробнее о функциях свойств MSBuild:https://docs.microsoft.com/en-us/visualstudio/msbuild/property-functions


мы можем использовать специальный параметр для dotnet publish -- version-suffix 1.2.3

для версия файла:

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

для версии:

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