Visual Studio 2017 中的自动版本控制(.NET Core)
Auto Versioning in 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)项目中控制版本。
这些值现在设置在 .csproj
文件中:
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
<AssemblyVersion>1.0.6.0</AssemblyVersion>
<FileVersion>1.0.6.0</FileVersion>
<Version>1.0.1</Version>
</PropertyGroup>
这些值与您在项目设置的 Package 选项卡中看到的值相同。虽然我不认为你可以使用 *
来自动增加版本,但你可以做的是引入一个 post 处理步骤来为你替换版本(例如,作为持续集成的一部分)。
我接受了上面的答案,因为@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)
我做了一个简单的 CLI 工具来设置 .csproj .NET Core 版本字符串 here。您可以将它与 GitVersion 等工具结合使用,以便在 CI 构建期间自动升级版本,如果这就是您所追求的。
我想出了一个解决方案,它与带星号 (*) 的旧 AssemblyVersion 属性几乎相同 - AssemblyVersion("1.0.*")
AssemblyVersion 和 AssemblyFileVersion 的值在 MSBuild 项目 .csproj 文件中(不在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();
}
}
任务 class 继承自 Microsoft.Build.Utilities.Task class 来自 Microsoft.Build.Utilities.Core NuGet包裹。
它在输入上采用 BaseVersion 属性(可选),在 Version 输出 属性 中采用 returns 生成的版本。获取版本号的逻辑与 .NET 自动版本控制相同(内部版本号是自 1/1/2000 以来的天数,修订版是自午夜以来的半秒)。
为了构建这个 MSBuild 任务,我们使用 .NET Standard 1.3 class library 项目类型和 class.
.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>
这个任务项目也可以在我的GitHubholajan/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 从 DC.Build.Tasks.dll 导入 GetCurrentBuildVersion 任务。它假定此 dll 文件位于 .csproj 文件的父目录中。
- 我们的 BeforeBuildActionsProject1 调用任务的目标必须具有每个项目的唯一名称,以防我们在调用 GetCurrentBuildVersion 任务的解决方案中有更多项目。
此解决方案的优势在于它不仅适用于构建服务器上的构建,而且适用于来自 dotnet build 或 Visual Studio.[=14 的手动构建=]
has anyone figured out how to control version in .NET Core (or .NETStandard for that matter) projects.
使用:
dotnet build /p:AssemblyVersion=1.2.3.4
我发现这个问题试图在 CI 构建的上下文中解决这个问题。我想将程序集版本设置为 CI 内部版本号。
我一直在寻找 VS2017 中使用 csproj 配置格式的 .NET Core 应用程序的版本增量器。
我找到了一个名为 dotnet bump 的项目,该项目适用于 project.json 格式,但很难找到适用于 .csproj 格式的解决方案。 dotnet bump 的作者实际上想出了 .csproj 格式的解决方案,它被称为 MSBump。
GitHub 上有一个项目:
https://github.com/BalassaMarton/MSBump
您可以在其中查看代码,它也可以在 NuGet 上使用。只需在 Nuget 上搜索 MSBump。
如果您正在使用 Visual Studio 团队 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
如果您在本地计算机上进行构建。
使用 GIT 的 tags/describe 功能,根据您的 GIT 设置启用 .NET Core / .NET Whatever 项目的版本控制。
我一直在使用 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)
改为
在 .csproj
的 <PropertyGroup>
部分中添加 <Deterministic>False</Deterministic>
“Confusing error message for wildcard in [AssemblyVersion] on .Net Core #22660”
中描述了使 AssemblyVersion * 工作的解决方法
Wildcards are only allowed if the build is not deterministic, which
is the default for .Net Core projects.
Adding <Deterministic>False</Deterministic>
to csproj fixes the
issue.
http://blog.paranoidcoding.com/2016/04/05/deterministic-builds-in-roslyn.html 中描述的 .Net Core 开发人员认为确定性构建有益的原因
和 Compilers should be deterministic: same inputs generate same outputs #372
但是,如果您使用的是 TeamCity、TFS 或其他 CI/CD 工具,最好让版本号由它们控制和递增,并作为参数传递给构建(正如其他答案中所建议的那样) ) ,例如
msbuild /t:build /p:Version=YourVersionNumber /p:AssemblyVersion=YourVersionNumber
msbuild /t:pack /p:Version=YourVersionNumber
我认为来自@joelsand 的 是在 VSTS
上为 dotnet 核心 运行 设置版本号的正确答案
要为此答案添加更多信息,
BUILD_BUILDNUMBER
其实就是一个predefined variable。
原来有两个版本的预定义变量。
一个是build.xxxx,另一个是BUILD_XXXX。
您只能在 cproj 中使用 Environment Variable Name
。
您可以使用 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>
我们可以为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.
感谢@joelsand 为我指明了正确的方向。
在 DevOps 构建 运行 时,我不得不稍微更改他的答案,我得到以下异常
The specified version string does not conform to the recommended format - major.minor.build.revision
我不得不在 major.minor.build 部分的末尾添加 $(BUILD_BUILDNUMBER) 。为了消除实际版本的重复,我还使用了版本前缀:
<PropertyGroup>
<VersionPrefix>1.0.3</VersionPrefix>
<Version Condition=" '$(BUILD_BUILDNUMBER)' == '' ">$(VersionPrefix)-local</Version>
<Version Condition=" '$(BUILD_BUILDNUMBER)' != '' ">$(VersionPrefix)-$(BUILD_BUILDNUMBER)</Version>
</PropertyGroup>
您可以像下面那样在 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>
作为替代方案,您可以尝试使用基于当前日期的后缀固定主号码:
<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>
对我有用的是使用 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 测试的解决方案,但应该适用于早期版本。
<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 让每个 Build 一个 Rebuild 更好。
如果构建缓慢或自动化,可以使用 TotalMinutes
、TotalDays
等。
我的 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 <k@kekyo.net>")]
[assembly: AssemblyMetadata("Committer","Kouji Matsui <k@kekyo.net>")]
[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 <k@kekyo.net>";
public const string Committer = "Kouji Matsui <k@kekyo.net>";
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";
}
}
}
总结以上所有内容:您可以通过以下方式恢复到旧的 AssemblyInfo.cs
行为:
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Deterministic>false</Deterministic>
但不推荐这种方法,因为关闭 GenerateAssemblyInfo
会导致基础设施问题,for example。
更具选择性的方法:
<Deterministic>false</Deterministic>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
<AssemblyVersion>1.2.*</AssemblyVersion>
而且您不再需要 AssemblyInfo.cs
。
我花了几个小时的大部分时间试图找到一种在 .NETCoreApp 1.1(Visual Studio 2017)中自动增加版本的方法。
我知道 AssemblyInfo.cs 正在文件夹中动态创建:obj/Debug/netcoreapp1.1/
它不接受旧方法:
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.*")]
如果我将项目设置为打包,我可以在那里设置版本,但这似乎用于构建 AssemblyInfo.cs 文件。
我的问题是,有没有人知道如何在 .NET Core(或 .NETStandard)项目中控制版本。
这些值现在设置在 .csproj
文件中:
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
<AssemblyVersion>1.0.6.0</AssemblyVersion>
<FileVersion>1.0.6.0</FileVersion>
<Version>1.0.1</Version>
</PropertyGroup>
这些值与您在项目设置的 Package 选项卡中看到的值相同。虽然我不认为你可以使用 *
来自动增加版本,但你可以做的是引入一个 post 处理步骤来为你替换版本(例如,作为持续集成的一部分)。
我接受了上面的答案,因为@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)
我做了一个简单的 CLI 工具来设置 .csproj .NET Core 版本字符串 here。您可以将它与 GitVersion 等工具结合使用,以便在 CI 构建期间自动升级版本,如果这就是您所追求的。
我想出了一个解决方案,它与带星号 (*) 的旧 AssemblyVersion 属性几乎相同 - AssemblyVersion("1.0.*")
AssemblyVersion 和 AssemblyFileVersion 的值在 MSBuild 项目 .csproj 文件中(不在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();
}
}
任务 class 继承自 Microsoft.Build.Utilities.Task class 来自 Microsoft.Build.Utilities.Core NuGet包裹。 它在输入上采用 BaseVersion 属性(可选),在 Version 输出 属性 中采用 returns 生成的版本。获取版本号的逻辑与 .NET 自动版本控制相同(内部版本号是自 1/1/2000 以来的天数,修订版是自午夜以来的半秒)。
为了构建这个 MSBuild 任务,我们使用 .NET Standard 1.3 class library 项目类型和 class.
.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>
这个任务项目也可以在我的GitHubholajan/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 从 DC.Build.Tasks.dll 导入 GetCurrentBuildVersion 任务。它假定此 dll 文件位于 .csproj 文件的父目录中。
- 我们的 BeforeBuildActionsProject1 调用任务的目标必须具有每个项目的唯一名称,以防我们在调用 GetCurrentBuildVersion 任务的解决方案中有更多项目。
此解决方案的优势在于它不仅适用于构建服务器上的构建,而且适用于来自 dotnet build 或 Visual Studio.[=14 的手动构建=]
has anyone figured out how to control version in .NET Core (or .NETStandard for that matter) projects.
使用:
dotnet build /p:AssemblyVersion=1.2.3.4
我发现这个问题试图在 CI 构建的上下文中解决这个问题。我想将程序集版本设置为 CI 内部版本号。
我一直在寻找 VS2017 中使用 csproj 配置格式的 .NET Core 应用程序的版本增量器。
我找到了一个名为 dotnet bump 的项目,该项目适用于 project.json 格式,但很难找到适用于 .csproj 格式的解决方案。 dotnet bump 的作者实际上想出了 .csproj 格式的解决方案,它被称为 MSBump。
GitHub 上有一个项目:
https://github.com/BalassaMarton/MSBump
您可以在其中查看代码,它也可以在 NuGet 上使用。只需在 Nuget 上搜索 MSBump。
如果您正在使用 Visual Studio 团队 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
如果您在本地计算机上进行构建。
使用 GIT 的 tags/describe 功能,根据您的 GIT 设置启用 .NET Core / .NET Whatever 项目的版本控制。
我一直在使用 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)
改为
在 .csproj
的<PropertyGroup>
部分中添加 <Deterministic>False</Deterministic>
“Confusing error message for wildcard in [AssemblyVersion] on .Net Core #22660”
中描述了使 AssemblyVersion * 工作的解决方法Wildcards are only allowed if the build is not deterministic, which is the default for .Net Core projects. Adding
<Deterministic>False</Deterministic>
to csproj fixes the issue.
http://blog.paranoidcoding.com/2016/04/05/deterministic-builds-in-roslyn.html 中描述的 .Net Core 开发人员认为确定性构建有益的原因 和 Compilers should be deterministic: same inputs generate same outputs #372
但是,如果您使用的是 TeamCity、TFS 或其他 CI/CD 工具,最好让版本号由它们控制和递增,并作为参数传递给构建(正如其他答案中所建议的那样) ) ,例如
msbuild /t:build /p:Version=YourVersionNumber /p:AssemblyVersion=YourVersionNumber
msbuild /t:pack /p:Version=YourVersionNumber
我认为来自@joelsand 的
要为此答案添加更多信息,
BUILD_BUILDNUMBER
其实就是一个predefined variable。
原来有两个版本的预定义变量。
一个是build.xxxx,另一个是BUILD_XXXX。
您只能在 cproj 中使用 Environment Variable Name
。
您可以使用 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>
我们可以为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.
感谢@joelsand 为我指明了正确的方向。
在 DevOps 构建 运行 时,我不得不稍微更改他的答案,我得到以下异常
The specified version string does not conform to the recommended format - major.minor.build.revision
我不得不在 major.minor.build 部分的末尾添加 $(BUILD_BUILDNUMBER) 。为了消除实际版本的重复,我还使用了版本前缀:
<PropertyGroup>
<VersionPrefix>1.0.3</VersionPrefix>
<Version Condition=" '$(BUILD_BUILDNUMBER)' == '' ">$(VersionPrefix)-local</Version>
<Version Condition=" '$(BUILD_BUILDNUMBER)' != '' ">$(VersionPrefix)-$(BUILD_BUILDNUMBER)</Version>
</PropertyGroup>
您可以像下面那样在 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>
作为替代方案,您可以尝试使用基于当前日期的后缀固定主号码:
<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>
对我有用的是使用 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 测试的解决方案,但应该适用于早期版本。
<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 让每个 Build 一个 Rebuild 更好。
如果构建缓慢或自动化,可以使用 TotalMinutes
、TotalDays
等。
我的 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 <k@kekyo.net>")]
[assembly: AssemblyMetadata("Committer","Kouji Matsui <k@kekyo.net>")]
[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 <k@kekyo.net>";
public const string Committer = "Kouji Matsui <k@kekyo.net>";
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";
}
}
}
总结以上所有内容:您可以通过以下方式恢复到旧的 AssemblyInfo.cs
行为:
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Deterministic>false</Deterministic>
但不推荐这种方法,因为关闭 GenerateAssemblyInfo
会导致基础设施问题,for example。
更具选择性的方法:
<Deterministic>false</Deterministic>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
<AssemblyVersion>1.2.*</AssemblyVersion>
而且您不再需要 AssemblyInfo.cs
。