Автоматическое управление версиями в 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, если на то пошло) проекты.

650   13  

13 ответов:

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

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

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

https://github.com/BalassaMarton/MSBump

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

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

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

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

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

причины, почему .Net Основные разработчики считают детерминированные сборки полезными, описанные в 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) в собственность необязательный параметр (генерирует AssemblyFileVersionAttribute) и AssemblyVersion (генерирует AssemblyVersionAttribute). В процессе MSBuild мы используем нашу пользовательскую задачу MSBuild для создания номеров версий, а затем переопределяем значения этих необязательный параметр и 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 class library тип проекта с этим классом.

.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, чтобы использовать эту задачу и установить необязательный параметр и 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 строй или Visual Studio.

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

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

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

dotnet build /p:AssemblyVersion=1.2.3.4

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

Я сделал простой инструмент командной строки для установки .csproj .NET Core version strings здесь. Вы можете объединить его с такими инструментами, как GitVersion для автоматической версии bumping во время сборки 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. 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)

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

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

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

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

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

примечание: Я нашел готовые конструкции.цели.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>

изменить: если вы строите с помощью MSBUILD

 $(SolutionDir)

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

 $(ProjectDir)

вместо

автоматическое продление версий для Visual Studio теперь поддерживает .Чистая ядра и .Чистый Стандарт с автоматическим приращением в простой пользовательский интерфейс.

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.

Comments

    Ничего не найдено.