我正在使用 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实例的反射是最后的手段,我仍然希望解析日志。
(别怪我!:-))
我的决定
经过一些调查后,我决定坚持使用我的初始解决方案:解析日志以确定构建是否失败。
检查我的评论,看看为什么我更喜欢到目前为止提供的建议。
如果有人有其他想法,请不要犹豫分享: - )
(否则这个问题可以关闭,我想......)
答案 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 ......