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

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

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

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

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

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


person Jason H    schedule 25.03.2017    source источник
comment
Я не знаю, как далеко вы продвинулись в этом, но похоже, что я задал почти тот же вопрос другим способом (stackoverflow.com/a / 43280282/685341) - Возможно, принятый ответ на этот вопрос вам поможет; вы можете просто передать /p: флаг dotnet msbuild в вашем скрипте сборки и установить версию, компанию, авторские права ... все это хорошее.   -  person Jay    schedule 10.04.2017
comment
Спасибо за информацию. Это просто открывает дополнительные возможности.   -  person Jason H    schedule 10.04.2017
comment
Ранее * поддерживался для AssemblyVersion, а не для AssemblyFileVersion - см. Могу ли я автоматически увеличивать версию сборки файла при использовании Visual Studio?   -  person Michael Freidgeim    schedule 28.10.2017
comment
FWIW подстановочный знак в версии сборки не поддерживается, поскольку для этого нового проекта детерминированный режим компилятора активен по умолчанию. Поскольку автоматическое приращение нарушило бы детерминизм (тот же ввод ›тот же вывод), оно запрещено в этом режиме. Вы можете установить <Deterministic>False</Deterministic> в csproj, чтобы использовать его. (или используйте любую другую логику MSbuild для вычисления _2 _ / _ 3_)   -  person Martin Ullrich    schedule 28.10.2017


Ответы (19)


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

Я нашел проект под названием dotnet bump, который работал с форматом project.json, но изо всех сил пытался найти решение для формата .csproj. Создатель dotnet bump фактически предложил решение для формата .csproj, и оно называется MSBump.

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

https://github.com/BalassaMarton/MSBump

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

