2012-05-29 7 views
12

ich mit ContinueOnError = true die MSBuild Aufgabe leite:Wie kann man überprüfen, ob eine MSBuild-Aufgabe schlägt fehl, wenn mit ContinueOnError = true

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

Also meine Build gelingt es immer wieder.

Gibt es eine Möglichkeit herauszufinden, ob ein Fehler auftritt?

Ich konnte keinen Output der MSBuild Aufgabe mit diesen Informationen finden. Die einzige Möglichkeit, die ich weiß, ist die Protokolldatei für Fehler zu analysieren, aber es sieht wie eine Umgehung für mich aus.

(Ich bin mit MSBuild 4,0)


Dies ist eine Antwort auf das letzte Feedback von @Ilya.
Ich verwende Feedback/Antwort wegen der Länge und Formatierungseinschränkungen der Kommentare.

Log auf individuelle Ziele scoped oder mehrere spezifische Aufgaben zu sein ...

Dies war in der Tat die erste Frage stellt sich, als ich Ihren Kommentar mit dem Vorschlag zu lesen Log.HasLoggedErrors zu verwenden: "Was ist der Umfang des Logs? ".
Leider konnte ich keine richtige Dokumentation finden. MSND hilft nicht viel ...
Warum wussten Sie, dass es auf die Aufgabe beschränkt ist?
Ich zweifle nicht an Ihrer Aussage überhaupt! Ich frage mich nur, wenn es eine richtige Dokumentation irgendwo .. (ich habe nicht MSBuild seit Jahren ;-)

In jedem Fall gewesen verwenden, was Sie als Projekt Bau ?

Meine Testprojekte sind sehr einfach.
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> 

Die CopyNotExistingFile.proj versucht, nur eine Datei zu kopieren, das nicht existiert:

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

Und das ist meine benutzerdefinierte Aufgabe 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; 
     } 
    } 
} 

Wenn ich MyTest.proj erstelle, wird HasLoggedErrors auf false gesetzt, obwohl ein Fehler (MSB3021) protokolliert wurde (?) An die Konsole Logger:

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. 

Meine Erwartung wurde HasLoggedErrors würde true eingestellt werden.



ein Weg ist, mich selbst zu bauen, aber mit unterschiedlichem Ziel, zum Beispiel Ihrer Default ein startet Ihre benutzerdefinierte MSBuildWrapper Aufgabe selbst zeigt (dh $ (MSBuildProjectFile)), aber mit einem anderen Ziel, dass macht andere Builds, Kopien

Ich habe es bereits versucht (das waren meine Untersuchungen, die ich in meinem Post meinte). Leider ist es nicht funktionieren :-(
(Ich bin mir bewusst gesagt, du in Theorie) Mein neues einzigen Projekt sieht wie folgt aus:.

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

Wenn ich dieses Projekt HasLoggedErrors bauen nach wie vor eingestellt werden, um false.
(Des Weiteren meine „echte“ Build ich zur Zeit beibehalten viel komplexeren mehrere Projektdateien mit Zielen enthalten ... so kann ich sie nicht packen alle in einem einzigen Projekt-Datei).

oder benutzerdefinierte Logger zu schreiben und es durch Zeilenbefehl vorbei

Das ist meine letzte Hoffnung war!
Meine "echte" Build hat eine benutzerdefinierte Logger über die Befehlszeile (ich habe es nicht für meine Test-Projekt der Einfachheit halber verwendet). Das erzeugt tatsächlich das Protokoll (eine XML-Datei), die ich analysieren werde, um herauszufinden, ob irgendwelche Fehler protokolliert wurden.
BTW, ich dachte der Konsolenlogger ist eine Art "globaler" Logger. Bin ich falsch?

Wie auch immer, der benutzerdefinierte Logger hilft auch nicht, der Log.HasLoggedErrors ist immer noch auf false eingestellt.
Gibt es eine Möglichkeit, dass ich nicht auf einen bestimmten Logger (z. B. meine benutzerdefinierte Logger) zu fragen, um zu fragen, ob es irgendwelche Fehler protokolliert hat?

Es sieht wirklich so aus Log ist auf einzelne Ziele beschränkt.

Hmm ... wenn die Reflexion über die Gebäude-Instanz der letzte Ausweg ist, würde ich immer noch lieber das Protokoll analysieren.
(Do not blame me :-)!)


Meine Entscheidung
Nach einigen Untersuchungen habe ich beschlossen, mit meiner ersten Lösung zu bleiben: analysieren Sie das Protokoll, um herauszufinden, ob die Build fehlgeschlagen .

Überprüfen Sie meine Kommentare, um zu sehen, warum ich es vorziehe, dass die Vorschläge bisher bereitgestellt wurden.

Wenn jemand hat einige andere Ideen, zögern Sie nicht :-) zu teilen

(Ansonsten kann diese Frage geschlossen werden, nehme ich an ...)

Antwort

19

das MSBuildLastTaskResultreserved property wird True gesetzt werden, wenn die letzte Aufgabe und False gelungen, wenn die letzte Aufgabe ist fehlgeschlagen:

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

ich glaube, das wurde mit MSBuild v4.0 eingeführt.

+0

+1 für den Hinweis auf eine neue reservierte Eigenschaft, die auf der MSDN-Site noch fehlt! Ich war mir dessen nicht bewusst. Das ist die Lösung, nach der ich gesucht habe, danke! – Elena

