MSBuild:発生した警告の数を取得する方法は?
-
02-07-2019 - |
質問
DelphiおよびC#プロジェクト、ユニットテストなどの場合、番号を含むMSBuildスクリプトがあります
問題は、警告が発生した場合にビルドを失敗としてマークする方法です(リリースビルドではなく、テスト目的)。カスタムタスクでLogWarningの代わりにLogErrorを使用するのは適切なオプションではないようです。なぜなら、ビルドはできる限り多くのテストを行い(実際のエラーになるまで)、できるだけ多くの警告を一度に報告する必要があるためです(ビルドプロジェクトはCruiseControl.NETで使用しています) )。
おそらく、解決策は警告フラグを内部に保存する独自のロガーを作成することですが、ビルドの最後にこのフラグを読み取る方法があるかどうかわかりませんか?
PS警告を受け取った直後にビルドを失敗させる問題はありません(Delphiコンパイラの出力はカスタムタスクによって処理され、/ warnaserrorはC#に使用できます)が、望ましい動作は" build all;すべての警告を収集します。ビルドに失敗します"最初の警告だけでなく、すべての警告について報告する。
P.P.S。本当に多くの警告を必要とせず、それらの存在のフラグだけが必要な限り、シグナリングメカニズムを簡素化し、共有メモリの代わりに些細なMutexを使用することにしました。コードは次のとおりです。
using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using System.Threading;
namespace Intrahealth.Build.WarningLogger
{
public sealed class WarningLoggerCheck : Task
{
public override bool Execute()
{
Log.LogMessage("WarningLoggerCheck:" + mutexName + "...");
result = false;
Mutex m = null;
try
{
m = Mutex.OpenExisting(mutexName);
}
catch (WaitHandleCannotBeOpenedException)
{
result = true;
}
catch (Exception)
{
}
if (result)
Log.LogMessage("WarningLoggerCheck PASSED");
else
Log.LogError("Build log contains warnings. Build is FAILED");
return result;
}
private bool result = true;
[Output]
public bool Result
{
get { return result; }
}
private string mutexName = "WarningLoggerMutex";
public string MutexName
{
get { return mutexName; }
set { mutexName = value ?? "WarningLoggerMutex"; }
}
}
public class WarningLogger : Logger
{
internal static int warningsCount = 0;
private string mutexName = String.Empty;
private Mutex mutex = null;
public override void Initialize(IEventSource eventSource)
{
eventSource.WarningRaised += new BuildWarningEventHandler(eventSource_WarningRaised);
}
private void SetMutex()
{
if (mutexName == String.Empty)
{
mutexName = "WarningLoggerMutex";
if (this.Parameters != null && this.Parameters != String.Empty)
{
mutexName = this.Parameters;
}
}
mutex = new Mutex(false, mutexName);
}
void eventSource_WarningRaised(object sender, BuildWarningEventArgs e)
{
if (e.Message != null && e.Message.Contains("MSB3146"))
return;
if (e.Code != null && e.Code.Equals("MSB3146"))
return;
if (warningsCount == 0)
SetMutex();
warningsCount++;
}
}
}
解決
AFAIK MSBuildには、ビルドスクリプトの特定のポイントで警告カウントを取得する組み込みサポートがありません。ただし、次の手順に従ってこの目標を達成できます。
- 警告イベントをリッスンし、警告の数をカウントするカスタムロガーを作成します
- [Output] WarningCountプロパティを公開するカスタムタスクを作成します
- カスタムタスクは、カスタムロガーから警告カウントの値を何らかの方法で取得します
最も難しいステップはステップ3です。これにはいくつかのオプションがあり、IPC-Inter Process Comunicationで自由に検索できます。これを実現する方法の実例を示します。各アイテムは異なるクラスライブラリです。
SharedMemory
http://weblogs.asp.net/rosherove/ archive / 2003/05/01 / 6295.aspx
名前付きのラッパーを作成しました の一部であった共有メモリ より大きなプロジェクト。基本的に シリアル化されたタイプとオブジェクトグラフ 共有され、そこから取得される メモリ(予想通りのものを含む クロスプロセス)。大きいかどうか これまでに完了したプロジェクトは別です 問題;-)。
SampleLogger
警告カウントを追跡するカスタムロガーを実装します。
namespace SampleLogger
{
using System;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;
using DM.SharedMemory;
public class MySimpleLogger : Logger
{
private Segment s;
private int warningCount;
public override void Initialize(IEventSource eventSource)
{
eventSource.WarningRaised += new BuildWarningEventHandler(eventSource_WarningRaised);
this.s = new Segment("MSBuildMetadata", SharedMemoryCreationFlag.Create, 65535);
this.s.SetData(this.warningCount.ToString());
}
void eventSource_WarningRaised(object sender, BuildWarningEventArgs e)
{
this.warningCount++;
this.s.SetData(this.warningCount.ToString());
}
public override void Shutdown()
{
this.s.Dispose();
base.Shutdown();
}
}
}
SampleTasks
MSbuildプロジェクトで発生した警告の数を読み取るカスタムタスクを実装します。カスタムタスクは、クラスライブラリ SampleLogger に実装されたカスタムロガーによって書き込まれた共有メモリから読み取ります。
namespace SampleTasks
{
using System;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;
using DM.SharedMemory;
public class BuildMetadata : Task
{
public int warningCount;
[Output]
public int WarningCount
{
get
{
Segment s = new Segment("MSBuildMetadata", SharedMemoryCreationFlag.Attach, 0);
int warningCount = Int32.Parse(s.GetData() as string);
return warningCount;
}
}
public override bool Execute()
{
return true;
}
}
}
スピンに行きます。
<?xml version="1.0" encoding="UTF-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Main">
<UsingTask TaskName="BuildMetadata" AssemblyFile="F:\temp\SampleLogger\bin\debug\SampleTasks.dll" />
<Target Name="Main">
<Warning Text="Sample warning #1" />
<Warning Text="Sample warning #2" />
<BuildMetadata>
<Output
TaskParameter="WarningCount"
PropertyName="WarningCount" />
</BuildMetadata>
<Error Text="A total of $(WarningCount) warning(s) were raised." Condition="$(WarningCount) > 0" />
</Target>
</Project>
次のコマンドを実行した場合:
c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MSBuild test.xml /logger:SampleLogger.dll
これは出力になります:
Microsoft (R) Build Engine Version 2.0.50727.3053
[Microsoft .NET Framework, Version 2.0.50727.3053]
Copyright (C) Microsoft Corporation 2005. All rights reserved.
Build started 30-09-2008 13:04:39.
__________________________________________________
Project "F:\temp\SampleLogger\bin\debug\test.xml" (default targets):
Target Main:
F:\temp\SampleLogger\bin\debug\test.xml : warning : Sample warning #1
F:\temp\SampleLogger\bin\debug\test.xml : warning : Sample warning #2
F:\temp\SampleLogger\bin\debug\test.xml(15,3): error : A total of 2 warning(s) were raised.
Done building target "Main" in project "test.xml" -- FAILED.
Done building project "test.xml" -- FAILED.
Build FAILED.
F:\temp\SampleLogger\bin\debug\test.xml : warning : Sample warning #1
F:\temp\SampleLogger\bin\debug\test.xml : warning : Sample warning #2
F:\temp\SampleLogger\bin\debug\test.xml(15,3): error : A total of 2 warning(s) were raised.
2 Warning(s)
1 Error(s)
Time Elapsed 00:00:00.01
他のヒント
C#コンパイラ(csc.exe)には/ warnaserrorスイッチがあり、警告をエラーとして扱い、ビルドに失敗します。これは、.csprojファイルの設定としても利用できます。 Delphiにも同様の機能があると思います。
msbuild.exe %~nx1 /t:Rebuild /p:Configuration=Release >> %MrB-BUILDLOG%
findstr /r /c:"[1-9][0-9]* Error(s)" >> %MrB-BUILDLOG%
if not errorlevel 1 (
echo ERROR: sending notification email for build errors in '%~nx1'. >> %MrB-BUILDLOG%
) else (
findstr /r /c:"[1-9][0-9]* Warning(s)" >> %MrB-BUILDLOG%
if not errorlevel 1 (
echo ERROR: sending notification email for build warnings in '%~nx1'. >>
%MrB-BUILDLOG% )else( echo '%〜nx1'の正常なビルド。 &gt;&gt; %MrB-BUILDLOG% ) )