person ravetroll    schedule 08.08.2017
comment
Я рекомендую использовать последнюю версию MSBump 2.1.0, она лучше поддерживает переключение конфигураций, а также устанавливает версию для текущей сборки, а не для следующей (как предыдущая версия). - person Márton Balassa; 12.08.2017
comment
Я вижу, что теперь он также поддерживает MSBuild, тогда как раньше для этого требовалась визуальная студия. - person ravetroll; 25.11.2017
comment
Да, и он также поддерживает проекты с несколькими целями. - person Márton Balassa; 13.12.2017
comment
Рассмотрите возможность использования GitVersioning. Это может быть подходящим для работы в вашей среде CI. github.com/AArnott/Nerdbank.GitVersioning - person Henrique; 21.02.2018
comment
MSBump увеличивает версию при каждой сборке, даже если вы ничего не меняли, это вызывает множество проблем в долгосрочной перспективе. Иногда версии не синхронизируются, и одна версия отстает от другой. - person Konrad; 10.10.2018
comment
Visual Studio 16.5 просто сломала это для меня. :( - person Daniel Henry; 22.03.2020

Добавьте <Deterministic>False</Deterministic> в <PropertyGroup> раздел файла .csproj.

Обходной путь для работы AssemblyVersion * описан в «Непонятное сообщение об ошибке для подстановочного знака в [AssemblyVersion] в .Net Ядро № 22660 ”

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

Причины, по которым разработчики .Net Core считают детерминированные сборки полезными, описаны в 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   
person Michael Freidgeim    schedule 28.10.2017
comment
Спасибо! Я знал, что есть скрытый рычаг для открытия сокровищницы! Я переношу старый проект на новый .NET SDK, и мне очень хотелось сделать это быстро, без хлопот по поиску решений для автоматического увеличения версии. Фактически, чем больше совместимости со старыми способами, тем лучше для моего случая. - person Ivaylo Slavov; 06.02.2018
comment
Это лучший ответ ИМО. Это позволяет инструментам сборки работать должным образом. По крайней мере, теперь я могу использовать внешний механизм для ввода числа в сборку. - person Michael Yanni; 30.08.2018
comment
Также убедитесь, что у вас нет ‹Version› 1.0.0 ‹/Version› в вашем .csproj - person College Code; 10.05.2021

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

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

Это укажет компилятору .NET Core использовать все, что находится в переменной среды BUILD_BUILDNUMBER, если она присутствует, или вернуться к 0.0.1-local, если вы выполняете сборку на своем локальном компьютере.

person joelsand    schedule 17.08.2017
comment
Хорошо, мне нравится этот подход, потому что переменные окружения можно просто установить на сервере сборки, в то время как эти условные выражения определяют набор сборки в двоичных файлах. - person jbooker; 21.08.2017
comment
Похоже, не работает с TFS 2010, но, надеюсь, мы скоро перейдем к этому! - person Mark Adamson; 10.10.2017
comment
Неплохое решение, хотя может потребоваться немного поработать, если в решении много проектов. - person tofutim; 02.01.2018
comment
Хорошее решение. Однако я получил исключение сборки. Мне пришлось немного изменить конфиг, чтобы это исправить. stackoverflow.com/a/59858009/106227 - person Stu Harper; 22.01.2020
comment
Это отлично работает с .NET Core 2.1.2 и TFS2017U3. - person Dave Johnson; 07.02.2020
comment
Один из простейших подходов, без скриптов и (к сожалению) актуальный для dotnet 5 - person Remy; 23.04.2021

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

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

Будет выведен пакет с таким именем: PackageName.1.0.0-pre20180807-1711.nupkg.

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

Version формируется из комбинации VersionPrefix и VersionSuffix, или, если VersionSuffix пусто, только VersionPrefix.

<PropertyGroup>
  <VersionPrefix>1.0.0</VersionPrefix>
</PropertyGroup>
person Fabricio Godoy    schedule 07.08.2018

Я придумал решение, которое работало почти так же, как старый атрибут AssemblyVersion со звездочкой (*) - AssemblyVersion (1.0. *)

Значения для AssemblyVersion и AssemblyFileVersion находятся в файле .csproj проекта MSBuild (а не в AssemblyInfo.cs) как свойство < strong> 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.Build.Utilities.Task пакета NuGet Microsoft.Build.Utilities.Core. Он принимает свойство BaseVersion (необязательно) на входе и возвращает сгенерированную версию в свойстве вывода Version. Логика получения номеров версий такая же, как и для автоматического управления версиями .NET (номер сборки - это количество дней с 01.01.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.Build.Tasks

Теперь мы настраиваем 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>

Здесь важно:

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

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

person HolaJan    schedule 15.04.2017
comment
Я бы рекомендовал использовать DateTime.UtcNow вместо DateTime.Now в методе GetCurrentBuildVersionString(), в частности, если код выполняется на машинах автоматической сборки. Они могут работать в 2 или 3 часа ночи, когда ваш компьютер переключается на летнее время и обратно. С DateTime.Now в этом сценарии вы можете вернуться назад с точки зрения версии. По общему признанию, это угловой случай, и я также признаю, что я придирчив. :-) Кроме того, проблема исчезнет, ​​если вы настроите один и тот же часовой пояс на всех машинах сборки и не будете переходить на летнее время. - person Manfred; 02.08.2017
comment
Есть ли для этого пакет NuGet? - person Jonathan Allen; 20.12.2017
comment
@Jonathan Allen: Нет, у меня нет планов для пакета nuget из-за разных имен в каждом проекте. Вы можете загрузить скомпилированную сборку задачи сборки на странице github.com/holajan/DC. Папка Build.Tasks / tree / master / dist - person HolaJan; 21.12.2017

Я принял приведенный выше ответ, потому что @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.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)
person Jason H    schedule 25.03.2017

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

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

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

