私は.NETCoreApp 1.1(Visual Studio 2017)でバージョンを自動インクリメントする方法を見つけることを試みるために数時間の大部分を費やしました。
AssemblyInfo.csがフォルダ内に動的に作成されていることを私は知っています:obj/Debug/netcoreapp1.1/
古いメソッド[Assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.*")]
を受け入れません。
プロジェクトをパッケージに設定した場合は、そこでバージョンを設定できますが、これはAssemblyInfo.csファイルのビルドに使用されているようです。
私の質問は、誰もが.NET Core(またはそのことについては.NETStandard)プロジェクトでバージョンを制御する方法を考え出したということです。
私はVS2017でcsproj設定フォーマットを使ってNet Coreアプリのバージョンインクリメンターを探していました。
Dotnet bumpというプロジェクトが見つかりました。このプロジェクトはproject.jsonフォーマットで動作しましたが、.csprojフォーマットの解決策を見つけるのに苦労しました。作家ドットネットバンプは実際に.csprojフォーマットのための解決策を思いつきました、そしてそれはMSBumpと呼ばれます。
GitHubにはそのためのプロジェクトがあります。
https://github.com/BalassaMarton/MSBump
nugetでも利用可能なコードとそのコードを見ることができます。 NugetでMSBumpを検索してください。
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>
を追加します。
AssemblyVersion *を機能させるための回避策は 「.Net Core#22660の[AssemblyVersion]のワイルドカードに関するエラーメッセージの混乱」 で説明されています。
ワイルドカードは、ビルドが確定的でない場合にのみ許可されます。これは、.NET Coreプロジェクトのデフォルトです。 csprojに
<Deterministic>False</Deterministic>
を追加することで問題は解決します。
.Netコア開発者が決定論的ビルドを有益と考える理由は、 http://blog.paranoidcoding.com/2016/04/05/deterministic-builds-in-roslyn.html と コンパイラは決定論的であるべきです:同じ入力は同じ出力を生成します#372
ただし、TeamCity、TFS、または他のCI/CDツールを使用している場合は、バージョン番号を管理し、それらを追加して、他の回答で提案されているようにパラメータとしてbuildに渡すほうがおそらくよいでしょう。
msbuild /t:build /p:Version=YourVersionNumber /p:AssemblyVersion=YourVersionNumber
パッケージ番号 NuGetパッケージ用
msbuild /t:pack /p:Version=YourVersionNumber
Star(*) - AssemblyVersion( "1.0。")*の古い AssemblyVersion 属性とほぼ同じように機能する解決策を思いつきました。
AssemblyVersionおよびAssemblyFileVersionの値は、プロパティとしてMSBuildプロジェクト .csproj fileにあります(AssemblyInfo.csにはない) FileVersion (AssemblyFileVersionAttribute)を生成し、 AssemblyVersion (AssemblyVersionAttribute)を生成します。 MSBuildプロセスでは、カスタムMSBuildタスクを使用してバージョン番号を生成してから、これらの FileVersion および AssemblyVersion プロパティの値をtaskからの新しい値でオーバーライドします。
そこで最初にカスタム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の自動バージョン管理と同じです(ビルド番号は2000年1月1日以降の日数、改訂は午前0時からの秒数です)。
この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 propertiesを設定します。 .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>
ここで重要なこと:
このソリューションの利点は、ビルドサーバー上のビルドからだけでなく、dotnet buildまたはVisual Studioからの手動ビルドでも機能することです。
これらの値は.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タブに移動したときに表示される値と同じです。 *
を使用してバージョンを自動インクリメントすることはできないと思いますが、できることはバージョンを置き換える後処理ステップを導入することです(たとえば、継続的インテグレーションの一部として)。
dotnet build /p:AssemblyVersion=1.2.3.4
私は次のように答えていました。私はこの問題をCIビルドのコンテキストで解決しようとしているのに気づきました。 AssemblyバージョンをCIビルド番号に設定したいと思いました。
現在の日付に基づいてバージョンサフィックスを設定するために、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/ja-jp/visualstudio/msbuild/property-functions
@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に変更しても同じ効果があります。
次の2つのスクリプトも作成しました。(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)
ここで.csproj .NET Coreバージョン文字列 を設定するための簡単なCLIツールを作成しました 。あなたがそれを望んでいるのであれば、あなたはそれをCIビルド中の自動バージョンバンピングのためのGitVersionのようなツールと組み合わせることができます。
Visual StudioのAutomatic Versionsエクステンションは、シンプルなユーザーインターフェースで.Net Coreと.Net Standardの自動インクリメントをサポートするようになりました。
https://marketplace.visualstudio.com/items?itemName=PrecisionInfinity.AutomaticVersions
GITの設定に基づいて、.Net Core/.Netプロジェクトのバージョン管理を可能にするために、GITのtags/describe機能を使用します。
プロジェクトのルートフォルダにあり、csprojファイルに含まれているPrebuild.targets.xmlファイルを使用しています。
<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)
代わりに
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/ja-jp/dotnet/core/tools/dotnet-publish?tabs=netcore21
--version-suffix <VERSION_SUFFIX> Defines the value for the $(VersionSuffix) property in the project.