2012-05-29 16 views
12

Me postulo la tareaMSBuild con ContinueOnError = true:¿Cómo comprobar si un MSBuild-tarea falla si se utiliza ContinueOnError = true

<MSBuild Projects="@(ComponentToDeploy)" 
    Targets="$(DeploymentTargets)" 
    Properties="$(CommonProperties);%(AdditionalProperties)" 
    ContinueOnError="true" 
    Condition="%(Condition)"/> 

Así que mi construcción siempre tiene éxito.

¿Hay alguna manera de averiguar si ocurre algún error?

no pude encontrar ninguna salida del MSBuild tarea que contiene esta información. La única forma que conozco es analizar el archivo de registro en busca de errores, pero parece una solución para mí.

(estoy utilizando MSBuild 4,0)


Esta es una respuesta a la última votaciones de @Ilya.
Estoy usando comentarios/respuestas debido a la longitud y las restricciones de formato de los comentarios.

Log está en el ámbito de objetivos individuales o para ser más específicos ... tareas

Este fue de hecho la primera pregunta surgió cuando estaba leyendo su comentario con la sugerencia de utilizar Log.HasLoggedErrors: "¿Fue el alcance del Log? ".
Desafortunadamente, no pude encontrar la documentación adecuada. MSND no ayuda mucho ...
¿Por qué sabía que tiene alcance para la tarea?
¡No tengo ninguna duda sobre su declaración! Me pregunto si hay una documentación adecuada en algún lugar .. (no he estado utilizando MSBuild durante años ;-)

En cualquier caso, lo que se construyen como proyecto ?

Mis proyectos de prueba son muy simples.
MyTest.project

<?xml version="1.0" encoding="utf-8" ?> 
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="ElenasTarget" ToolsVersion="4.0"> 

    <UsingTask AssemblyFile="$(MSBuildProjectDirectory)\MyCompany.Tools.MSBuild.Tasks.dll" TaskName="MSBuildWithHasLoggedErrors" /> 

    <ItemGroup> 
     <MyProjects Include="CopyNotExistingFile.proj" /> 
    </ItemGroup> 

    <Target Name="ElenasTarget"> 
     <MSBuildWithHasLoggedErrors Projects="@(MyProjects)" ContinueOnError="true" > 
      <Output TaskParameter="HasLoggedErrors" PropertyName="BuildFailed" /> 
     </MSBuildWithHasLoggedErrors> 

     <Message Text="BuildFailed=$(BuildFailed)" /> 
    </Target> 
</Project> 

El CopyNotExistingFile.proj simplemente intenta copiar un archivo que no existe:

<?xml version="1.0" encoding="utf-8" ?> 
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Target1" ToolsVersion="4.0"> 
    <Target Name="Target1"> 
     <Copy SourceFiles="C:\lalala.bum" DestinationFiles="C:\tralala.bam" /> 
    </Target> 
</Project> 

Y esta es mi tarea personalizada MSBuildWithHasLoggedErrors

namespace MyCompany.Tools.MSBuild.Tasks 
{ 
    public class MSBuildWithHasLoggedErrors : Microsoft.Build.Tasks.MSBuild 
    { 
     [Output] 
     public bool HasLoggedErrors { get; private set; } 

     public override bool Execute() 
     { 
      try 
      { 
       base.Execute(); 
       HasLoggedErrors = Log.HasLoggedErrors; 
      } 
      catch (Exception e) 
      { 
       Log.LogErrorFromException(e, true); 
       return false; 
      } 

      return true; 
     } 
    } 
} 

Si construyo mi MyTest.proj, el HasLoggedErrors se establecerá en false aunque se registró un error (MSB3021) (?) Al registrador de la consola:

Project "C:\Users\elena\mytest.proj" on node 1 (default targets). 
Project "C:\Users\elena\mytest.proj" (1) is building "C:\Users\elena\CopyNotExistingFile.proj" (2) on node 1 (default targets). 
Target1: 
    Copying file from "C:\lalala.bum" to "C:\tralala.bam". 
C:\Users\elena\CopyNotExistingFile.proj(5,4): error MSB3021: Unable to copy file "C:\lalala.bum" to "C:\tralala.bam". Could not find file 'C:\lalala.bum'. 
Done Building Project "C:\Users\elena\CopyNotExistingFile.proj" (default targets) -- FAILED. 
ElenasTarget: 
    BuildFailed=False 