person Gigi    schedule 25.03.2017
comment
Я боялся, что это будет ответ. Я посмотрю, смогу ли я сделать шаг перед сборкой, чтобы увеличить его. - person Jason H; 25.03.2017
comment
Как указано в другом потоке, новый формат csproj позволяет отключить автоматическое создание файла assemblyinfo и указать свой собственный. Я последовал совету ответа natemcmaster и использовал стандартный файл AssemblyInfo.cs: stackoverflow.com/questions/42138418/ - person James Eby; 22.06.2017
comment
Почему убрали автоинкремент? У меня это работало очень хорошо и очень просто в течение многих лет. Я нажимаю master, CI сборки и приращения, затем версия считывается непосредственно из встроенной библиотеки DLL с использованием некоторого сценария PS, а затем использую эту версию в качестве аргумента при отправке в NuGet. Так просто. Сейчас сломано. - person Luke Puplett; 30.08.2017
comment
@LukePuplett: см. [«Непонятное сообщение об ошибке для подстановочного знака в AssemblyVersion на .Net Core # 22660»] (github.com/dotnet/roslyn/issues/22660). Причины, по которым они считают детерминированные сборки полезными, описаны в blog.paranoidcoding.com/2016/04/05/ и компиляторы должны быть детерминированными: одни и те же входные данные генерируют одинаковые выходные данные # 372 ‹github.com/dotnet/roslyn/issues/372 - person Michael Freidgeim; 28.10.2017
comment
Это довольно круто, и я согласен с этой идеей ... но ... почему бы не поддержать функцию * auto-increment-but-not-except-the-source-really-changed? #риторический вопрос - person Luke Puplett; 28.10.2017

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

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

person Chris McKenzie    schedule 31.07.2017
comment
В названии написано Автоматическое управление версиями в Visual Studio 2017 (.NET Core). Где именно сборка вручную соответствует Visual Studio 2017? - person JCKödel; 02.08.2017
comment
Я отвечал на вопрос: кто-нибудь понял, как управлять версией в проектах .NET Core (или .NETStandard, если на то пошло). Я обнаружил, что этот вопрос пытается решить эту проблему в контексте сборки CI. Я хотел установить версию сборки на номер сборки CI. Извините, если вы считаете, что это не имеет отношения к рассматриваемому вопросу. - person Chris McKenzie; 02.08.2017
comment
Для меня это полезный компонент, спасибо. Я буду использовать это как часть решения CI - person Mark Adamson; 27.09.2017
comment
@ChrisMcKenzie: ваш комментарий должен быть включен в ваш ответ, чтобы прояснить ваше намерение - person Michael Freidgeim; 28.10.2017
comment
** это не работает для меня в проектах netstandard, когда assemblyinfo.cs не указан, а версия находится в csproj ... - person tofutim; 02.01.2018
comment
Попробуйте удалить версию из csproj? Я не считаю это необходимым. См. этот пример - person Chris McKenzie; 03.01.2018

Вы можете сделать это, как показано ниже, в файле csproj. Я не разбирался в математике. Я обнаружил это где-то еще на Stack Overflow, но это работает и даст вам что-то похожее на версию 1.0. *.

<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>
person Clarke76    schedule 06.03.2020
comment
Не работает для netstandard2.0 в моем окружении. Я использую .NET Core SDK 3.1.403. Что-то еще нужно, чтобы заставить эту работу работать? При запуске с dotnet build номер версии по умолчанию не меняется. - person Manfred; 26.10.2020
comment
Спасибо, коротко и работает. - @Manfred: Возможно, вместо этого используйте AssemblyVersion или что-то подобное. Это было проблемой для меня. FileVersion была установлена. но AssemblyVersion - нет. Также: ‹Version› больше не следует использовать (если я не ошибаюсь). - person Martini Bianco; 29.11.2020
comment
Также: Вместо ‹FileVersion› 1.0. … ‹/FileVersion› Я использовал ‹FileVersion› $ (VersionPrefix). … ‹/FileVersion›, а затем я могу правильно установить номер версии в свойстве VersionPefix. - person Martini Bianco; 29.11.2020

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

person Tagc    schedule 03.04.2017
comment
проклятый гений. любить это! - person pms1969; 13.07.2017

Спасибо @joelsand за то, что указали мне правильное направление.

Мне пришлось немного изменить его ответ, так как при запуске DevOps Build у меня возникло следующее исключение

Указанная строка версии не соответствует рекомендуемому формату - major.minor.build.revision

Мне пришлось добавить $ (BUILD_BUILDNUMBER) в конец раздела major.minor.build. Чтобы исключить дубликат фактической версии, я также использую префикс версии:

<PropertyGroup>
    <VersionPrefix>1.0.3</VersionPrefix>
    <Version Condition=" '$(BUILD_BUILDNUMBER)' == '' ">$(VersionPrefix)-local</Version>
    <Version Condition=" '$(BUILD_BUILDNUMBER)' != '' ">$(VersionPrefix)-$(BUILD_BUILDNUMBER)</Version>
</PropertyGroup>
person Stu Harper    schedule 22.01.2020
comment
У меня была такая же проблема, и ваш ответ исправил ее. Спасибо. - person Meeting Attender; 07.04.2020

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

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

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

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

Затем Prebuild.targets.xml сгенерирует файл CommonAssemblyInfo.cs, в который вы можете включить теги версии, которые хотите, на основе вашей версии GIT.

ПРИМЕЧАНИЕ: я нашел Prebuilds.targets.xml где-то еще, поэтому не стал его очищать.)

