2012-05-29 69 views
12

我与ContinueOnError =真运行的MSBuild任务使用ContinueOnError =真:如何检查是否一个的MSBuild任务失败,如果

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

所以我总是构建成功。

有没有办法找出是否有错误发生?

我找不到任何输出MSBuild任务包含此信息。 我知道的唯一方法是解析日志文件中的错误,但它看起来像我的解决方法。

(我用的MSBuild 4.0)


这是一个答案@Ilya最后反馈。
由于评论的长度和格式限制,我使用的是反馈/答案。

日志的作用范围是单个目标或更具体的任务......

这的确是当我读您的意见与建议使用Log.HasLoggedErrors的第一个问题出现了:“是Log的范围?“。
不幸的是,我无法找到合适的文档。 MSND帮助不大......
你为什么知道它的任务范围?
我毫不怀疑你的陈述!我只是想知道,如果有一个适当的文件的地方.. (使用的MSBuild我没有多年;-)

在任何情况下,你作为建设项目?

我的测试项目非常简单。
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> 

CopyNotExistingFile.proj只是试图复制不存在的文件:

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

这是我的自定义任务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; 
     } 
    } 
} 

如果我构建我的MyTest.proj,则HasLoggedErrors将设置为false,但会记录一个错误(MSB3021)(?)在控制台记录:

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. 

我的期望是HasLoggedErrors将被设置为true



一个办法就是建立自我,但有不同的目标,例如您的DefaultTargets一个启动您的自定义MSBuildWrapper任务指向本身(即$(MSBuildProjectFile)),但具有不同的目标是其他版本,副本

我已经试过了(这是我的调查,我的意思是在我的文章中)。遗憾的是它不工作或者:-(
(我知道你在理论上说) 我的新项目看起来是这样的:

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

如果我建这个项目HasLoggedErrors仍然会设置为false
(此外,我目前维护的“真实”版本更复杂,包含多个带目标的项目文件......所以我无法将它们全部打包到单个项目文件中)。

或编写自定义记录器,并使其通过命令行

这是我最后的希望!
我的“真实”版本自定义记录器通过命令行(我没有用它为我的测试项目,为了简单起见)。这实际上是生成日志(一个XML文件),我将解析以确定是否记录了任何错误。
顺便说一句,我认为控制台记录器是一种“全球”记录器。我错了吗?

无论如何,自定义记录器既没有帮助,Log.HasLoggedErrors仍然设置为false
有没有某种方式我不知道引用特定的记录器(例如我的自定义记录器)以询问它是否记录了任何错误?

它确实看起来像Log是作用于单个目标。

嗯......如果buildengine实例上的反射是最后的手段,我仍然会更喜欢解析日志。
(不要怪我:-)!)


我的决定
一些调查,我决定坚持我最初的解决方案后:分析日志,以找出是否构建失败。

查看我的评论,看看为什么我更喜欢到目前为止提供的建议。

如果有人有一些其他的想法不要犹豫,分享:-)

(否则,这个问题可以被关闭,我想...)

回答

19

MSBuildLastTaskResultreserved property将被设置为True如果最后一个任务成功,False如果上次任务失败:

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

我相信这在MSBuild v4.0中引入。

+0

+1提示在MSDN站点上仍然缺少的新保留属性!我没有意识到这一点。这是我正在寻找的解决方案,谢谢! – Elena

+0

如果您查看MSDN保留属性页面的底部,您会看到来自社区的某人记录了几个缺失的属性。令人困惑的是官方文件从未更新过。 –

+0

是的,我今天看了这个评论,甚至在我的桌子上还有最后一版Sayed Ibrahim Hashimi的书;-)但是我没有意识到这个属性,thx又一次! – Elena

0

你可以捕捉TargetOutputs并检查他们的事后的错误情况,但这仍然相当黑客。

+0

嗯......如果没有更好的方法,我会更好地创建一个自定义任务,解析我的日志文件并计算错误(和警告)。 使我的项目文件看起来更清晰.. @skolima无论如何感谢您的快速答案! – Elena

+4

不需要解析日志,只需从Microsoft.Build.Tasks.MSBuild继承并显示返回Log.HasLoggedErrors的输出 –

+0

这是个好主意,谢谢@IlyaKozhevnikov! – Elena

0

如果您只想检查MSBuild任务是否失败,请使用Exec任务。将IgnoreExitCode设置为true并检查ExitCode输出值。如果不是零,则有些错误。

如果你需要构建错误的列表,使用/fileloggerparameters command line switch记录错误只对某些特定的文件:

/flp1:logfile=errors.txt;errorsonly

+0

我只想检查'MSBuild'任务是否失败,但我不想使用'Exec'任务而不是'MSBuild'任务,因为最后的优点。 – Elena

0

但如果里面的一些其他任务目标(例如Copytask)引发错误Log.HasLoggedErrors返回false。

不知道评论有长度的限制...

日志的作用范围是单个目标或更具体的任务,(据我所知)没有办法获得一个“全球”的,可能是通过反思buildengine实例,或编写自定义记录器并通过命令行传递它。无论如何,你作为项目建设的是什么? HasLoggedErrors按预期工作(并且多年来一直保持不变),它显示正在构建的项目是否记录了任何错误。它不能也不应该控制其他任务的记录(可能使用其他类型的记录器)。如果你想要一个全球化的,一种方法是建立自我,但有不同的目标,例如你的DefaultTargets启动你自定义的MSBuildWrapper任务指向自己(即$(MSBuildProjectFile)),但有一个不同的目标,其他生成,复制,等,理论上应该模拟全球HasLoggedErrors ...

+0

我承认我应该详细描述我的“调查”。 我刚做完了,看到我的答案。 无论如何,我真的很感谢你的建议和“意志”的帮助! :-) – Elena

3

我知道这个线程是有点老了,但另一种可能的解决方案,我想你需要知道,构建以执行一些“最后的任务”失败,就是用:

<OnError ExecuteTargets="FinalReportTarget;CleanupTarget" /> 

那在发生错误时会失败,但执行“FinalReportTarget”和“CleanupTarget”。

ContinueOnError =“true”在这种情况下不需要。

+1

阿列克谢,感谢您的建议,但重点是我想使用“ContinueOnError =”true“”。我的项目中有几个MSBuild任务,我想全部运行它们,无论它们中的一些是否失败。但最后我希望能够检查其中一些是否失败。使用你的方法,构建将在其中一个任务失败时立即终止。 – Elena

+0

这可能不是最优雅的解决方案,但是您可以在您希望发生错误的每个单独标记中链接OnError。此外,您可以使用一些常见的PrintError任务,如,在PrintError中您将检查MSBuildLastTaskResult。 –

相关问题