我正在使用 MSBuild 任务并设置 ContinueOnError=true:
<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>
< p > < em > 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,即使在控制台记录了一个错误(MSB3021),HasLoggedErrors
也会被设置为false
:
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
是针对各个目标作用域的。嗯... 如果反射生成实例是最后的手段,我仍然更喜欢解析日志。
(别责备我!:-))
我的决定
经过一些调查,我决定坚持我的最初解决方案:解析日志以查找构建是否失败。
请检查我的评论,了解为什么我更喜欢这个建议。
如果有人有其他想法,请不要犹豫分享 :-)
(否则,我想可以关闭此问题...)
$(MSBuildLastTaskResult)
仅在上一个任务失败时才为False
。这听起来很琐碎,但是对于任务批处理来说并非如此。也就是说,如果任务批处理执行两次MSBuild
任务,而只有第一个失败了,整个构建将会失败,但该属性将被设置为True
。 - tm1CallTarget
而不是MSBuild
并使用任务批处理,则整个构建将成功,并且当第一个任务失败且最后一个任务成功时,$(MSBuildLastTaskResult)
设置为True
。但是,如果不使用任务批处理,则CallTarget
任务将在第一个失败的任务处停止,将$(MSBuildLastTaskResult)
设置为False
并使构建失败。这些不同的行为可以视为不一致性或强大的功能,具体取决于观点。 - tm1