Done Building Project "C:\Users\elena\mytest.proj" (default targets). 

Build succeeded. 

Mi expectativa era HasLoggedErrors se establecería en true.



una forma es construir uno mismo pero con diferente objetivo, por ejemplo sus DefaultTargets uno lanza su encargo tarea MSBuildWrapper apuntando a sí mismo (es decir, $ (MSBuildProjectFile)), pero con un objetivo diferente que otras construcciones, copias

Ya lo he intentado (esas fueron mis investigaciones que quise decir en mi publicación). Por desgracia, no funciona bien :-(
(Soy consciente de que dicho en teoría) Mi nuevo solo proyecto se parece a esto:.

<?xml version="1.0" encoding="utf-8" ?> 
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="ElenasTarget" ToolsVersion="4.0"> 

    <UsingTask AssemblyFile="$(MSBuildProjectDirectory)\MyCompany.Tools.MSBuild.Tasks.dll" TaskName="MSBuildWithHasLoggedErrors" /> 

    <Target Name="ElenasTarget"> 
     <MSBuildWithHasLoggedErrors Projects="$(MSBuildProjectFile)" Targets="CopyNotExistingFile" ContinueOnError="true" > 
      <Output TaskParameter="HasLoggedErrors" PropertyName="BuildFailed" /> 
     </MSBuildWithHasLoggedErrors> 

     <Message Text="BuildFailed=$(BuildFailed)" /> 
    </Target> 

    <Target Name="CopyNotExistingFile" > 
     <Copy SourceFiles="C:\lalala.bum" DestinationFiles="C:\tralala.bam" /> 
    </Target> 
</Project> 

Si construyo este proyecto HasLoggedErrors seguirá siendo establecerse en false.
(Además, mi compilación "real" que actualmente mantengo es mucho más compleja y contiene varios archivos de proyecto con objetivos ... por lo que no puedo empaquetarlos todos en un solo archivo de proyecto)

o escribir registrador de costumbre y pasándolo a través de línea de comandos

Esa era mi última esperanza!
Mi construcción "real" tiene un registrador personalizado pasado a través de la línea de comandos (no lo usé para mi proyecto de prueba por simplicidad). Eso realmente está produciendo el registro (un archivo XML) que voy a analizar para averiguar si se han registrado errores.
Por cierto, pensé que el registrador de consola es una especie de registrador "global". ¿Estoy equivocado?

De todos modos, el registrador personalizado tampoco ayuda, el Log.HasLoggedErrors todavía está configurado en false.
¿Hay algún modo en el que no estoy consciente de hacer referencia a un registrador en particular (por ejemplo, mi registrador personalizado) para preguntar si ha registrado algún error?

Parece que Log se ha adaptado a objetivos individuales.

Hmm ... si el reflejo en la instancia de buildengine es el último recurso, aún así preferiría analizar el registro.
(no me culpe :-)!)


Mi decisión
Después de algunas investigaciones que he decidido seguir con mi solución inicial: analizar el registro para averiguar si la compilación falló .

Revise mis comentarios para ver por qué prefiero que las sugerencias se hayan proporcionado hasta el momento.

Si alguien tiene algunas otras ideas no dudan en compartir :-)

(De lo contrario, esta pregunta puede ser cerrado, supongo ...)

Respuesta

19

el MSBuildLastTaskResultreserved property se establecerá en True si la última tarea tuvo éxito y False si la última tarea no se pudo:

<MSBuild Projects="@(ComponentToDeploy)" 
     Targets="$(DeploymentTargets)" 
     Properties="$(CommonProperties);%(AdditionalProperties)" 
     ContinueOnError="true" 
     Condition="%(Condition)" /> 
<Message Text="MSBuild failed!" Condition="'$(MSBuildLastTaskResult)' == 'False'" /> 

creo que esto se introdujo con MSBuild v4.0.

+0

+1 por la sugerencia de una nueva propiedad reservada que todavía falta en el sitio de MSDN. Yo no era consciente de ello. Esta es la solución que estaba buscando, ¡gracias! – Elena