+0

Wenn Sie unten auf der Seite mit den reservierten MSDN-Eigenschaften nachsehen, sehen Sie, dass jemand aus der Community einige fehlende Eigenschaften freundlicherweise dokumentiert hat. Rätselhaft, dass die offizielle Dokumentation noch nie aktualisiert wurde. –

+0

Ja, ich habe diesen Kommentar gerade heute gelesen und ich habe sogar die letzte Ausgabe des Buches von Sayed Ibrahim Hashimi auf meinem Tisch ;-) aber ich war mir dieser Eigenschaft nicht bewusst, thx wieder! – Elena

0

Sie TargetOutputs erfassen könnte und prüfen sie auf Fehlerbedingungen danach, aber das ist immer noch ziemlich hackish.

+0

Hmm ... wenn es keinen besseren Weg gibt, werde ich besser eine benutzerdefinierte Aufgabe erstellen, die meine Protokolldatei analysiert und die Fehler (und Warnungen) zählt. Macht meine Projektdatei klarer .. @skolima danke trotzdem für die schnelle Antwort! – Elena

+4

Keine Notwendigkeit, das Protokoll zu analysieren, nur von Microsoft.Build.Tasks.MSBuild erben und eine Ausgabe, die Log.HasLoggedErrors –

+0

zurückgibt, dass eine großartige Idee, danke @IlyaKozhevnikov! – Elena

0

Wenn Sie nur überprüfen möchten, ob die MSBuild-Aufgabe fehlgeschlagen ist, verwenden Sie Exec Aufgabe. Setzen Sie IgnoreExitCode auf true und überprüfen Sie den Ausgabewert von ExitCode. Wenn nicht Null, stimmt etwas nicht.

Wenn Sie die Liste der Buildfehler müssen, verwenden Sie /fileloggerparameters command line switch Fehler bis zu einem gewissen bestimmten Datei nur zu protokollieren:

/flp1:logfile=errors.txt;errorsonly

+0

Ich möchte nur überprüfen, ob die 'MSBuild' Task fehlgeschlagen ist, aber ich möchte' Exec' Task statt der 'MSBuild' Task verwenden, weil der Vorteile des letzten. – Elena

0

Aber wenn eine andere Aufgabe in einige target (zB Copytask) hat einen Fehler ausgelöst Log.HasLoggedErrors gibt false zurück.

nicht Kannten Kommentare Längenbegrenzungen haben ...

Log auf einzelne Ziele scoped oder speziellere Aufgaben zu sein, und (soweit mir bekannt) gibt es keine Möglichkeit um eine "globale" zu erhalten, kann es durch eine Reflektion der Build-Engine-Instanz geschehen, oder durch Schreiben einer benutzerdefinierten Log-Datei und durch Übergeben einer Befehlszeile. Was bauest du auf jeden Fall als Projekt? HasLoggedErrors funktioniert wie erwartet (und hat seit Jahren unverändert funktioniert), es zeigt an, wenn das zu erstellende Projekt Fehler protokolliert hat. Es hat keine Kontrolle über die Protokollierung anderer Aufgaben (die möglicherweise andere Arten von Protokollierern verwenden). Wenn Sie eine globale Methode verwenden möchten, besteht die Möglichkeit, sich selbst zu erstellen, aber mit anderen Zielen, zum Beispiel Ihre DefaultTargets, startet Ihre benutzerdefinierte MSBuildWrapper-Task auf sich selbst (zB $ (MSBuildProjectFile)), aber mit einem anderen Ziel, das andere Builds, Kopien, etc, in Theorie es eine globale HasLoggedErrors simulieren soll ...

+0

Ich gebe zu, ich sollte meine "Untersuchungen" im Detail beschreiben. Ich habe es gerade getan, siehe meine Antwort. Wie auch immer, ich schätze wirklich Ihre Vorschläge und "will" helfen! :-) – Elena

3

Ich weiß, dieser Thread ist ein bisschen alt, aber eine andere mögliche Lösung, wie ich nehme an, Sie benötigt, um diese zu bauen, um gescheitert zu wissen, einige „letzte Aufgabe“ auszuführen, zu verwenden ist:

<OnError ExecuteTargets="FinalReportTarget;CleanupTarget" /> 

That würde den Build im Falle eines Fehlers fehlschlagen, aber führe "FinalReportTarget" und "CleanupTarget" aus.

ContinueOnError = "Wahr" wird in diesem Fall nicht benötigt.

+1

Aleksey, danke für deinen Vorschlag, aber der Punkt ist, dass ich "ContinueOnError =" true "" verwenden möchte. Ich habe mehrere MSBuild-Aufgaben in meinem Projekt, und ich möchte sie alle ausführen, egal ob einige von ihnen fehlschlagen. Aber am Ende möchte ich prüfen können, ob einige von ihnen versagt haben. Mit Ihrem Ansatz wird der Build sofort beendet, wenn eine der Aufgaben fehlschlägt. – Elena

+0

Dies ist möglicherweise nicht die eleganteste Lösung, aber Sie könnten OnError in jedem einzelnen Tag verketten, in dem Sie erwarten, dass der Fehler dann auftritt. Außerdem könnten Sie eine gemeinsame PrintError-Aufgabe haben, etwa , wo Sie in PrintError MSBuildLastTaskResult überprüfen würden. –