我花了几个小时的时间试图找到一种在.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配置格式为VS2017中的Net Core应用程序寻找版本增量器。
我找到了一个名为dotnet bump的项目,该项目适用于project.json格式,但很难找到.csproj格式的解决方案。作者dotnet bump实际上提出了.csproj格式的解决方案,它被称为MSBump。
在GitHub上有一个项目:
https://github.com/BalassaMarton/MSBump
在那里你可以看到Nuget上的代码及其可用的代码。只需在Nuget上搜索MSBump。
使用GIT的标签/描述功能,根据您的GIT设置启用.Net Core / .Net的任何项目的版本控制。
我一直在使用Prebuild.targets.xml文件,该文件位于项目的根文件夹中,并包含在csproj文件中,如:
#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)
使用“生成AssemblyInfo”标记禁用自动assemblyinfo生成。
然后Prebuild.targets.xml将生成一个CommonAssemblyInfo.cs文件,您可以根据您的GIT版本包含所需的版本标签
注意:我在其他地方找到了Prebuilds.targets.xml,所以没有打扰清理它。)
Prebuild.targets.xml文件:
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="PreBuild.targets.xml" />
...
<PropertyGroup>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
编辑:如果你正在使用MSBUILD建设
<?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>
可能会给你带来麻烦,使用
$(SolutionDir)
代替
Visual Studio的自动版本扩展现在支持简单的用户界面中的.Net Core和.Net Standard自动增量。
$(ProjectDir)
我认为来自@joelsand的这个https://marketplace.visualstudio.com/items?itemName=PrecisionInfinity.AutomaticVersions是设置在VSTS上运行的dotnet核心版本号的正确答案
要为此答案添加更多信息,
Answer实际上是一个BUILD_BUILDNUMBER
。
事实证明,有两个版本的预定义变量。
一个是build.xxxx,另一个是BUILD_XXXX。
你只能在csproj中使用predefined variable。
我们可以使用Environment Variable Name
的特殊参数
对于文件版本:
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
如果您使用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
。
在.csproj的<Deterministic>False</Deterministic>
部分中添加<PropertyGroup>
在Qazxswpoi中描述了使AssemblyVersion *工作的变通方法
只有在构建不确定时才允许使用通配符,这是.Net Core项目的默认设置。将“Confusing error message for wildcard in [AssemblyVersion] on .Net Core #22660”添加到csproj可以解决这个问题。
.Net核心开发人员认为<Deterministic>False</Deterministic>
和http://blog.paranoidcoding.com/2016/04/05/deterministic-builds-in-roslyn.html中描述的确定性构建有益的原因
但是,如果您正在使用TeamCity,TFS或其他CI / CD工具,最好保持版本号受控制并增加它们并将其作为参数传递给构建(如在其他答案中所建议的那样),例如,
Compilers should be deterministic: same inputs generate same outputs #372
包裹号码msbuild /t:build /p:Version=YourVersionNumber /p:AssemblyVersion=YourVersionNumber
for NuGet packages
我提出的解决方案与旧的AssemblyVersion属性几乎相同,只有星号(*) - AssemblyVersion(“1.0。”)*
AssemblyVersion和AssemblyFileVersion的值在MSBuild项目.csproj文件中(不在AssemblyInfo.cs中)作为属性FileVersion(生成AssemblyFileVersionAttribute)和AssemblyVersion(生成AssemblyVersionAttribute)。在MSBuild过程中,我们使用自定义MSBuild任务生成版本号,然后使用来自task的新值覆盖这些FileVersion和AssemblyVersion属性的值。
首先,我们创建自定义MSBuild任务GetCurrentBuildVersion:
msbuild /t:pack /p:Version=YourVersionNumber
任务类继承自Microsoft.Build.Utilities.Core NuGet包中的Microsoft.Build.Utilities.Task类。它在输入上使用BaseVersion属性(可选)并在Version输出属性中返回生成的版本。获取版本号的逻辑与.NET自动版本控制相同(内部版本号是自2000年1月1日起的天数,而修订版是午夜后的半秒)。
要构建此MSBuild任务,我们将.NET Class 1.3类库项目类型与此类一起使用。
.csproj文件可能如下所示:
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();
}
}
这个任务项目也可以在我的GitHub <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>
中找到
现在我们设置MSBuild来使用此任务并设置FileVersion和AssemblyVersion属性。在.csproj文件中,它看起来像这样:
holajan/DC.Build.Tasks
重要的事情:
此解决方案的优点是它不仅可以从构建服务器上构建,还可以在dotnet构建或Visual Studio的手动构建中工作。
现在,这些值在<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>
文件中设置:
.csproj
如果您进入项目设置的“包”选项卡,则这些值与您看到的值相同。虽然我认为您不能使用<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
<AssemblyVersion>1.0.6.0</AssemblyVersion>
<FileVersion>1.0.6.0</FileVersion>
<Version>1.0.1</Version>
</PropertyGroup>
自动增加版本,但您可以做的是引入一个后处理步骤来替换您的版本(例如,作为持续集成的一部分)。
dotnet build /p:AssemblyVersion=1.2.3.4
我回答说:“有没有人想出如何控制.NET Core(或.NETStandard)项目中的版本。”我发现这个问题试图在CI构建的上下文中解决这个问题。我想将程序集版本设置为CI内部版本号。
您可以使用MSBuild属性函数根据当前日期设置版本后缀:
*
这将输出一个名为PackageName.1.0.0-pre20180807-1711.nupkg的包。
有关MSBuild属性函数的更多详细信息:<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<VersionSuffix>pre$([System.DateTime]::UtcNow.ToString(yyyyMMdd-HHmm))</VersionSuffix>
</PropertyGroup>
我做了一个简单的CLI工具来设置.csproj .NET核心版本字符串https://docs.microsoft.com/en-us/visualstudio/msbuild/property-functions。您可以将它与GitVersion等工具结合使用,以便在CI构建期间实现自动版本冲突,如果这就是您所追求的。
我接受了上面的答案,因为@Gigi是正确的(截至目前),但我很恼火,并提出了以下PowerShell脚本。
首先,我在我的解决方案文件夹(UpdateBuildVersion.ps1)中有脚本:
here
我把它添加到csproj文件中:
#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)
即使将其设置为PreBuildEvent,事实上版本号在文件加载到内存之后才会更新,因此版本号在下一次构建之前不会反映出来。实际上,您可以将其更改为PostBuildEvent,它将具有相同的效果。
我还创建了以下两个脚本:(UpdateMinorVersion.ps1)
<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>
(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 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)