+0

Si mira la parte inferior de la página de propiedades reservadas de MSDN, verá que alguien de la comunidad documentó amablemente varias propiedades perdidas. Es desconcertante que la documentación oficial nunca haya sido actualizada. –

+0

Sí, leí este comentario hoy e incluso tengo la última edición del libro de Sayed Ibrahim Hashimi en mi mesa ;-) pero no estaba al tanto de esta propiedad, ¡de nuevo! – Elena

0

Se podría capturar TargetOutputs y comprobar si condiciones de error después, pero eso todavía es bastante hackish.

+0

Hmm ... si no hay una mejor manera, crearé mejor una tarea personalizada para analizar mi archivo de registro y contar los errores (y advertencias). Hace que mi archivo de proyecto se vea más claro .. @skolima gracias de todos modos por la respuesta rápida! – Elena

+4

No es necesario analizar el registro, solo heredar de Microsoft.Build.Tasks.MSBuild y exponer un resultado que devuelve Log.HasLoggedErrors –

+0

¡Esa es una gran idea, gracias @IlyaKozhevnikov! – Elena

0

Si solo desea comprobar si la tarea MSBuild falló, utilice la tarea Exec. Establezca IgnoreExitCode en true y marque el valor de salida de ExitCode. Si no es cero, algo está mal.

Si necesita la lista de errores de generación, utilice /fileloggerparameters command line switch a registrar los errores sólo para algún archivo específico:

/flp1:logfile=errors.txt;errorsonly

+0

Solo quiero comprobar si la tarea 'MSBuild' falló, pero no quiero usar la tarea' Exec' en lugar de la tarea 'MSBuild' porque de las ventajas de la última. – Elena

0

Pero si alguna otra tarea en el interior el objetivo (por ejemplo, Copytask) generó un error, el Log.HasLoggedErrors devuelve falso.

no sabía comentarios tienen límites de longitud ...

Log está en el ámbito de objetivos individuales o para ser tareas más específicas, y (por lo que yo sepa) no hay manera para obtener uno "global", puede ser a través de la reflexión en la instancia buildengine, o escribir registrador personalizado y pasarlo a través de la línea de comandos. En cualquier caso, ¿qué estás construyendo como proyecto? HasLoggedErrors funciona como se esperaba (y ha estado funcionando sin cambios durante años), muestra si el proyecto que se está creando registró algún error. No tiene, ni debe tener, ningún control sobre el registro de otras tareas (que podría usar otros tipos de registradores). Si desea una global, una forma es construir uno mismo pero con un objetivo diferente, por ejemplo, su DefaultTargets uno inicia su tarea personalizada de MSBuildWrapper apuntando a sí misma (es decir, $ (MSBuildProjectFile)) pero con un objetivo diferente que hace otras compilaciones, copias, etc, en teoría debe simular un HasLoggedErrors globales ...

+0

Admito que debería describir mis "investigaciones" en detalles. Acabo de hacerlo, ver mi respuesta. De todos modos, ¡realmente aprecio sus sugerencias y "quiero" ayudar! :-) – Elena

3

Sé que este hilo es un poco viejo, pero otra solución posible, ya que supongo que tenía que saber que la acumulación fallado con el fin de ejecutar alguna "tarea final", es utilizar:

<OnError ExecuteTargets="FinalReportTarget;CleanupTarget" /> 

Eso fallaría la compilación en caso de error, pero ejecutaría "FinalReportTarget" y "CleanupTarget".

ContinueOnError = "true" no es necesario en este caso.

+1

Aleksey, gracias por su sugerencia, pero el punto es que quiero usar "ContinueOnError =" true "". Tengo varias tareas de MSBuild en mi proyecto y quiero ejecutarlas todas, sin importar si algunas fallan. Pero al final quiero poder verificar si algunos de ellos fallaron. Usando su enfoque, la construcción terminará inmediatamente cuando una de las tareas falle. – Elena

+0

Esta podría no ser la solución más elegante, pero podría encadenar OnError en cada etiqueta por separado en la que espera que ocurra el error. Además, podría tener alguna tarea PrintError común, algo así como , donde en PrintError comprobaría MSBuildLastTaskResult. –

Cuestiones relacionadas