Skip to content

Commit

Permalink
Add ability to treat rule violations as errors (#523)
Browse files Browse the repository at this point in the history
* Add ability to treat rule violations as errors

fixes #522

* PR updates
  • Loading branch information
ErikEJ authored Feb 29, 2024
1 parent 6cbe29b commit e66f0e7
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 12 deletions.
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ Starting with version 2.7.0 of the SDK, there is support for running static code
- [SqlServer.Rules](https://github.com/tcartwright/SqlServer.Rules/blob/master/docs/table_of_contents.md)
- [Smells](https://github.com/davebally/TSQL-Smells)

Static code analysis can be enabled by adding the following to the project file:
Static code analysis can be enabled by adding the `RunSqlCodeAnalysis` property to the project file:

```xml
<Project Sdk="MSBuild.Sdk.SqlProj/2.7.0">
Expand All @@ -546,11 +546,23 @@ Static code analysis can be enabled by adding the following to the project file:
</PropertyGroup>
</Project>
```

A xml file with the analysis results is created in the output folder.

The optional `CodeAnalysisRules` property allows you to disable individual rules or groups of rules.

A xml file with the analysis results is created in the output folder, and any problems found during analysis are reported as build warnings.
Any rule violations found during analysis are reported as build warnings.

Individual rule violations can be configured to be reported as build errors as shown below.

`TreatWarningsAsErrors` does not affect found problems.
```xml
<Project Sdk="MSBuild.Sdk.SqlProj/2.7.0">
<PropertyGroup>
<RunSqlCodeAnalysis>True</RunSqlCodeAnalysis>
<CodeAnalysisRules>+!SqlServer.Rules.SRN0005</CodeAnalysisRules>
</PropertyGroup>
</Project>
```

## Workaround for parser errors (SQL46010)
This project relies on the publicly available T-SQL parser which may not support all T-SQL syntax constructions. Therefore you might encounter a SQL46010 error if you have a script file that contains unsupported syntax. If that happens, there's a couple of workarounds you can try:
Expand Down
13 changes: 11 additions & 2 deletions src/DacpacTool/PackageAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public sealed class PackageAnalyzer
private readonly IConsole _console;
private readonly HashSet<string> _ignoredRules = new();
private readonly HashSet<string> _ignoredRuleSets = new();
private readonly HashSet<string> _errorRuleSets = new();

public PackageAnalyzer(IConsole console, string rulesExpression)
{
Expand Down Expand Up @@ -49,7 +50,7 @@ public void Analyze(TSqlModel model, FileInfo outputFile)
{
foreach (var err in result.Problems)
{
_console.WriteLine(err.GetOutputMessage());
_console.WriteLine(err.GetOutputMessage(_errorRuleSets));
}

result.SerializeResultsToXml(GetOutputFileName(outputFile));
Expand All @@ -72,7 +73,7 @@ private void BuildRuleLists(string rulesExpression)
.StartsWith("-", StringComparison.OrdinalIgnoreCase)
&& rule.Length > 1))
{
if (rule.EndsWith("*", StringComparison.OrdinalIgnoreCase))
if (rule.Length > 2 && rule.EndsWith("*", StringComparison.OrdinalIgnoreCase))
{
_ignoredRuleSets.Add(rule[1..^1]);
}
Expand All @@ -81,6 +82,14 @@ private void BuildRuleLists(string rulesExpression)
_ignoredRules.Add(rule[1..]);
}
}
foreach (var rule in rulesExpression.Split(new[] { ';' },
StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Where(rule => rule
.StartsWith("+!", StringComparison.OrdinalIgnoreCase)
&& rule.Length > 2))
{
_errorRuleSets.Add(rule[2..]);
}
}
}

Expand Down
12 changes: 10 additions & 2 deletions src/DacpacTool/SqlRuleProblemExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SqlServer.Dac.CodeAnalysis;

Expand All @@ -9,9 +10,16 @@ namespace MSBuild.Sdk.SqlProj.DacpacTool
/// </summary>
public static class SqlRuleProblemExtensions
{
public static string GetOutputMessage(this SqlRuleProblem sqlRuleProblem)
public static string GetOutputMessage(this SqlRuleProblem sqlRuleProblem, HashSet<string> errorRules)
{
ArgumentNullException.ThrowIfNull(sqlRuleProblem);

SqlRuleProblemSeverity sqlRuleProblemSeverity = sqlRuleProblem.Severity;

if (errorRules.Contains(sqlRuleProblem.RuleId))
{
sqlRuleProblemSeverity = SqlRuleProblemSeverity.Error;
}

var stringBuilder = new StringBuilder();
stringBuilder.Append(sqlRuleProblem.SourceName);
Expand All @@ -21,7 +29,7 @@ public static string GetOutputMessage(this SqlRuleProblem sqlRuleProblem)
stringBuilder.Append(sqlRuleProblem.StartColumn);
stringBuilder.Append("):");
stringBuilder.Append(' ');
stringBuilder.Append(sqlRuleProblem.Severity);
stringBuilder.Append(sqlRuleProblemSeverity);
stringBuilder.Append(' ');
stringBuilder.Append(sqlRuleProblem.ErrorMessageString);

Expand Down
10 changes: 6 additions & 4 deletions test/DacpacTool.Tests/PackageAnalyzerTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.IO;
using System.Linq;
using Microsoft.SqlServer.Dac.Model;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;
Expand Down Expand Up @@ -38,7 +39,7 @@ public void RunsAnalyzerWithSupressions()
var testConsole = (TestConsole)_console;
testConsole.Lines.Clear();
var result = BuildSimpleModel();
var packageAnalyzer = new PackageAnalyzer(_console, "-SqlServer.Rules.SRD0006;-Smells.SML005;-SqlServer.Rules.SRD999;;");
var packageAnalyzer = new PackageAnalyzer(_console, "-SqlServer.Rules.SRD0006;-Smells.SML005;-SqlServer.Rules.SRD999;+!SqlServer.Rules.SRN0002;");

// Act
packageAnalyzer.Analyze(result.model, result.fileInfo);
Expand All @@ -47,8 +48,9 @@ public void RunsAnalyzerWithSupressions()
testConsole.Lines.Count.ShouldBe(13);

testConsole.Lines.ShouldContain($"Analyzing package '{result.fileInfo.FullName}'");
testConsole.Lines.ShouldNotContain($"SRD0006");
testConsole.Lines.ShouldNotContain($"SML005");
testConsole.Lines.Any(l => l.Contains("SRD0006")).ShouldBeFalse();
testConsole.Lines.Any(l => l.Contains("SML0005")).ShouldBeFalse();
testConsole.Lines.Any(l => l.Contains("Error SRN0002")).ShouldBeTrue();
testConsole.Lines.ShouldContain($"Successfully analyzed package '{result.fileInfo.FullName}'");
}

Expand All @@ -68,7 +70,7 @@ public void RunsAnalyzerWithWildcardSupressions()
testConsole.Lines.Count.ShouldBe(13);

testConsole.Lines.ShouldContain($"Analyzing package '{result.fileInfo.FullName}'");
testConsole.Lines.ShouldNotContain($"SRD");
testConsole.Lines.Any(l => l.Contains("SRD")).ShouldBeFalse();
testConsole.Lines.ShouldContain($"Successfully analyzed package '{result.fileInfo.FullName}'");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<TargetFramework>netstandard2.0</TargetFramework>
<SqlServerVersion>Sql150</SqlServerVersion>
<RunSqlCodeAnalysis>True</RunSqlCodeAnalysis>
<CodeAnalysisRules>-SqlServer.Rules.SRD0006;-Smells.*</CodeAnalysisRules>
<CodeAnalysisRules>-SqlServer.Rules.SRD0006;-Smells.*;+!SqlServer.Rules.SRN0002</CodeAnalysisRules>
</PropertyGroup>

<Import Project="$(MSBuildThisFileDirectory)..\..\src\MSBuild.Sdk.SqlProj\Sdk\Sdk.targets" />
Expand Down

0 comments on commit e66f0e7

Please sign in to comment.