This should be obvious to do, but I just couldn't make it work...
What I'm trying to do is simple: I would like my compilation to fail with an error if there is a warning. Yes, the famous TreatWarningsAsErrors
...
I configured it in my C# project properties
This results in the expected TreatWarningsAsErrors
section in my csproj:
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
So far so good, if I add an useless private
variable in my code, it results in a compilation error:
private int unused;
Error 3 Warning as Error: The field 'XXXX.unused' is never used
But the whole problem is, I can't make it work for assembly reference issues. If I have a reference to an unknown assembly, the compiler (either devenv or msbuild) throws a warning, but I want an error instead.
Ultimately, I'm trying to configure a gated check-in TFS build configuration, so TFS would reject a commit in case there is a "The referenced component 'XXXX' could not be found." warning. Something simpler than modifying the build process template would be great.
Yes, even once in a while you will encounter the occasional warning you'd be better off leaving as a warning or even disabling completely. Those should be the exception to the rule, though. Here's some practical advise: at the start of a new project, start treating all warnings as errors, by default.
The TreatWarningsAsErrors option treats all warnings as errors. You can also use the TreatWarningsAsErrors to set only some warnings as errors. If you turn on TreatWarningsAsErrors, you can use WarningsNotAsErrors to list warnings that shouldn't be treated as errors.
WARNING: Something has not worked as it should. This may be of greater or lesser importance depending on the circumstances. e.g. An input file was not found, or was of the wrong format. ERROR: Something ``serious'' has gone wrong.
You can use the -Werror compiler flag to turn all or some warnings into errors. Show activity on this post. You can use -fdiagnostics-show-option to see the -W option that applies to a particular warning. Unfortunately, in this case there isn't any specific option that covers that warning.
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("{0}\**\*.log", 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.
MSBuild 15 now supports a /warnaserror
flag, which forces MSBuild warnings to be treated as errors.
MSBuild 15 is intalled with Visual Studio 2017 but can also be downloaded from GitHub
This GitHub issue explains why it cannot be set via an MSBuild property (tl;dr a property is too late)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With