1
votes

In CruiseControl.NET 1.8.4, I'm running a single project with multiple MsBuild-Tasks. A short excerpt from the project configuration, parsed and validated by the CCValidator:

<tasks>
  <msbuild>
    <buildArgs>msbuild-base.xml /m /p:BuildInParallel="true";Configuration="Release";Platform="Any CPU";nr="false";ccversionbase=15.1.0;NuGetProjectDir=D:\REPO\Repo-Base /verbosity:minimal /nologo /target:PreBuild</buildArgs>
    <dynamicValues />
    <environment />
    <executable>C:\Program Files (x86)\MSBuild\12.0\Bin\MSBuild.exe</executable>
    <logger>"C:\Program Files (x86)\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MSBuild.dll"</logger>
    <loggerParameters />
    <priority>Normal</priority>
    <timeout>120</timeout>
    <workingDirectory>D:\BaseLibraries</workingDirectory>
  </msbuild>
  <msbuild>
    <buildArgs>msbuild-other.xml /m /p:BuildInParallel="true";Configuration="Release";Platform="Any CPU";nr="false";ccversionbase=15.1.0;revfile=D:\REPO\Repo-Base\ci-revision.xml /verbosity:minimal /nologo /target:CIFull</buildArgs>
    <dynamicValues />
    <environment />
    <executable>C:\Program Files (x86)\MSBuild\12.0\Bin\MSBuild.exe</executable>
    <logger>"C:\Program Files (x86)\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MSBuild.dll"</logger>
    <loggerParameters />
    <priority>Normal</priority>
    <timeout>120</timeout>
    <workingDirectory>D:\BaseLibraries</workingDirectory>
  </msbuild>
</tasks>

There are a lot more tasks, but this should be enough to explain the problem. All tasks have different msbuild-files and are not targets in the same file.

For a successful build run of the project, the first few tasks must complete successfully. So it's perfect that CC.NET stops building when a task fails. But if one of the later tasks fail, I'd like to let CC.NET go on with the next task instead of stopping the whole build.

How can I configure CC.NET to ignore a failing task and go on with the next one?

2

2 Answers

1
votes

If you place the tasks that may always be ran in the publisher section, they will be ran, regardless if they fail or not.

It becomes more problematic if the order is something like : MayNotFail, MayFail, MayFail, MayNotFail

for that scenario I can not immediately think of a solution

1
votes

CruiseControl.NET let's the build stop and fail, when one of the tasks fails. I want to have the build completed with all tasks triggered, even if one task failes. Bonus: If one fails, I want the build status on "failed", but without stopping on the first fail event.

So I put all the non-critical ("optional") tasks into an extra MsBuild-Script:

