This repository has been archived by the owner on Dec 25, 2023. It is now read-only.
/
XmlFileLoggerLogFileFormat.cs
225 lines (193 loc) · 7.72 KB
/
XmlFileLoggerLogFileFormat.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
namespace Cake.Issues.MsBuild.LogFileFormat
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
using Cake.Core.Diagnostics;
/// <summary>
/// MsBuild log format as written by the <c>XmlFileLogger</c> class from MSBuild Extension Pack.
/// </summary>
internal class XmlFileLoggerLogFileFormat : BaseMsBuildLogFileFormat
{
/// <summary>
/// Initializes a new instance of the <see cref="XmlFileLoggerLogFileFormat"/> class.
/// </summary>
/// <param name="log">The Cake log instance.</param>
public XmlFileLoggerLogFileFormat(ICakeLog log)
: base(log)
{
}
/// <inheritdoc/>
public override IEnumerable<IIssue> ReadIssues(
MsBuildIssuesProvider issueProvider,
IssueCommentFormat format,
RepositorySettings repositorySettings,
MsBuildIssuesSettings issueProviderSettings)
{
#pragma warning disable SA1123 // Do not place regions within elements
#region DupFinder Exclusion
#pragma warning restore SA1123 // Do not place regions within elements
issueProvider.NotNull(nameof(issueProvider));
repositorySettings.NotNull(nameof(repositorySettings));
issueProviderSettings.NotNull(nameof(issueProviderSettings));
#endregion
var result = new List<IIssue>();
// Read log file.
var logDocument = XDocument.Parse(issueProviderSettings.LogFileContent.ToStringUsingEncoding(true));
// Loop through all warning tags.
foreach (var warning in logDocument.Descendants("warning"))
{
// Read affected project from the warning.
if (!this.TryGetProject(warning, repositorySettings, out string projectFileRelativePath))
{
continue;
}
// Read affected file from the warning.
if (!this.TryGetFile(warning, repositorySettings, out string fileName))
{
continue;
}
// Read affected line from the warning.
if (!TryGetLine(warning, out var line))
{
continue;
}
// Read rule code from the warning.
if (!TryGetRule(warning, out string rule))
{
continue;
}
// Determine rule URL.
Uri ruleUrl = null;
if (!string.IsNullOrWhiteSpace(rule))
{
ruleUrl = MsBuildRuleUrlResolver.Instance.ResolveRuleUrl(rule);
}
// Build issue.
result.Add(
IssueBuilder
.NewIssue(warning.Value, issueProvider)
.WithPriority(IssuePriority.Warning)
.InProject(projectFileRelativePath, System.IO.Path.GetFileNameWithoutExtension(projectFileRelativePath))
.InFile(fileName, line)
.OfRule(rule, ruleUrl)
.Create());
}
return result;
}
/// <summary>
/// Reads the affected line from a warning logged in a MsBuild log.
/// </summary>
/// <param name="warning">Warning element from MsBuild log.</param>
/// <param name="line">Returns line.</param>
/// <returns>True if the line could be parsed.</returns>
private static bool TryGetLine(XElement warning, out int? line)
{
line = null;
var lineAttr = warning.Attribute("line");
var lineValue = lineAttr?.Value;
if (string.IsNullOrWhiteSpace(lineValue))
{
return false;
}
line = int.Parse(lineValue, CultureInfo.InvariantCulture);
// Convert negative line numbers or line number 0 to null
if (line <= 0)
{
line = null;
}
return true;
}
/// <summary>
/// Reads the rule code from a warning logged in a MsBuild log.
/// </summary>
/// <param name="warning">Warning element from MsBuild log.</param>
/// <param name="rule">Returns the code of the rule.</param>
/// <returns>True if the rule code could be parsed.</returns>
private static bool TryGetRule(XElement warning, out string rule)
{
rule = string.Empty;
var codeAttr = warning.Attribute("code");
if (codeAttr == null)
{
rule = null;
return true;
}
rule = codeAttr.Value;
return !string.IsNullOrWhiteSpace(rule);
}
/// <summary>
/// Determines the project for a warning logged in a MsBuild log.
/// </summary>
/// <param name="warning">Warning element from MsBuild log.</param>
/// <param name="repositorySettings">Repository settings to use.</param>
/// <param name="project">Returns project.</param>
/// <returns>True if the project could be parsed.</returns>
private bool TryGetProject(
XElement warning,
RepositorySettings repositorySettings,
out string project)
{
project = string.Empty;
var projectNode = warning.Ancestors("project").FirstOrDefault();
if (projectNode == null)
{
return true;
}
var projectAttr = projectNode.Attribute("file");
if (projectAttr == null)
{
return true;
}
project = projectAttr.Value;
if (string.IsNullOrWhiteSpace(project))
{
return true;
}
// Validate project path and make relative to repository root.
bool result;
(result, project) = this.ValidateFilePath(project, repositorySettings);
return result;
}
/// <summary>
/// Reads the affected file path from a warning logged in a MsBuild log.
/// </summary>
/// <param name="warning">Warning element from MsBuild log.</param>
/// <param name="repositorySettings">Repository settings to use.</param>
/// <param name="fileName">Returns the full path to the affected file.</param>
/// <returns>True if the file path could be parsed.</returns>
private bool TryGetFile(
XElement warning,
RepositorySettings repositorySettings,
out string fileName)
{
fileName = string.Empty;
var fileAttr = warning.Attribute("file");
if (fileAttr == null)
{
return true;
}
fileName = fileAttr.Value;
if (string.IsNullOrWhiteSpace(fileName))
{
return true;
}
// If not absolute path, combine with file path from compile task.
if (!fileName.IsFullPath())
{
var parentFileAttr = warning.Parent?.Attribute("file");
if (parentFileAttr != null)
{
var compileTaskDirectory = System.IO.Path.GetDirectoryName(parentFileAttr.Value);
fileName = System.IO.Path.Combine(compileTaskDirectory, fileName);
}
}
// Validate file path and make relative to repository root.
bool result;
(result, fileName) = this.ValidateFilePath(fileName, repositorySettings);
return result;
}
}
}