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

113

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

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

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

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

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

Джейсон Х
источник
Я не знаю, как далеко вы продвинулись в этом, но похоже, что я задал почти тот же вопрос другим способом ( stackoverflow.com/a/43280282/685341 ). Возможно, принятый ответ на этот вопрос поможет вам; вы можете просто передать /p:флаг dotnet msbuildв свой скрипт сборки и установить версию, компанию, авторские права ... все это хорошее.
Джей
2
Спасибо за информацию. Это просто открывает дополнительные возможности.
Джейсон Х
Ранее * поддерживался для AssemblyVersion, а не для AssemblyFileVersion - см. Могу ли я автоматически увеличивать версию сборки файла при использовании Visual Studio?
Майкл
4
FWIW подстановочный знак в версии сборки не поддерживается, потому что для этого нового проекта "детерминированный" режим компилятора активен по умолчанию. Поскольку автоинкремент нарушит детерминизм (тот же ввод> тот же вывод), в этом режиме он запрещен. Вы можете настроить его <Deterministic>False</Deterministic>в csproj. (или используйте любую другую логику MSbuild для вычисления <VersionPrefix>/ <Version>)
Мартин Ульрих

Ответы:

23

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

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

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

https://github.com/BalassaMarton/MSBump

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

ravetroll
источник
1
Я рекомендую использовать последнюю версию MSBump 2.1.0, она лучше поддерживает переключение конфигураций, а также устанавливает версию для текущей сборки, а не для следующей (как предыдущая версия).
Мартон Баласса,
Я вижу, что теперь он также поддерживает MSBuild, тогда как раньше для этого требовалась визуальная студия.
ravetroll
2
Да, и он также поддерживает проекты с несколькими целями.
Márton Balassa
4
Рассмотрите возможность использования GitVersioning. Он может быть подходящим для работы в вашей среде CI. github.com/AArnott/Nerdbank.GitVersioning
Henrique
1
MSBump увеличивает версию при каждой сборке, даже если вы ничего не меняли, в долгосрочной перспективе это вызывает множество проблем. А иногда версии не синхронизируются, и одна версия отстает от другой.
Конрад
69

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

Обходной путь, заставляющий AssemblyVersion * работать, описан в «Непонятном сообщении об ошибке для подстановочного знака в [AssemblyVersion] в .Net Core # 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   
Майкл Фрейджейм
источник
Спасибо! Я знал, что есть скрытый рычаг для открытия сокровищницы! Я переношу старый проект на новый .NET SDK, и мне очень хотелось сделать это быстро, без хлопот по поиску решений для автоматического увеличения версии. На самом деле, чем больше совместимо со старыми способами, тем лучше для моего случая.
Ивайло Славов
Это лучший ответ ИМО. Это позволяет инструментам сборки работать правильно. По крайней мере, теперь я могу использовать внешний механизм для ввода числа в сборку.
Майкл Янни
Пожалуйста, расширите свой ответ еще немного: предлагаемое дополнение должно быть в разделе <PropertyGroup> файла .csproj. И, конечно, спасибо за отличный ответ!
GerardV
1
@gerardv, готово, но вы можете улучшить правки самостоятельно stackoverflow.com/help/editing
Майкл Фрейдгейм,
62

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

<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если вы выполняете сборку на своем локальном компьютере.

Joelsand
источник
Хорошо, мне нравится этот подход, потому что переменные окружения можно просто установить на сервере сборки, в то время как эти условные выражения определяют набор сборки в двоичных файлах.
jbooker
Похоже, не работает с TFS 2010, но, надеюсь, мы скоро перейдем к этому!
Марк Адамсон
Неплохое решение, хотя может потребоваться немного работы, если в решении много проектов.
tofutim 02
Хорошее решение. Однако я получил исключение сборки. Пришлось немного изменить конфиг, чтобы это исправить. stackoverflow.com/a/59858009/106227
Стю Харпер,
Это отлично работает с .NET Core 2.1.2 и TFS2017U3
Дэйв Джонсон,
16

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

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

HolaJan
источник
4
Я бы рекомендовал использовать DateTime.UtcNowвместо DateTime.Nowметода GetCurrentBuildVersionString()in, в частности, если код выполняется на машинах автоматической сборки. Они могут работать в 2 или 3 часа ночи, когда ваш компьютер переключается на летнее время и обратно. В DateTime.Nowэтом сценарии вы можете вернуться назад с точки зрения версии. По общему признанию, это угловой случай, и я также признаю, что я придирчив. :-) Кроме того, проблема исчезнет, ​​если вы настроите один и тот же часовой пояс на всех машинах сборки и не будете переходить на летнее время.
Манфред
Есть ли для этого пакет NuGet?
Джонатан Аллен
@Jonathan Allen: Нет, у меня нет планов для пакета nuget из-за разных имен в каждом проекте. Вы можете скачать скомпилированную сборку задач сборки в папке github.com/holajan/DC.Build.Tasks/tree/master/dist
HolaJan
Мы использовали настраиваемое консольное приложение, чтобы получить нашу версию с сервера и создать файл AssemblyInfo.cs перед сборкой. Такой подход идеально подходит для того, что мы делаем. Удалось ли вам использовать этот метод, чтобы поместить версию в «Версия» функции пакета новых проектов? Было бы неплохо, но я думаю, мы можем вернуться к использованию nuget.exe для упаковки, поскольку он нам также понадобится для публикации.
Дэвид Ричи
15