<Project DefaultTargets="CIFull" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <PropertyGroup>
        <MsBuildAgent>"C:\Program Files (x86)\MSBuild\12.0\Bin\MSBuild.exe"</MsBuildAgent>
        <MsBuildArguments>msbuild.xml /m /p:BuildInParallel="true";Configuration="Release";Platform="Any CPU";nr="false";ccversionbase=$(ccversionbase);revfile=$(revfile);buildplans=$(buildplans) /verbosity:minimal /nologo /target:CIFull /nr:false</MsBuildArguments>
    </PropertyGroup>

    <Target Name="Libraries">
        <Exec Command="$(MsBuildAgent) $(MsBuildArguments)" WorkingDirectory="$(buildplans)\MyLibraryOne" IgnoreExitCode="false" ContinueOnError="true">
            <Output TaskParameter="ExitCode" PropertyName="LibExitCode01" />
        </Exec>
        <Exec Command="$(MsBuildAgent) $(MsBuildArguments)" WorkingDirectory="$(buildplans)\MyLibraryTwo" IgnoreExitCode="false" ContinueOnError="true">
            <Output TaskParameter="ExitCode" PropertyName="LibExitCode02" />
        </Exec>
        <Exec Command="$(MsBuildAgent) $(MsBuildArguments)" WorkingDirectory="$(buildplans)\MyLibraryThree" IgnoreExitCode="false" ContinueOnError="true">
            <Output TaskParameter="ExitCode" PropertyName="LibExitCode03" />
        </Exec>
    </Target>

    <Target Name="Applications">
        <Exec Command="$(MsBuildAgent) $(MsBuildArguments)" WorkingDirectory="$(buildplans)\ApplicationOne" IgnoreExitCode="false" ContinueOnError="true">
            <Output TaskParameter="ExitCode" PropertyName="AppExitCode01" />
        </Exec>
        <Exec Command="$(MsBuildAgent) $(MsBuildArguments)" WorkingDirectory="$(buildplans)\ApplicationTwo" IgnoreExitCode="false" ContinueOnError="true">
            <Output TaskParameter="ExitCode" PropertyName="AppExitCode02" />
        </Exec>
        <Exec Command="$(MsBuildAgent) $(MsBuildArguments)" WorkingDirectory="$(buildplans)\ApplicationThree" IgnoreExitCode="false" ContinueOnError="true">
            <Output TaskParameter="ExitCode" PropertyName="AppExitCode03" />
        </Exec>
    </Target>

    <Target Name="ValidateExitCodes">
        <ItemGroup>
            <Failed Condition="$(LibExitCode01) != 0" Include="MyLibraryOne" />
            <Failed Condition="$(LibExitCode02) != 0" Include="MyLibraryTwo" />
            <Failed Condition="$(LibExitCode03) != 0" Include="MyLibraryThree" />
            <Failed Condition="$(AppExitCode01) != 0" Include="ApplicationOne" />
            <Failed Condition="$(AppExitCode02) != 0" Include="ApplicationTwo" />
            <Failed Condition="$(AppExitCode03) != 0" Include="ApplicationThree" />
        </ItemGroup>
        <ItemGroup>
            <Success Condition="$(LibExitCode01) == 0" Include="MyLibraryOne" />
            <Success Condition="$(LibExitCode02) == 0" Include="MyLibraryTwo" />
            <Success Condition="$(LibExitCode03) == 0" Include="MyLibraryThree" />
            <Success Condition="$(AppExitCode01) == 0" Include="ApplicationOne" />
            <Success Condition="$(AppExitCode02) == 0" Include="ApplicationTwo" />
            <Success Condition="$(AppExitCode03) == 0" Include="ApplicationThree" />
        </ItemGroup>
        <Message Importance="High" Text="*** Success: @(Success->Count()) (@(Success, ' '))" />
        <Message Importance="High" Text="*** Failed:  @(Failed->Count()) (@(Failed, ' '))" />
        <Error Text="*** FAILED: @(Failed, ' ') ***" Condition="'@(Failed->Count())' > 0" />
    </Target>

    <Target Name="CIFull" DependsOnTargets="Libraries;Applications;ValidateExitCodes" />

</Project>

Instead of adding each of the "optional" libraries and applications as Tasks to the CC.NET project, they are now listed in the MsBuild file above. The CC.NET configuration is modified as follows:

<tasks>
  <msbuild>
    <!-- When this task fails, the build shall stop and fail -->
    <buildArgs>msbuild-base.xml /m /p:BuildInParallel="true";Configuration="Release";Platform="Any CPU";nr="false";ccversionbase=15.1.0;NuGetProjectDir=D:\REPO\Repo-Base /verbosity:minimal /nologo /target:PreBuild</buildArgs>
    <dynamicValues />
    <environment />
    <executable>C:\Program Files (x86)\MSBuild\12.0\Bin\MSBuild.exe</executable>
    <logger>"C:\Program Files (x86)\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MSBuild.dll"</logger>
    <loggerParameters />
    <priority>Normal</priority>
    <timeout>120</timeout>
    <workingDirectory>D:\BaseLibraries</workingDirectory>
  </msbuild>
  <msbuild>
    <!-- This task is the new build file from above. -->
    <buildArgs>msbuild-new.xml /m /p:BuildInParallel="true";Configuration="Release";Platform="Any CPU";nr="false";ccversionbase=15.1.0;revfile=D:\REPO\Repo-Base\ci-revision.xml;buildplans=D:\Meta\BuildPlans /verbosity:minimal /nologo /target:CIFull</buildArgs>
    <dynamicValues />
    <environment />
    <executable>C:\Program Files (x86)\MSBuild\12.0\Bin\MSBuild.exe</executable>
    <logger>"C:\Program Files (x86)\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MSBuild.dll"</logger>
    <loggerParameters />
    <priority>Normal</priority>
    <timeout>120</timeout>
    <workingDirectory>D:\Meta</workingDirectory>
  </msbuild>
</tasks>

CC.NET does the first task first. If it fails, no other task is executed and an error is reported. Was it OK, CC.NET goes on with the second task.

Now, all the libs and applications are build - ignoring (but saving) the return value (targets Libraries and Applications). The target ValidateExitCodes now creates a list of successful and failed tasks - after all tasks have run. And if the list for failed tasks contains an element, an error is returned to CC.NET. CC.NET will set the build state to error.