Skip to content

Commit 2790a07

Browse files
authored
Add MSBuildTreatWarningsAsErrors alongside TreatWarningsAsErrors (#15)
1 parent 7705ca4 commit 2790a07

File tree

3 files changed

+100
-5
lines changed

3 files changed

+100
-5
lines changed

src/build/Workleap.DotNet.CodingStandards.props

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717
<ContinuousIntegrationBuild Condition="'$(CI)' == 'true'">true</ContinuousIntegrationBuild>
1818
<ContinuousIntegrationBuild Condition="'$(TEAMCITY_VERSION)' != ''">true</ContinuousIntegrationBuild>
1919

20-
<!-- TreatWarningsAsErrors is enabled for release builds, unless explicitly set -->
20+
<!-- TreatWarningsAsErrors and MSBuildTreatWarningsAsErrors are enabled for release builds, unless explicitly set -->
2121
<TreatWarningsAsErrors Condition="'$(Configuration)' == 'Release' AND '$(TreatWarningsAsErrors)' == ''">true</TreatWarningsAsErrors>
22+
<MSBuildTreatWarningsAsErrors Condition="'$(Configuration)' == 'Release' AND '$(MSBuildTreatWarningsAsErrors)' == ''">true</MSBuildTreatWarningsAsErrors>
2223

2324
<!-- https://devblogs.microsoft.com/visualstudio/vs-toolbox-accelerate-your-builds-of-sdk-style-net-projects/ -->
2425
<AccelerateBuildsInVisualStudio Condition="'$(AccelerateBuildsInVisualStudio)' == ''">true</AccelerateBuildsInVisualStudio>

tests/Workleap.DotNet.CodingStandards.Tests/CodingStandardTests.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,42 @@ public async Task WarningsAsErrorOnGitHubActions()
2525
Assert.True(data.HasError("RS0030"));
2626
}
2727

28+
[Fact]
29+
public async Task MSBuildWarningsAsErrorOnDebugConfiguration()
30+
{
31+
using var project = new ProjectBuilder(fixture, testOutputHelper);
32+
project.AddCsprojFile(packageReferences: new Dictionary<string, string> { { "Azure.Identity", "1.10.4" } });
33+
project.AddFile("sample.cs", """
34+
namespace sample;
35+
public static class Sample
36+
{
37+
public static void Main(string[] args)
38+
{
39+
}
40+
}
41+
""");
42+
var data = await project.BuildAndGetOutput();
43+
Assert.True(data.HasWarning("NU1902"));
44+
}
45+
46+
[Fact]
47+
public async Task MSBuildWarningsAsErrorOnReleaseConfiguration()
48+
{
49+
using var project = new ProjectBuilder(fixture, testOutputHelper);
50+
project.AddCsprojFile(packageReferences: new Dictionary<string, string> { { "Azure.Identity", "1.10.4" } });
51+
project.AddFile("sample.cs", """
52+
namespace sample;
53+
public static class Sample
54+
{
55+
public static void Main(string[] args)
56+
{
57+
}
58+
}
59+
""");
60+
var data = await project.BuildAndGetOutput(["--configuration", "Release"]);
61+
Assert.True(data.HasError("NU1902"));
62+
}
63+
2864
[Fact]
2965
public async Task NamingConvention_Invalid()
3066
{

tests/Workleap.DotNet.CodingStandards.Tests/Helpers/ProjectBuilder.cs

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Xunit.Abstractions;
33
using System.Text.Json;
44
using CliWrap;
5+
using Xunit.Sdk;
56

67
namespace Workleap.DotNet.CodingStandards.Tests.Helpers;
78

@@ -46,14 +47,27 @@ public void AddFile(string relativePath, string content)
4647
File.WriteAllText(this._directory.GetPath(relativePath), content);
4748
}
4849