Вы можете использовать функцию свойства 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>
Фабрицио Годой
источник
Это действительно удобно
Джерри Никсон
12

Я принял приведенный выше ответ, потому что @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)
Джейсон Х
источник
10

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

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

Крис Маккензи
источник
1
В названии написано «Автоматическое управление версиями в Visual Studio 2017 (.NET Core)». Где именно сборка вручную соответствует «Visual Studio 2017»?
JCKödel
4
Я отвечал: «Кто-нибудь придумал, как управлять версией в проектах .NET Core (или .NETStandard в этом отношении)». Я обнаружил, что этот вопрос пытается решить эту проблему в контексте сборки CI. Я хотел установить версию сборки на номер сборки CI. Извините, если вы считаете, что это не имеет отношения к рассматриваемому вопросу.
Крис Маккензи
Спасибо, это полезный компонент. Я буду использовать это как часть решения CI
Марк Адамсон,
1
@ChrisMcKenzie: ваш комментарий должен быть включен в ваш ответ, чтобы прояснить ваши намерения
Майкл
** это не работает для меня в проектах netstandard, когда assemblyinfo.cs не указан, а версия находится в csproj ...
tofutim 02
9

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

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

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

Джиджи
источник
6
Я боялся, что это будет ответ. Я посмотрю, смогу ли я сделать шаг перед сборкой, чтобы увеличить его.
Jason H
3
Как указано в другом потоке, новый формат csproj позволяет вам отключить автоматическое создание файла assemblyinfo и указать свой собственный. Я последовал совету natemcmaster answer здесь и использовал стандартный файл AssemblyInfo.cs: stackoverflow.com/questions/42138418/…
Джеймс Эби
5
Почему убрали автоинкремент? У меня это работало очень хорошо и очень просто в течение многих лет. Я нажимаю master, CI сборки и приращения, затем версия считывается непосредственно из встроенной DLL с использованием некоторого сценария PS, а затем использую эту версию в качестве аргумента при отправке в NuGet. Так просто. Сейчас сломано.
Люк Пуплетт
1
@LukePuplett здесь тоже самое. так обидно!
Шимми Вайцхандлер
@LukePuplett: См. [«Непонятное сообщение об ошибке для подстановочного знака в AssemblyVersion на .Net Core # 22660»] ( github.com/dotnet/roslyn/issues/22660 ), Причины, по которым они считают Детерминированные сборки полезными, описаны на сайте blog.paranoidcoding.com / 2016/04/05 /… и компиляторы должны быть детерминированными: одни и те же входные данные генерируют одинаковые выходные данные # 372 < github.com/dotnet/roslyn/issues/372 >
Майкл
5

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

Tagc
источник
@JasonH Спасибо, дайте мне знать, если у вас возникнут проблемы.
Tagc 03
проклятый гений. любить это!
pms1969
4

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

вместо

Вт Скельтвед
источник
Ницца! Будет ли установлен или использован VersionSuffix? Не похоже
Марк Адамсон
4

Вы можете сделать следующее в файле csproj. Я не разбирался в математике. Я обнаружил это где-то еще в stackoverflow. Но это работает и даст вам нечто похожее на версию 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>
Кларк76
источник
3

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

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

госпожа
источник
1
Я провел быстрый тест с демонстрационным решением (приложение для Windows), и он работает, также со стандартным проектом .net. Это был быстрый тест, поэтому придется погрузиться глубже, чтобы проверить, все ли получается, что мы хотим. Но вы обязательно можете попробовать это.
ArieKanarie
3

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

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

The specified version string does not conform to the recommended format - 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>
Стю Харпер
источник
У меня была такая же проблема, и ваш ответ исправил ее. Спасибо.
Посетитель встречи
2

Мы можем использовать специальный параметр для 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.
Анатолий Кламер
источник
1

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

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

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

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

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

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

максисам
источник
Не build.xxxxиспользуется во внешнем интерфейсе для ссылки в конвейере и BUILD_XXXXимеет то же значение, но с немного измененным синтаксисом, необходимым для ссылки на переменную в PS?
dst3p
1

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

  <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>
tsubasaetkisi
источник
У вас есть хорошее решение. Однако не всем нравится использовать DateTime в своих версиях.
Джейсон Х