Skip to content

Commit

Permalink
[CI] Use SARIF for static analysis
Browse files Browse the repository at this point in the history
  • Loading branch information
melanchall committed Apr 28, 2024
1 parent 3d91cbe commit c49377d
Show file tree
Hide file tree
Showing 14 changed files with 167 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace ConvertReSharperReportToHtml
{
internal sealed class ArtifactLocationDto
{
public string Uri { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace ConvertReSharperReportToHtml
{
internal sealed class DriverDto
{
public RuleDto[] Rules { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace ConvertReSharperReportToHtml
{
internal sealed class LocationDto
{
public PhysicalLocationDto PhysicalLocation { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace ConvertReSharperReportToHtml
{
internal sealed class PhysicalLocationDto
{
public ArtifactLocationDto ArtifactLocation { get; set; }

public RegionDto Region { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace ConvertReSharperReportToHtml
{
internal sealed class RegionDto
{
public int StartLine { get; set; }

public int StartColumn { get; set; }

public int EndLine { get; set; }

public int EndColumn { get; set; }

public int CharOffset { get; set; }

public int CharLength { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace ConvertReSharperReportToHtml
{
internal sealed class RelationshipDto
{
public TargetDto Target { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace ConvertReSharperReportToHtml
{
internal sealed class ReportDto
{
public RunDto[] Runs { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace ConvertReSharperReportToHtml
{
internal sealed class ResultDto
{
public string RuleId { get; set; }

public TextDto Message { get; set; }

public LocationDto[] Locations { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace ConvertReSharperReportToHtml
{
internal sealed class RuleDto
{
public string Id { get; set; }

public TextDto FullDescription { get; set; }

public TextDto ShortDescription { get; set; }

public RelationshipDto[] Relationships { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace ConvertReSharperReportToHtml
{
internal sealed class RunDto
{
public ResultDto[] Results { get; set; }

public ToolDto Tool { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace ConvertReSharperReportToHtml
{
internal sealed class TargetDto
{
public string Id { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace ConvertReSharperReportToHtml
{
internal sealed class TextDto
{
public string Text { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace ConvertReSharperReportToHtml
{
internal sealed class ToolDto
{
public DriverDto Driver { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
using System.Text;
using ConvertReSharperReportToHtml;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using System.Xml.XPath;

var inputFilePath = Path.GetFullPath(args[0]);
var outputFilePath = Path.GetFullPath(args[1]);
var branch = args[2];

Console.WriteLine($"Converting [{inputFilePath}] to HTML [{outputFilePath}] for [{branch}] branch...");

var xDocument = XDocument.Load(inputFilePath);
var reportJson = File.ReadAllText(inputFilePath);
var xDocument = JsonSerializer.Deserialize<ReportDto>(reportJson, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
var issueTypes = GetIssueTypes(xDocument);
var projects = GetProjects(xDocument);

Expand All @@ -20,39 +21,63 @@

foreach (var project in projects)
{
Console.WriteLine($"Processing [{project}] project...");
if (project.Contains("Test"))
{
Console.WriteLine(" skip test project");
continue;
}

var allIssues = GetProjectIssues(xDocument, project, issueTypes);
Console.WriteLine($" [{allIssues.Length}] issues found");

var issuesGroups = allIssues
.GroupBy(i => i.IssueType)
.ToArray();

Console.WriteLine($" [{issuesGroups.Length}] issues groups built");

stringBuilder.AppendLine($@"
<hr>
<hr>
<h1>{project} ({allIssues.Length} issues)</h1>
");

var i = 1;

foreach (var issues in issuesGroups)
{
Console.WriteLine($" [{i} / {issuesGroups.Length}] {issues.Key}");

stringBuilder.AppendLine($@"
<hr>
<h2>[{issues.Key.Severity}] {issues.Key.Description}</h2>
<table>
");

var j = 1;
var groupSize = issues.Count();

foreach (var issue in issues)
{
Console.WriteLine($" [{j} / {groupSize}] {issue.Message}");

var gitHubPath = issue.FilePath.Replace('\\', '/');
stringBuilder.AppendLine($@"
<tr>
<td><a href=""https://github.com/melanchall/drywetmidi/blob/{branch}/{gitHubPath}#L{issue.LineNumber}"">{issue.FilePath} <strong>({issue.LineNumber})</strong></a></td>
<td>{issue.Message}</td>
</tr>
");

j++;
}

stringBuilder.AppendLine($@"
</table>
");

i++;
}
}

Expand All @@ -63,27 +88,33 @@

//

Dictionary<string, IssueType> GetIssueTypes(XDocument xDocument) => xDocument
.Root
.XPathSelectElements("//IssueType")
Dictionary<string, IssueType> GetIssueTypes(ReportDto xDocument) => xDocument
.Runs
.First()
.Tool
.Driver
.Rules
.ToDictionary(
e => e.Attribute("Id").Value,
e => new IssueType(e.Attribute("Description").Value, e.Attribute("Severity").Value));

string[] GetProjects(XDocument xDocument) => xDocument
.Root
.XPathSelectElements("//Issues//Project")
.Select(e => e.Attribute("Name").Value)
e => e.Id,
e => new IssueType(e.FullDescription?.Text ?? e.ShortDescription.Text, e.Relationships.First().Target.Id));

string[] GetProjects(ReportDto xDocument) => xDocument
.Runs
.First()
.Results
.Select(e => Regex.Match(e.Locations.First().PhysicalLocation.ArtifactLocation.Uri, @"(.+?)/").Groups[1].Value)
.ToArray();

Issue[] GetProjectIssues(XDocument xDocument, string project, Dictionary<string, IssueType> issueTypes) => xDocument
.Root
.XPathSelectElements($"//Issues//Project[@Name='{project}']//Issue")
Issue[] GetProjectIssues(ReportDto xDocument, string project, Dictionary<string, IssueType> issueTypes) => xDocument
.Runs
.First()
.Results
.Where(e => e.Locations.First().PhysicalLocation.ArtifactLocation.Uri.StartsWith($"{project}/"))
.Select(e => new Issue(
e.Attribute("File").Value,
issueTypes[e.Attribute("TypeId").Value],
Convert.ToInt32(e.Attribute("Line")?.Value ?? "-1"),
e.Attribute("Message").Value))
e.Locations.First().PhysicalLocation.ArtifactLocation.Uri,
issueTypes[e.RuleId],
e.Locations.First().PhysicalLocation.Region.StartLine,
e.Message.Text))
.ToArray();

record IssueType(string Description, string Severity);
Expand Down

0 comments on commit c49377d

Please sign in to comment.