Подтвердить что ты не робот

Как проверить, не сбой 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 является последним средством, я бы предпочел разбор журнала.
(Не обвиняйте меня!:-))


Мое решение
После некоторых исследований я решил придерживаться своего первоначального решения: проанализируйте журнал, чтобы узнать, не удалось ли построить сборку.

Проверьте мои комментарии, чтобы узнать, почему я предпочитаю, чтобы предложения были предоставлены до сих пор.

Если у кого-то есть другие идеи, не стесняйтесь делиться: -)

(В противном случае этот вопрос может быть закрыт, я полагаю...)

4b9b3361

Ответ 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...