49-
public void AddCsprojFile(Dictionary<string, string>? properties = null)
50+
public void AddCsprojFile(Dictionary<string, string>? properties = null, Dictionary<string, string>? packageReferences = null)
5051
{
51-
var element = new XElement("PropertyGroup");
52+
var propertyElement = new XElement("PropertyGroup");
5253
if (properties != null)
5354
{
5455
foreach (var prop in properties)
5556
{
56-
element.Add(new XElement(prop.Key), prop.Value);
57+
propertyElement.Add(new XElement(prop.Key), prop.Value);
58+
}
59+
}
60+
61+
var referencesElement = new XElement("ItemGroup");
62+
if (packageReferences != null)
63+
{
64+
foreach (var reference in packageReferences)
65+
{
66+
var packageReference = new XElement("PackageReference");
67+
packageReference.SetAttributeValue("Include", reference.Key);
68+
packageReference.SetAttributeValue("Version", reference.Value);
69+
70+
referencesElement.Add(packageReference);
5771
}
5872
}
5973

@@ -66,11 +80,12 @@ public void AddCsprojFile(Dictionary<string, string>? properties = null)
6680
<Nullable>enable</Nullable>
6781
<ErrorLog>{SarifFileName},version=2.1</ErrorLog>
6882
</PropertyGroup>
69-
{element}
83+
{propertyElement}
7084
7185
<ItemGroup>
7286
<PackageReference Include="Workleap.DotNet.CodingStandards" Version="*" />
7387
</ItemGroup>
88+
{referencesElement}
7489
</Project>
7590
""";
7691

@@ -92,9 +107,52 @@ public async Task<SarifFile> BuildAndGetOutput(string[]? buildArguments = null)
92107

93108
var bytes = await File.ReadAllBytesAsync(this._directory.GetPath(SarifFileName));
94109
var sarif = JsonSerializer.Deserialize<SarifFile>(bytes) ?? throw new InvalidOperationException("The sarif file is invalid");
110+
111+
this.AppendAdditionalResult(sarif);
112+
95113
this._testOutputHelper.WriteLine("Sarif result:\n" + string.Join("\n", sarif.AllResults().Select(r => r.ToString())));
96114
return sarif;
97115
}
98116

99117
public void Dispose() => this._directory.Dispose();
118+
119+
private void AppendAdditionalResult(SarifFile sarifFile)
120+
{
121+
if (this._testOutputHelper is not TestOutputHelper testOutputHelper || sarifFile.Runs == null)
122+
{
123+
return;
124+
}
125+
126+
var outputLines = testOutputHelper.Output.Split(Environment.NewLine);
127+
var customRunResults = new List<SarifFileRunResult>();
128+
129+
// These rules (for nuget package vulnerability) are not parsed in the sarif file automatically
130+
// See https://learn.microsoft.com/en-us/nuget/reference/errors-and-warnings/nu1901-nu1904
131+
var scannedRules = new List<string> { "NU1901", "NU1902", "NU1903", "NU1904" }
132+
.ToDictionary(x => x, x => $"{x}:");
133+
134+
foreach (var outputLine in outputLines)
135+
{
136+
foreach (var scannedRule in scannedRules)
137+
{
138+
var scannedRuleIndex = outputLine.IndexOf(scannedRule.Value, StringComparison.OrdinalIgnoreCase);
139+
if (scannedRuleIndex == -1)
140+
{
141+
continue;
142+
}
143+
144+
var previousColonIndex = outputLine.LastIndexOf(':', scannedRuleIndex);
145+
var ruleLevel = outputLine.Substring(previousColonIndex + 1, scannedRuleIndex - previousColonIndex - 1).Trim();
146+
147+
var message = outputLine[(scannedRuleIndex + scannedRule.Value.Length + 1)..];
148+
customRunResults.Add(new SarifFileRunResult { Level = ruleLevel, RuleId = scannedRule.Key, Message = new SarifFileRunResultMessage { Text = message } });
149+
}
150+
}
151+
152+
var distinctRules = customRunResults
153+
.DistinctBy(x => new { x.RuleId, x.Level })
154+
.ToArray();
155+
156+
sarifFile.Runs = sarifFile.Runs.Append(new SarifFileRun { Results = distinctRules }).ToArray();
157+
}
100158
}

0 commit comments

Comments
 (0)