Файл 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>

РЕДАКТИРОВАТЬ: если вы строите с помощью MSBUILD,

 $(SolutionDir)

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

 $(ProjectDir)

вместо

person Tue Skeltved    schedule 06.10.2017
comment
Отлично! Будет ли установлен или использован VersionSuffix? Не похоже - person Mark Adamson; 10.10.2017

Мы можем использовать специальный параметр для 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.
person Anatoli Klamer    schedule 10.09.2018

В качестве альтернативы вы можете попробовать фиксированный старший номер с суффиксом на основе текущей даты:

  <PropertyGroup>
    <VersionPrefix>1</VersionPrefix>
    <VersionSuffix>$([System.DateTime]::UtcNow.ToString(yyMM)).$([System.DateTime]::UtcNow.ToString(ddHH)).$([System.DateTime]::UtcNow.ToString(mmss))</VersionSuffix>
    <Version Condition=" '$(VersionSuffix)' == '' ">$(VersionPrefix).0.0.1</Version>
    <Version Condition=" '$(VersionSuffix)' != '' ">$(VersionPrefix).$(VersionSuffix)</Version>
  </PropertyGroup>
person tsubasaetkisi    schedule 21.08.2020
comment
У вас есть хорошее решение. Однако не всем нравится использовать DateTime в своих версиях. - person Jason H; 21.08.2020

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

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

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

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

Один - build.xxxx, другой - BUILD_XXXX.

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

person maxisam    schedule 15.02.2018
comment
Разве build.xxxx не используется во внешнем интерфейсе для ссылки в конвейере, а BUILD_XXXX - это то же значение, но с немного измененным синтаксисом, необходимым для ссылки на переменную в PS? - person dst3p; 22.02.2019

Что сработало для меня, так это определить Patch и Revision с помощью PropertyGroup, тогда вы можете просто использовать эти переменные для версии (и префикса, если необходимо). Номера версий должны быть короткими, поэтому я использую YearMonth для Patch и MinutesOfDay для Revision. Добавьте эти строки в свой файл csproj:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <PropertyGroup>
        <VersionMajor>0</VersionMajor>
        <VersionMinor>9</VersionMinor>
        <VersionPatch Condition="'$(VersionPatch)' == ''">$([System.DateTime]::UtcNow.ToString("yyMM"))</VersionPatch>
        <VersionRevision Condition="'$(VersionRevision)' == ''">$([System.DateTime]::UtcNow.TimeOfDay.TotalMinutes.ToString("0"))</VersionRevision>
    </PropertyGroup>

    <PropertyGroup>
        <OutputType>...</OutputType>
        <TargetFramework>net5.0</TargetFramework>
        <Title>Software Title</Title>
        <Description>...</Description>
        <Authors>...</Authors>
        <Version>$(VersionMajor).$(VersionMinor).$(VersionPatch).$(VersionRevision)</Version>
    </PropertyGroup>

    ....

</Project>

Его можно получить обычным способом, используя Directory.build.props файл. Дополнительная информация здесь: https://docs.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2019

Просто добавьте файл с таким именем в папку проекта и поместите туда эти строки.


Я наткнулся здесь на поиски решения для общих проектов. В моем случае я решил добавить файл Version.build.props в мой общий проект со структурой, показанной выше, и только одну новую строку в любом файле csproj для проектов, использующих мой общий код:

<!-- Shared project import -->
<Import Project="..\Shared\Shared.projitems" Label="Shared" /> 
<!-- Version number generator -->
<Import Project="$([MSBuild]::GetPathOfFileAbove('Version.Build.props', '$(MSBuildThisFileDirectory)../Shared/'))" />

