如果使用ContinueOnError = true,如何检查MSBuild-Task是否失败

时间:2012-05-29 09:50:36

标签: msbuild msbuild-task msbuild-4.0

我正在使用 ContinueOnError = true 运行 MSBuild 任务:

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

所以我的构建总是成功。

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

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

(我正在使用MSBuild 4.0)


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

  

日志范围限定为单个目标或更具体的任务......

这确实是我在阅读您的评论并提出使用Log.HasLoggedErrors的建议时出现的第一个问题:“是否是日志的范围?”。
不幸的是,我无法找到合适的文档。 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



  

一种方法是构建self但具有不同的目标,例如你的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文件),以确定是否记录了任何错误 BTW,我认为控制台记录器是一种“全局”记录器。我错了吗?

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

看起来Log的范围确定为单个目标。

嗯......如果对buildengine实例的反射是最后的手段,我仍然希望解析日志。
(别怪我!:-))


我的决定
经过一些调查后,我决定坚持使用我的初始解决方案:解析日志以确定构建是否失败。

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

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

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

5 个答案:

答案 0 :(得分:20)

如果上一个任务成功,MSBuildLastTaskResult reserved property将设置为True,如果上一个任务失败,则False将设置为<MSBuild Projects="@(ComponentToDeploy)" Targets="$(DeploymentTargets)" Properties="$(CommonProperties);%(AdditionalProperties)" ContinueOnError="true" Condition="%(Condition)" /> <Message Text="MSBuild failed!" Condition="'$(MSBuildLastTaskResult)' == 'False'" />

{{1}}

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

答案 1 :(得分:3)

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

<OnError ExecuteTargets="FinalReportTarget;CleanupTarget" />

如果出现错误,那么构建将失败,但执行“FinalReportTarget”和“CleanupTarget”。

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

答案 2 :(得分:0)

您可以捕获TargetOutputs并在之后检查错误情况,但这仍然是非常hackish。

答案 3 :(得分:0)

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

如果您需要构建错误列表,请使用/fileloggerparameters command line switch仅将错误记录到某个特定文件:

/flp1:logfile=errors.txt;errorsonly

答案 4 :(得分:0)

  

但如果某个目标中的另一个任务(例如Copytask)引发错误,则Log.HasLoggedErrors返回false。

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

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