Auto Versioning in Visual Studio 2017 (.NET Core)

后端 未结 16 1347
一整个雨季
一整个雨季 2020-11-28 18:45

I have spent the better part of a few hours trying to find a way to auto-increment versions in a .NETCoreApp 1.1 (Visual Studio 2017).

I know the the AssemblyInfo.cs

相关标签:
16条回答
  • 2020-11-28 19:26

    I came up with a solution that worked almost the same as old AssemblyVersion attribute with star (*) - AssemblyVersion("1.0.*")

    Values for AssemblyVersion and AssemblyFileVersion is in MSBuild project .csproj file (not in AssemblyInfo.cs) as property FileVersion (generates AssemblyFileVersionAttribute) and AssemblyVersion (generates AssemblyVersionAttribute). In MSBuild process we use our custom MSBuild task to generate version numbers and then we override values of these FileVersion and AssemblyVersion properties with new values from task.

    So first, we create our custom MSBuild task 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();
        }
    }
    

    Task class inherit from Microsoft.Build.Utilities.Task class from Microsoft.Build.Utilities.Core NuGet package. It takes BaseVersion property (optional) on input and returns generated version in Version output property. The logic to get version numbers is same as .NET automatic versioning (Build number is days count since 1/1/2000 and Revision is half seconds since midnight).

    To build this MSBuild task, we use .NET Standard 1.3 class library project type with this class.

    .csproj file can looks like this:

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

    This task project is also available in my GitHub holajan/DC.Build.Tasks

    Now we setup MSBuild to use this task and set FileVersion and AssemblyVersion properties. In .csproj file, it looks like this:

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

    Important things here:

    • Mentioned UsingTask imports GetCurrentBuildVersion task from DC.Build.Tasks.dll. It assumes that this dll file is located on parent directory from your .csproj file.
    • Our BeforeBuildActionsProject1 Target that calls task must have unique name per project in case we have more projects in the solution which calls GetCurrentBuildVersion task.

    The advantage of this solution is that it works not only from builds on build server, but also in manual builds from dotnet build or Visual Studio.

    0 讨论(0)
  • 2020-11-28 19:27

    I think this Answer from @joelsand is the correct answer for setting version number for dotnet core running on VSTS

    To add more information for this answer,

    BUILD_BUILDNUMBER is actually a predefined variable.

    It turns out there are 2 versions of predefined variable.

    One is build.xxxx, the other is BUILD_XXXX.

    You can only use Environment Variable Name in cproj.

    0 讨论(0)
  • 2020-11-28 19:28

    To enable versioning of your .NET Core / .NET Whatever project based on your GIT setup, using the tags/describe functionality of GIT.

    I have been using a Prebuild.targets.xml file which is located in the root folder for the project and included in the csproj file like:

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

    Use the "GenerateAssembyInfo" tag to disable automatic assembly info generation.

    Then the Prebuild.targets.xml will generate a CommonAssemblyInfo.cs file where you can include the version tags you want based on your GIT version

    NOTE: I have found the Prebuilds.targets.xml somewhere else, so haven't bothered cleaning it up .)

    The Prebuild.targets.xml file:

        <?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: If you are building using MSBUILD the

     $(SolutionDir)
    

    Might cause you trouble, use

     $(ProjectDir)
    

    instead

    0 讨论(0)
  • 2020-11-28 19:30

    I have been looking for a version incrementer for a .NET Core app in VS2017 using the csproj configuration format.

    I found a project called dotnet bump that worked for the project.json format but struggled to find a solution for the .csproj format. The writer of dotnet bump actually came up with the solution for the .csproj format and it is called MSBump.

    There is a project on GitHub for it at:

    https://github.com/BalassaMarton/MSBump

    where you can see the code and it's available on NuGet too. Just search for MSBump on Nuget.

    0 讨论(0)
提交回复
热议问题