MSBuild: come ottenere il numero di avvisi generati?
-
02-07-2019 - |
Domanda
Esiste uno script MSBuild, che include il numero se progetti Delphi e C #, unit test ecc.
Il problema è: come contrassegnare la build non riuscita se sono stati generati avvisi (a scopo di test, non per build di rilascio)? L'uso di LogError invece di LogWarning in attività personalizzate sembra non essere una buona opzione, perché la build dovrebbe testare quanto più è in grado (fino a quando non si verifica un errore reale) di segnalare il maggior numero possibile di avvisi in un momento (il progetto di build sta utilizzando in CruiseControl.NET ).
Forse, la soluzione è quella di creare il mio logger che memorizzi il flag degli avvisi all'interno, ma non riesco a trovare se c'è un modo per leggere questo flag al termine della compilazione?
P.S. Non c'è alcun problema a fallire la compilazione immediatamente dopo aver ricevuto un avviso (l'output del compilatore Delphi viene elaborato dall'attività personalizzata e / warnaserror potrebbe essere usato per C #), ma il comportamento desiderato è "build everything; raccogliere tutti gli avvisi; fallire la compilazione " per riferire su tutti gli avvertimenti, non solo sul primo.
P.P.S. Per quanto non mi serva davvero un numero di avvertimenti, ma solo la bandiera della loro presenza, ho deciso di semplificare il meccanismo di segnalazione e usare un banale Mutex invece della memoria condivisa. Il codice è sotto:
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++;
}
}
}
Soluzione
AFAIK MSBuild non ha supporto integrato per recuperare il conteggio degli avvisi in un determinato punto dello script di compilazione. Puoi comunque seguire questi passaggi per raggiungere questo obiettivo:
- Crea un logger personalizzato che ascolta l'evento di avviso e conta il numero di avvisi
- Crea un'attività personalizzata che espone una proprietà [Output] WarningCount
- L'attività personalizzata ottiene in qualche modo il valore del conteggio degli avvisi dal logger personalizzato
Il passaggio più difficile è il passaggio 3. Per questo ci sono diverse opzioni e puoi cercarle liberamente in IPC - Inter Process Comunication. Segue un esempio funzionante di come è possibile raggiungere questo obiettivo. Ogni elemento è una Libreria di classi diversa
SharedMemory
http://weblogs.asp.net/rosherove/ archive / 2003/05/01 / 6295.aspx
Ho creato un wrapper per il nome memoria condivisa che faceva parte di a progetto più ampio. Fondamentalmente lo consente tipi serializzati e grafici di oggetti a essere archiviato e recuperato da condiviso memoria (incluso come ti aspetteresti processo incrociato). Sia il più grande il progetto che viene mai completato è un altro importa ;-).
SampleLogger
Implementa il logger personalizzato che tiene traccia del conteggio degli avvisi.
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
Implementa l'attività personalizzata che legge il numero di avvisi generati nel progetto MSbuild. L'attività personalizzata legge dalla memoria condivisa scritta dal logger personalizzato implementato nella libreria di classi 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;
}
}
}
Fare un giro.
<?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>
Se si esegue il comando seguente:
c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MSBuild test.xml /logger:SampleLogger.dll
Questo sarà l'output:
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
Altri suggerimenti
Il compilatore C # (csc.exe) ha un'opzione / warnaserror tratterà gli avvisi come errori e fallirà la compilazione. Questo è disponibile anche come impostazione nel file .csproj. Presumo che Delphi abbia un'abilità simile.
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% ) altro ( echo Creazione riuscita di '% ~ nx1'. & Gt; > % MrB-BUILDLOG% ) )