Я оставил этот код здесь на всякий случай, если он кому-то понадобится.

* Решение протестировано для .Net5, но должно работать и с более ранними версиями.

person Antonio Rodríguez    schedule 23.11.2020

  <PropertyGroup>
    <SecondsSinceEpoch>$([System.DateTime]::UtcNow.Subtract($([System.DateTime]::MinValue)).TotalSeconds)</SecondsSinceEpoch>
    <Revision>$([System.Math]::Truncate($([System.Decimal]::Remainder($(SecondsSinceEpoch), 100000))))</Revision>
    <Version>1.7.0.$(Revision)</Version>
    <AssemblyVersion>$(Version)</AssemblyVersion>
    <FileVersion>$(Version)</FileVersion>
  </PropertyGroup>

Мой подход к установке приличного значения через .csproj. К сожалению, если следующая перестройка произойдет через 100000 секунды, то значение будет таким же. Лучше, чем MSBump делать каждую сборку Re < / strong> build хотя.

Можно использовать TotalMinutes, TotalDays и т. Д. При медленной или автоматической сборке.

person Christopher Galpin    schedule 14.02.2021

Подводя итог всему вышесказанному: вы можете вернуться к старому AssemblyInfo.cs поведению следующим образом:

<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Deterministic>false</Deterministic>

Но этот подход не рекомендуется, потому что отключение GenerateAssemblyInfo может привести к проблемам с инфраструктурой, например . Более избирательный подход:

<Deterministic>false</Deterministic>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
<AssemblyVersion>1.2.*</AssemblyVersion>

и вам больше не нужен AssemblyInfo.cs.

person Kirsan    schedule 29.04.2021

Мой проект OSS RelaxVersioner может полностью автоматически вставлять атрибуты и константные литералы в репозиторий git только в пакете NuGet. устанавливается без использования каких-либо инструментов.

Пример прикладной информации:

sing System.Reflection;
[assembly: AssemblyVersion("1.0.21")]
[assembly: AssemblyFileVersion("2020.12.20.33529")]
[assembly: AssemblyInformationalVersion("1.0.21-561387e2f6dc90046f56ef4c3ac501aad0d5ec0a")]
[assembly: AssemblyMetadata("Date","Sun, 20 Dec 2020 09:37:39 GMT")]
[assembly: AssemblyMetadata("Branch","master")]
[assembly: AssemblyMetadata("Tags","")]
[assembly: AssemblyMetadata("Author","Kouji Matsui <[email protected]>")]
[assembly: AssemblyMetadata("Committer","Kouji Matsui <[email protected]>")]
[assembly: AssemblyMetadata("Message","Merge branch 'devel'")]
[assembly: AssemblyMetadata("Build","")]
[assembly: AssemblyMetadata("Generated","Sun, 20 Dec 2020 09:37:43 GMT")]
[assembly: AssemblyMetadata("Platform","AnyCPU")]
[assembly: AssemblyMetadata("BuildOn","Unix")]
[assembly: AssemblyMetadata("SdkVersion","5.0.101")]

namespace YourApp
{
  internal static class ThisAssembly
  {
    public const string AssemblyVersion = "1.0.21";
    public const string AssemblyFileVersion = "2020.12.20.33529";
    public const string AssemblyInformationalVersion = "1.0.21-561387e2f6dc90046f56ef4c3ac501aad0d5ec0a";
    public static class AssemblyMetadata
    {
      public const string Date = "Sun, 20 Dec 2020 09:37:39 GMT";
      public const string Branch = "master";
      public const string Tags = "";
      public const string Author = "Kouji Matsui <[email protected]>";
      public const string Committer = "Kouji Matsui <[email protected]>";
      public const string Message = "Merge branch 'devel'";
      public const string Build = "";
      public const string Generated = "Sun, 20 Dec 2020 09:37:43 GMT";
      public const string Platform = "AnyCPU";
      public const string BuildOn = "Unix";
      public const string SdkVersion = "5.0.101";
    }
  }
}
person Kouji Matsui    schedule 27.03.2021