2012-05-29 5 views
12

sto facendo funzionare il compito MSBuild con ContinueOnError = true:Come verificare se un MSBuild-Task non riesce se si utilizza ContinueOnError = true

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

Quindi la mia generazione riesce sempre.

C'è un modo per scoprire se si verifica un errore?

non ho trovato alcun uscita del compito MSBuild contenente queste informazioni. L'unico modo che conosco è analizzare il file di log per gli errori, ma sembra una soluzione alternativa per me.

(sto usando MSBuild 4,0)


Questa è una risposta all'ultima valutazioni di @Ilya.
Uso feedback/risposta a causa della lunghezza e delle restrizioni di formattazione dei commenti.

log è ambito di obiettivi individuali o per essere più specifici compiti ...

Questa è stata infatti la prima questione è stata sollevata quando stavo leggendo il tuo commento con il suggerimento di utilizzare Log.HasLoggedErrors: "Era lo scopo del registro? ".
Purtroppo non ero in grado di trovare una documentazione adeguata. MSND non aiuta molto ...
Perché lo sapevate che è ambito per l'attività?
Non ho alcun dubbio sulla tua affermazione! Mi chiedo solo se c'è una documentazione adeguata da qualche parte .. (non sono stato utilizzando MSBuild per anni ;-)

In ogni caso, quello che stai costruendo come progetto ?

I miei progetti di test sono molto semplici.
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> 

Il CopyNotExistingFile.proj cerca solo di copiare un file che non esiste:

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

E questo è il mio compito personalizzato 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; 
     } 
    } 
} 

Se si crea il mio MyTest.proj il HasLoggedErrors verrà impostato su false sebbene sia stato registrato un errore (MSB3021) (?) Per il logger console:

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. 

La mia aspettativa è stata HasLoggedErrors verrebbe impostato su true.



un modo è quello di costruire auto, ma con target diverso, per esempio il vostro DefaultTargets una lancia il vostro compito personalizzato MSBuildWrapper punta a se stesso (cioè $ (MSBuildProjectFile)), ma con un target diverso che altre build, copie

L'ho già provato (erano le mie indagini che intendevo nel mio post). Purtroppo non funziona nemmeno :-(
(mi rendo conto che hai detto in teoria) Il mio nuovo singolo progetto assomiglia a questo:.

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

Se io costruisco questo progetto HasLoggedErrors sarà ancora essere impostato su false.
(Inoltre, la mia generazione "vero" attualmente sto mantenendo molto complexer contenente diversi file di progetto con gli obiettivi ... quindi non tutti in grado di confezionare in un unico file di progetto).

o scrivendo logger personalizzato e passando attraverso la linea di comando

Quella è stata la mia ultima speranza!
La mia build "reale" ha un logger personalizzato passato attraverso la riga di comando (non l'ho usato per il mio progetto di test per semplicità). Questo è in realtà la produzione del log (un file XML) che sto per analizzare per scoprire se sono stati registrati errori.
BTW, pensavo che il logger della console fosse una specie di registratore "globale". Mi sbaglio?

Ad ogni modo, il registratore personalizzato non è d'aiuto, lo Log.HasLoggedErrors è ancora impostato su false.
C'è un modo in cui non sono a conoscenza di fare riferimento a un particolare registratore (ad esempio il mio registratore personalizzato) per chiedere se ha registrato errori?

Sembra davvero che Log abbia un ambito per i singoli target.

Hmm ... se il riflesso sull'istanza del buildengine è l'ultima risorsa, preferirei comunque analizzare il registro.
(Non prendetevela con me :-)!)


La mia decisione
Dopo alcune indagini ho deciso di restare con la mia soluzione iniziale: analizzare il registro per scoprire se la generazione non è riuscita .

Controlla i miei commenti per capire perché preferisco che i suggerimenti siano stati forniti finora.

Se qualcuno ha altre idee non esitano a condividere :-)

(In caso contrario, questa domanda può essere chiuso, immagino ...)

risposta

19

il MSBuildLastTaskResultreserved property sarà impostato True se l'ultima operazione è riuscita e False se l'ultima operazione riuscita:

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

credo che questo è stato introdotto con MSBuild v4.0.

+0

+1 per il suggerimento su una nuova proprietà riservata che ancora manca sul sito MSDN! Non ne ero consapevole. Questa è la soluzione che stavo cercando, grazie! – Elena

+0

