2008-09-30 10 views
5

Hay un script MSBuild, que incluye número si proyectos Delphi y C#, pruebas unitarias, etc.MSBuild: ¿Cómo obtener el número de advertencias planteadas?

El problema es: cómo marcar la compilación falló si se generaron advertencias (para propósitos de prueba, no para compilaciones de versiones). Usar LogError en lugar de LogWarning en tareas personalizadas no parece ser una buena opción, ya que la compilación debería probar tanto como sea posible (hasta un error real) para informar tantas advertencias como sea posible en un tiempo (el proyecto de compilación se usa en CruiseControl.NET)

Puede ser, la solución es crear mi propio registrador que almacenaría el indicador de advertencias dentro, pero no puedo encontrar si hay una manera de leer este indicador al final de compilación?

P.S. No hay problema en dejar de construir inmediatamente después de recibir una advertencia (la tarea personalizada procesa la salida del compilador Delphi y/warnaserror se puede usar para C#), pero el comportamiento deseado es "compilar todo, recopilar todas las advertencias; para informar sobre todas las advertencias, no solo sobre la primera.

P.P.S. Por lo que realmente no necesito un número de advertencias, sino solo una bandera de su presencia, decidí simplificar el mecanismo de señalización, y usar Mutex trivial en lugar de memoria compartida. Es el código de abajo:

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++; 
     } 
    } 
} 

Respuesta

7

yo sepa ha MSBuild sin soporte incorporado para recuperar el conteo de advertencia en un punto dado del script de compilación. Sin embargo, puede seguir estos pasos para lograr este objetivo:

  1. Crear un registrador personalizado que detecta el evento de advertencia y cuenta el número de advertencias
  2. Crear una tarea personalizada que expone un [Salida] WARNINGCOUNT propiedad
  3. la tarea personalizada consigue de alguna manera el valor de la cuenta advertencia del registrador de encargo

el paso más difícil es el paso 3. Para ello existen varias opciones y se les puede buscar libremente bajo IPC - Inter Comunicación de procesos. Sigue un ejemplo práctico de cómo puedes lograr esto. Cada elemento es una biblioteca de clases diferente.

SharedMemory

http://weblogs.asp.net/rosherove/archive/2003/05/01/6295.aspx

He creado un contenedor para llamado memoria compartida que era parte de un proyecto más amplio . Básicamente permite tipos serializados y gráficos de objetos a almacenarse y recuperarse de la memoria compartida (incluido el proceso cruzado que se esperaba).Si el proyecto más grande alguna vez se completa es otro asunto ;-).

SampleLogger

implementa el registrador personalizado que realiza un seguimiento del recuento de advertencia.

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 la tarea personalizada que lee el número de advertencias planteadas en el proyecto MSBUILD. La tarea personalizada se lee desde la memoria compartida escrita por el registrador personalizado implementado en la biblioteca de clases 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; 
     } 
    } 
} 

Dando 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> 

Si ejecuta el siguiente comando:

c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MSBuild test.xml /logger:SampleLogger.dll 

Ésta será la salida:

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 
+0

Intenté usar casi lo mismo, pero utilicé el miembro estático en la subclase Tarea para recopilar el recuento de advertencias (y no funcionó). Gracias por la idea sobre la memoria compartida. – Abelevich

1

El compilador de C# (csc.exe) tiene un interruptor de encendido/warnaserror se tratará a los avisos como errores y fallar la construcción. Esto también está disponible como una configuración en el archivo .csproj. Supongo que Delphi tiene una habilidad similar.

+0

Lo sentimos, pero la tarea es recoger todas las advertencias (o, al menos, tan tanto como sea posible, hasta un error real), y marque la compilación como fallida después de eso. No es conveniente esperar la compilación de CruiseControl; recibir mensaje sobre la primera advertencia; arregla el problema y espera el siguiente. – Abelevich

+0

Para quién quiere saber de todos modos: Delphi 2009 tiene un tratamiento todas las advertencias como errores –

+0

Lo sentimos, no nos dimos cuenta CC.NET se da por vencido después del primer error. –

1
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 construcción exitosa de '~% nx1'. >>% MrB-BUILDLOG% ) )

+0

No es una solución en msbuild, pero una solución provisional –

Cuestiones relacionadas