Treat all warnings as errors

MSBuild warnings (all start with MSB*) as opposed to CSC warnings cannot be suppressed nor promoted to errors. For the reason the ResolveAssemblyReference task prints its messages on the fly and does not aggregate any of them.

The only feasible solution is reading the MSBuild log files created during the TFS build.
I think the most elegant solution is to implement a custom Build CodeActivity. The following is a simple activity that will output to results any files containing a given SearchString:

using System;
using System.Activities;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.TeamFoundation.Build.Client;

namespace MyBuildActivities.FileSystem
{
    [BuildActivity(HostEnvironmentOption.Agent)]
    public sealed class ReadStringFromFile : CodeActivity
    {
        [RequiredArgument]
        public InArgument<IEnumerable<string>> Files { get; set; }

        [RequiredArgument]
        public InArgument<string> SearchString { get; set; }

        public OutArgument<string> Result { get; set; }

        protected override void Execute(CodeActivityContext context)
        {
            var files = context.GetValue(Files);
            var searchString = context.GetValue(SearchString);

            var list =
                (files.Where(file => File.ReadAllText(file).Contains(searchString))
                    .Select(file => string.Format("{0} was found at {1}", searchString, file))).ToList();

            if(list.Count > 0)
                Result.Set(context, string.Join(Environment.NewLine, list));
        }
    }
}

Declared in the build process template like so:

xmlns:cfs="clr-namespace:MyBuildActivities.FileSystem;assembly=MyBuildActivities"

Invoked just at the end of the Compile and Test for Configuration sequence:

<Sequence DisplayName="Handle MSBuild Errors">
         <Sequence.Variables>
                 <Variable x:TypeArguments="scg:IEnumerable(x:String)" Name="logFiles" />                                                                                                                 
                 <Variable x:TypeArguments="x:String" Name="readStringFromFileResult" />
         </Sequence.Variables>
         <mtbwa:FindMatchingFiles DisplayName="Find Log Files" MatchPattern="[String.Format(&quot;{0}\**\*.log&quot;, logFileDropLocation)]" Result="[logFiles]" mtbwt:BuildTrackingParticipant.Importance="Low" />
         <cfs:ReadStringFromFile Files="[logFiles]" SearchString="MSB3245" Result="[readStringFromFileResult]" />
         <mtbwa:WriteBuildMessage DisplayName="Write Result" Message="[readStringFromFileResult]" Importance="[Microsoft.TeamFoundation.Build.Client.BuildMessageImportance.High]" />
         <If Condition="[readStringFromFileResult.Count > 0]" DisplayName="If SearchString Was Found" mtbwt:BuildTrackingParticipant.Importance="Low">
                 <If.Then>
                          <Throw DisplayName="Throw Exception" Exception="[New Exception(readStringFromFileResult)]" mtbwt:BuildTrackingParticipant.Importance="Low" />
                 </If.Then>
         </If>                                                                                                              
</Sequence>

I’ve tested this on TFS 2012 though it should work for TFS 2010 as well.

Leave a Comment