Se si esamina la parte inferiore della pagina Proprietà riservate MSDN, si vedrà che qualcuno della comunità ha documentato gentilmente diverse proprietà mancanti. Sconcertante che la documentazione ufficiale non sia mai stata aggiornata. –

+0

Sì, ho letto questo commento proprio oggi e ho anche l'ultima edizione del libro di Sayed Ibrahim Hashimi sul mio tavolo ;-) ma non ero a conoscenza di questa proprietà, grazie ancora! – Elena

0

Si potrebbe catturare TargetOutputs e verificare la presenza di condizioni di errore in seguito, ma è ancora abbastanza hackerato.

+0

Hmm ... se non c'è modo migliore sarà meglio creare un'attività personalizzata analizzando il mio file di registro e contando gli errori (e gli avvisi). Rende il mio file di progetto più chiaro .. @skolima grazie comunque per la risposta rapida! – Elena

+4

Non è necessario analizzare il log, ereditare semplicemente da Microsoft.Build.Tasks.MSBuild ed esporre un output che restituisce Log.HasLoggedErrors –

+0

Una buona idea, grazie a @IlyaKozhevnikov! – Elena

0

Se si desidera verificare se l'attività MSBuild non è riuscita, utilizzare l'attività Exec. Impostare IgnoreExitCode su true e verificare il valore di output ExitCode. Se non è zero, qualcosa non va.

Se è necessario l'elenco degli errori di compilazione, utilizzare /fileloggerparameters command line switch per registrare gli errori solo per alcuni file specifico:

/flp1:logfile=errors.txt;errorsonly

+0

Voglio solo controllare se l'attività 'MSBuild' non è riuscita, ma non voglio usare l'attività' Exec' invece del task 'MSBuild' perché dei vantaggi dell'ultimo – Elena

0

Ma se un altro compito all'interno di alcuni target (ad esempio Copytask) ha generato un errore il Log.HasLoggedErrors restituisce false.

non sapeva commenti hanno limiti di lunghezza ...

log è ambito di obiettivi individuali o per essere più specifici compiti, e (per quanto io sappia) non c'è modo per ottenere uno "globale", può essere attraverso la riflessione sull'istanza di buildengine, o scrivere logger personalizzato e passarlo attraverso la riga di comando. In ogni caso, cosa stai costruendo come progetto? HasLoggedErrors funziona come previsto (e ha funzionato invariato per anni), mostra se il progetto in costruzione ha registrato errori. Non ha e non dovrebbe avere alcun controllo sulla registrazione di altre attività (che potrebbero utilizzare altri tipi di logger). Se si desidera uno globale, un modo è quello di costruire sé stessi ma con target diversi, ad esempio DefaultTargets, si avvia l'attività MSBuildWrapper personalizzata che punta a se stessa (cioè $ (MSBuildProjectFile)) ma con un target diverso che crea altre build, copie, ecc, in teoria dovrebbe simulare un HasLoggedErrors globali ...

+0

Ammetto che dovrei descrivere le mie "indagini" in dettaglio. L'ho appena fatto, vedere la mia risposta. Comunque, apprezzo molto i tuoi suggerimenti e "volontà" di aiutare! :-) – Elena

3

So che questa discussione è un po 'vecchio, ma un'altra soluzione possibile, come presumo avevi bisogno di sapere che generazione non riuscita per eseguire qualche "operazione finale", è quello di utilizzare:

<OnError ExecuteTargets="FinalReportTarget;CleanupTarget" /> 

Quello fallirebbe la compilazione in caso di errore, ma eseguirà "FinalReportTarget" e "CleanupTarget".

ContinueOnError = "true" non è necessario in questo caso.

+1

Aleksey, grazie per il tuo suggerimento ma il punto è che voglio usare "ContinueOnError =" true "". Ho diversi compiti di MSBuild nel mio progetto e voglio eseguirli tutti, non importa se alcuni di essi falliscono. Ma alla fine voglio essere in grado di controllare se alcuni di loro hanno fallito. Usando il tuo approccio la compilazione terminerà immediatamente quando una delle attività fallisce. – Elena

+0

Questa potrebbe non essere la soluzione più elegante, ma è possibile associare OnError a ogni tag separato in cui si prevede che l'errore si verifichi. Inoltre potresti avere qualche task PrintError, qualcosa di simile a , dove in PrintError verificherai MSBuildLastTaskResult. –