-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* WIP * Add suppressions support * Apply suggestions * add more rules Update tests * add wildcard exclusions (similar to VS UI) * Update targets * Undo attempt at Targets * simplify * Update .Targets * Add IncludeAssets * Add comment
- Loading branch information
Showing
12 changed files
with
312 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
using System; | ||
using System.Text; | ||
using Microsoft.SqlServer.Dac.Extensibility; | ||
|
||
namespace MSBuild.Sdk.SqlProj.DacpacTool | ||
{ | ||
/// <summary> | ||
/// A wrapper for <see cref="ExtensibilityError" /> that provides MSBuild compatible output and source document information. | ||
/// </summary> | ||
public static class ExtensibilityErrorExtensions | ||
{ | ||
public static string GetOutputMessage(this ExtensibilityError extensibilityError) | ||
{ | ||
ArgumentNullException.ThrowIfNull(extensibilityError); | ||
|
||
var stringBuilder = new StringBuilder(); | ||
stringBuilder.Append(extensibilityError.Document); | ||
stringBuilder.Append('('); | ||
stringBuilder.Append(extensibilityError.Line); | ||
stringBuilder.Append(','); | ||
stringBuilder.Append(extensibilityError.Column); | ||
stringBuilder.Append("):"); | ||
stringBuilder.Append(' '); | ||
stringBuilder.Append(extensibilityError.Severity); | ||
stringBuilder.Append(' '); | ||
stringBuilder.Append(extensibilityError.ErrorCode); | ||
stringBuilder.Append(": "); | ||
stringBuilder.Append(extensibilityError.Message); | ||
|
||
return stringBuilder.ToString(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using Microsoft.SqlServer.Dac.CodeAnalysis; | ||
using Microsoft.SqlServer.Dac.Model; | ||
using System.Linq; | ||
|
||
namespace MSBuild.Sdk.SqlProj.DacpacTool | ||
{ | ||
public sealed class PackageAnalyzer | ||
{ | ||
private readonly IConsole _console; | ||
private readonly HashSet<string> _ignoredRules = new(); | ||
private readonly HashSet<string> _ignoredRuleSets = new(); | ||
|
||
public PackageAnalyzer(IConsole console, string rulesExpression) | ||
{ | ||
_console = console ?? throw new ArgumentNullException(nameof(console)); | ||
|
||
BuildRuleLists(rulesExpression); | ||
} | ||
|
||
public void Analyze(TSqlModel model, FileInfo outputFile) | ||
{ | ||
_console.WriteLine($"Analyzing package '{outputFile.FullName}'"); | ||
try | ||
{ | ||
var factory = new CodeAnalysisServiceFactory(); | ||
var service = factory.CreateAnalysisService(model); | ||
|
||
if (_ignoredRules.Count > 0 || _ignoredRuleSets.Count > 0) | ||
{ | ||
service.SetProblemSuppressor(p => | ||
_ignoredRules.Contains(p.Rule.RuleId) | ||
|| _ignoredRuleSets.Any(s => p.Rule.RuleId.StartsWith(s))); | ||
} | ||
|
||
var result = service.Analyze(model); | ||
if (!result.AnalysisSucceeded) | ||
{ | ||
var errors = result.GetAllErrors(); | ||
foreach (var err in errors) | ||
{ | ||
_console.WriteLine(err.GetOutputMessage()); | ||
} | ||
return; | ||
} | ||
else | ||
{ | ||
foreach (var err in result.Problems) | ||
{ | ||
_console.WriteLine(err.GetOutputMessage()); | ||
} | ||
|
||
result.SerializeResultsToXml(GetOutputFileName(outputFile)); | ||
} | ||
_console.WriteLine($"Successfully analyzed package '{outputFile}'"); | ||
} | ||
catch (Exception ex) | ||
{ | ||
_console.WriteLine($"ERROR: An unknown error occurred while analyzing package '{outputFile.FullName}': {ex.Message}"); | ||
} | ||
} | ||
|
||
private void BuildRuleLists(string rulesExpression) | ||
{ | ||
if (!string.IsNullOrWhiteSpace(rulesExpression)) | ||
{ | ||
foreach (var rule in rulesExpression.Split(new[] { ';' }, | ||
StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) | ||
.Where(rule => rule | ||
.StartsWith("-", StringComparison.OrdinalIgnoreCase) | ||
&& rule.Length > 1)) | ||
{ | ||
if (rule.EndsWith("*", StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
_ignoredRuleSets.Add(rule[1..^1]); | ||
} | ||
else | ||
{ | ||
_ignoredRules.Add(rule[1..]); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private static string GetOutputFileName(FileInfo outputFile) | ||
{ | ||
var outputFileName = outputFile.FullName; | ||
if (outputFile.Extension.Equals(".dacpac", StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
outputFileName = outputFile.FullName[..^7]; | ||
} | ||
return outputFileName + ".CodeAnalysis.xml"; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
using System; | ||
using System.Text; | ||
using Microsoft.SqlServer.Dac.CodeAnalysis; | ||
|
||
namespace MSBuild.Sdk.SqlProj.DacpacTool | ||
{ | ||
/// <summary> | ||
/// A wrapper for <see cref="SqlRuleProblem" /> that provides MSBuild compatible output and source document information. | ||
/// </summary> | ||
public static class SqlRuleProblemExtensions | ||
{ | ||
public static string GetOutputMessage(this SqlRuleProblem sqlRuleProblem) | ||
{ | ||
ArgumentNullException.ThrowIfNull(sqlRuleProblem); | ||
|
||
var stringBuilder = new StringBuilder(); | ||
stringBuilder.Append(sqlRuleProblem.SourceName); | ||
stringBuilder.Append('('); | ||
stringBuilder.Append(sqlRuleProblem.StartLine); | ||
stringBuilder.Append(','); | ||
stringBuilder.Append(sqlRuleProblem.StartColumn); | ||
stringBuilder.Append("):"); | ||
stringBuilder.Append(' '); | ||
stringBuilder.Append(sqlRuleProblem.Severity); | ||
stringBuilder.Append(' '); | ||
stringBuilder.Append(sqlRuleProblem.ErrorMessageString); | ||
|
||
return stringBuilder.ToString(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
using System.IO; | ||
using Microsoft.SqlServer.Dac.Model; | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
using Shouldly; | ||
|
||
namespace MSBuild.Sdk.SqlProj.DacpacTool.Tests | ||
{ | ||
[TestClass] | ||
public class PackageAnalyzerTests | ||
{ | ||
private readonly IConsole _console = new TestConsole(); | ||
|
||
[TestMethod] | ||
public void RunsAnalyzer() | ||
{ | ||
// Arrange | ||
var testConsole = (TestConsole)_console; | ||
testConsole.Lines.Clear(); | ||
var result = BuildSimpleModel(); | ||
var packageAnalyzer = new PackageAnalyzer(_console, null); | ||
|
||
// Act | ||
packageAnalyzer.Analyze(result.model, result.fileInfo); | ||
|
||
// Assert | ||
testConsole.Lines.Count.ShouldBe(15); | ||
|
||
testConsole.Lines.ShouldContain($"Analyzing package '{result.fileInfo.FullName}'"); | ||
testConsole.Lines.ShouldContain($"proc1.sql(1,47): Warning SRD0006 : SqlServer.Rules : Avoid using SELECT *."); | ||
testConsole.Lines.ShouldContain($"proc1.sql(1,47): Warning SML005 : Smells : Avoid use of 'Select *'"); | ||
testConsole.Lines.ShouldContain($"Successfully analyzed package '{result.fileInfo.FullName}'"); | ||
} | ||
|
||
[TestMethod] | ||
public void RunsAnalyzerWithSupressions() | ||
{ | ||
// Arrange | ||
var testConsole = (TestConsole)_console; | ||
testConsole.Lines.Clear(); | ||
var result = BuildSimpleModel(); | ||
var packageAnalyzer = new PackageAnalyzer(_console, "-SqlServer.Rules.SRD0006;-Smells.SML005;-SqlServer.Rules.SRD999;;"); | ||
|
||
// Act | ||
packageAnalyzer.Analyze(result.model, result.fileInfo); | ||
|
||
// Assert | ||
testConsole.Lines.Count.ShouldBe(13); | ||
|
||
testConsole.Lines.ShouldContain($"Analyzing package '{result.fileInfo.FullName}'"); | ||
testConsole.Lines.ShouldNotContain($"SRD0006"); | ||
testConsole.Lines.ShouldNotContain($"SML005"); | ||
testConsole.Lines.ShouldContain($"Successfully analyzed package '{result.fileInfo.FullName}'"); | ||
} | ||
|
||
[TestMethod] | ||
public void RunsAnalyzerWithWildcardSupressions() | ||
{ | ||
// Arrange | ||
var testConsole = (TestConsole)_console; | ||
testConsole.Lines.Clear(); | ||
var result = BuildSimpleModel(); | ||
var packageAnalyzer = new PackageAnalyzer(_console, "-SqlServer.Rules.SRD*"); | ||
|
||
// Act | ||
packageAnalyzer.Analyze(result.model, result.fileInfo); | ||
|
||
// Assert | ||
testConsole.Lines.Count.ShouldBe(13); | ||
|
||
testConsole.Lines.ShouldContain($"Analyzing package '{result.fileInfo.FullName}'"); | ||
testConsole.Lines.ShouldNotContain($"SRD"); | ||
testConsole.Lines.ShouldContain($"Successfully analyzed package '{result.fileInfo.FullName}'"); | ||
} | ||
|
||
private static (FileInfo fileInfo, TSqlModel model) BuildSimpleModel() | ||
{ | ||
var tmodel = new TestModelBuilder() | ||
.AddTable("TestTable", ("Column1", "nvarchar(100)")) | ||
.AddStoredProcedure("sp_GetData", "SELECT * FROM dbo.TestTable", "proc1.sql"); | ||
|
||
var model = tmodel.Build(); | ||
var packagePath = tmodel.SaveAsPackage(); | ||
|
||
return (new FileInfo(packagePath), model); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
|
||
namespace MSBuild.Sdk.SqlProj.DacpacTool.Tests | ||
{ | ||
internal class TestConsole : IConsole | ||
{ | ||
public readonly List<string> Lines = new List<string>(); | ||
|
||
public string ReadLine() | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
public void WriteLine(string value) | ||
{ | ||
Lines.Add(value); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
CREATE PROCEDURE [dbo].[sp_Test] | ||
AS | ||
BEGIN | ||
SELECT * FROM [dbo].[MyTable]; | ||
END |
12 changes: 12 additions & 0 deletions
12
test/TestProjectWithAnalyzers/TestProjectWithAnalyzers.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<Project> | ||
<Import Project="$(MSBuildThisFileDirectory)..\..\src\MSBuild.Sdk.SqlProj\Sdk\Sdk.props" /> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>netstandard2.0</TargetFramework> | ||
<SqlServerVersion>Sql150</SqlServerVersion> | ||
<RunSqlCodeAnalysis>True</RunSqlCodeAnalysis> | ||
<CodeAnalysisRules>-SqlServer.Rules.SRD0006;-Smells.*</CodeAnalysisRules> | ||
</PropertyGroup> | ||
|
||
<Import Project="$(MSBuildThisFileDirectory)..\..\src\MSBuild.Sdk.SqlProj\Sdk\Sdk.targets" /> | ||
</Project> |