Как проверить, не сбой MSBuild-Task при использовании ContinueOnError = true
Я запускаю задачу 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>
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 является последним средством, я бы предпочел разбор журнала.
(Не обвиняйте меня!:-))
Мое решение
После некоторых исследований я решил придерживаться своего первоначального решения: проанализируйте журнал, чтобы узнать, не удалось ли построить сборку.
Проверьте мои комментарии, чтобы узнать, почему я предпочитаю, чтобы предложения были предоставлены до сих пор.
Если у кого-то есть другие идеи, не стесняйтесь делиться: -)
(В противном случае этот вопрос может быть закрыт, я полагаю...)
Ответы
Ответ 1
MSBuildLastTaskResult
зарезервированное свойство будет установлено в True
, если последняя задача выполнена успешно, и False
, если последняя задача не выполнена:
<MSBuild Projects="@(ComponentToDeploy)"
Targets="$(DeploymentTargets)"
Properties="$(CommonProperties);%(AdditionalProperties)"
ContinueOnError="true"
Condition="%(Condition)" />
<Message Text="MSBuild failed!" Condition="'$(MSBuildLastTaskResult)' == 'False'" />
Я считаю, что это было введено с MSBuild v4.0.
Ответ 2
Я знаю, что этот поток немного устарел, но еще одно возможное решение, так как я полагаю, вам нужно знать, что сборка завершилась неудачей, чтобы выполнить некоторую "конечную задачу", заключается в использовании:
<OnError ExecuteTargets="FinalReportTarget;CleanupTarget" />
Это может привести к сбою сборки в случае ошибки, но выполнить "FinalReportTarget" и "CleanupTarget".
ContinueOnError = "true" в этом случае не требуется.
Ответ 3
Вы можете записать TargetOutputs
и затем проверить их на наличие ошибок, но это все еще довольно хакерское.
Ответ 4
Если вы хотите проверить, не была ли выполнена задача MSBuild, используйте Exec. Установите IgnoreExitCode в true и проверьте выходное значение ExitCode. Если не ноль, что-то не так.
Если вам нужен список ошибок сборки, используйте /fileloggerparameters командной строки, чтобы регистрировать ошибки только для определенного файла:
/flp1:logfile=errors.txt;errorsonly
Ответ 5
Но если другая задача внутри какой-либо цели (например, Copytask) вызвала ошибку, Log.HasLoggedErrors возвращает false.
Не знал, что комментарии имеют ограничения по длине...
Журнал привязан к отдельным целям или к более конкретным задачам, и (насколько мне известно) нет способа получить "глобальный", может быть через отражение в экземпляре buildengine или написание пользовательских logger и передать его через командную строку. В любом случае, что вы строите как проект? HasLoggedErrors работает так, как ожидалось (и работает неизменным в течение многих лет), он показывает, если проект строится с ошибками. Он не должен и не должен иметь никакого контроля за протоколированием других задач (которые могут использовать другие типы регистраторов). Если вы хотите глобальный, один способ - создать себя, но с другой целью, например, ваш DefaultTargets запускает вашу собственную задачу MSBuildWrapper, указывающую на себя (то есть $(MSBuildProjectFile)), но с другой целью, которая выполняет другие сборки, копии, и т.д., в теории он должен имитировать глобальные HasLoggedErrors...