13

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

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

所以我的构建总是成功的。

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

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

(我正在使用 MSBuild 4.0)


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

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

当我阅读您的评论并建议使用以下内容时,这确实是第一个问题Log.HasLoggedErrors:“日志的范围是多少? ”。
不幸的是,我找不到合适的文档。MSND 帮不上什么忙……
你为什么知道它是针对任务的?
我一点都不怀疑你的说法!我只是想知道某处是否有适当的文档..(我已经多年没有使用MSBuild了;-)

无论如何,您要构建什么项目?

我的测试项目非常简单。
我的测试项目

<?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.projHasLoggedErrors将被设置为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.

我的期望HasLoggedErrorstrue.



一种方法是构建 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 文件),我将对其进行解析以了解是否记录了任何错误。
顺便说一句,我认为控制台记录器是一种“全局”记录器。我错了吗?

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

它确实看起来像是Log针对单个目标的。

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


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

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

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

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

4

5 回答 5

23

如果最后一个任务成功并且最后一个任务失败,则MSBuildLastTaskResult 保留属性将设置为:TrueFalse

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

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

于 2012-06-05T19:44:17.410 回答
3

我知道这个线程有点旧,但另一个可能的解决方案是使用:

<OnError ExecuteTargets="FinalReportTarget;CleanupTarget" />

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

在这种情况下,不需要ContinueOnError="true" 。

于 2013-08-08T10:03:30.613 回答
0

之后您可以捕获TargetOutputs并检查它们是否存在错误情况,但这仍然是相当骇人听闻的。

于 2012-05-29T10:37:40.773 回答
0

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

如果您需要构建错误列表,请使用/fileloggerparameters 命令行开关将错误仅记录到某些特定文件:

/flp1:logfile=errors.txt;errorsonly

于 2012-05-29T12:32:08.353 回答
0

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

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

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

于 2012-05-30T19:34:33.993 回答