pmdtester 1.6.2 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +12 -0
- data/.github/workflows/build.yml +7 -7
- data/.github/workflows/manual-integration-tests.yml +7 -7
- data/.github/workflows/publish-release.yml +9 -9
- data/.hoerc +1 -1
- data/.rubocop_todo.yml +1 -14
- data/.vscode/launch.json +32 -0
- data/History.md +47 -0
- data/Manifest.txt +13 -0
- data/README.rdoc +76 -30
- data/Rakefile +11 -11
- data/config/custom.jfc +1126 -0
- data/config/project-list-with-cpd.xml +268 -0
- data/config/projectlist_1_2_0.xsd +1 -1
- data/config/projectlist_1_3_0.xsd +53 -0
- data/lib/pmdtester/builders/cpd_project_hasher.rb +70 -0
- data/lib/pmdtester/builders/liquid_renderer.rb +111 -16
- data/lib/pmdtester/builders/pmd_report_builder.rb +133 -37
- data/lib/pmdtester/builders/project_hasher.rb +24 -25
- data/lib/pmdtester/builders/rule_set_builder.rb +2 -0
- data/lib/pmdtester/builders/summary_report_builder.rb +6 -1
- data/lib/pmdtester/cmd.rb +16 -7
- data/lib/pmdtester/cpd_report_diff.rb +99 -0
- data/lib/pmdtester/jfr_summary.rb +119 -0
- data/lib/pmdtester/location.rb +38 -0
- data/lib/pmdtester/parsers/cpd_report_document.rb +241 -0
- data/lib/pmdtester/parsers/options.rb +19 -0
- data/lib/pmdtester/parsers/pmd_report_document.rb +14 -1
- data/lib/pmdtester/parsers/projects_parser.rb +1 -1
- data/lib/pmdtester/pmd_branch_detail.rb +29 -9
- data/lib/pmdtester/pmd_report_detail.rb +54 -13
- data/lib/pmdtester/pmd_tester_utils.rb +45 -17
- data/lib/pmdtester/pmd_violation.rb +15 -6
- data/lib/pmdtester/project.rb +63 -3
- data/lib/pmdtester/report_diff.rb +5 -13
- data/lib/pmdtester/runner.rb +185 -37
- data/lib/pmdtester/system_info.rb +58 -0
- data/lib/pmdtester/word_differ.rb +132 -0
- data/lib/pmdtester.rb +8 -1
- data/pmdtester.gemspec +17 -17
- data/resources/css/pmd-tester.css +15 -0
- data/resources/js/project-report.js +293 -112
- data/resources/project_cpd_report.html +144 -0
- data/resources/project_diff_report.html +151 -18
- data/resources/project_index.html +12 -3
- data/resources/project_pmd_report.html +17 -2
- metadata +63 -43
|
@@ -1,32 +1,18 @@
|
|
|
1
1
|
/*
|
|
2
|
-
This is what's included in project_diff_report.html
|
|
3
|
-
to make the violation table work.
|
|
2
|
+
This is what's included in project_diff_report.html, project_pmd_report.html and project_cpd_report.html
|
|
3
|
+
to make the violation table and duplication table work.
|
|
4
4
|
|
|
5
|
-
It depends on the `
|
|
5
|
+
It depends on the `pmd_report` and `cpd_report` global vars, which is generated
|
|
6
6
|
in another JS file by LiquidProjectRenderer
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
$(document).ready(function () {
|
|
10
10
|
|
|
11
|
-
function makeCodeLink(violation) {
|
|
12
|
-
let template = project.source_link_template
|
|
13
|
-
template = template.replace('{file}', project.file_index[violation.f])
|
|
14
|
-
template = template.replace('{line}', violation.l);
|
|
15
|
-
return template
|
|
16
|
-
}
|
|
17
|
-
|
|
18
11
|
function extractFilename(path) {
|
|
19
12
|
const pathArray = path.split("/");
|
|
20
13
|
return pathArray[pathArray.length - 1];
|
|
21
14
|
}
|
|
22
15
|
|
|
23
|
-
function renderCodeSnippet(violation) {
|
|
24
|
-
var node = document.createElement('p');
|
|
25
|
-
var url = project.source_link_base + '/' + project.file_index[violation.f];
|
|
26
|
-
window.pmd_code_snippets.fetch(document, node, url, violation.l, makeCodeLink(violation));
|
|
27
|
-
return node;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
16
|
const cssClass = {
|
|
31
17
|
"+": "added",
|
|
32
18
|
"-": "removed",
|
|
@@ -39,109 +25,304 @@ $(document).ready(function () {
|
|
|
39
25
|
"~": "Changed",
|
|
40
26
|
}
|
|
41
27
|
|
|
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
|
-
searchPanes :{
|
|
84
|
-
orthogonal: {
|
|
85
|
-
'display': 'shortFile',
|
|
86
|
-
'search': undefined
|
|
87
|
-
}
|
|
88
|
-
},
|
|
89
|
-
targets: 0
|
|
28
|
+
function renderViolationsTable() {
|
|
29
|
+
const COLUMN_LINE = 0;
|
|
30
|
+
const COLUMN_LOCATION = 1;
|
|
31
|
+
const COLUMN_TYPE = 2;
|
|
32
|
+
const COLUMN_FILE = 3; // reference to file name in pmd_report.file_index
|
|
33
|
+
const COLUMN_RULE = 4; // reference to rule name in pmd_report.rule_index
|
|
34
|
+
const COLUMN_MESSAGE = 5;
|
|
35
|
+
const COLUMN_OLD_LOCATION = 6;
|
|
36
|
+
|
|
37
|
+
function makeCodeLink(violation) {
|
|
38
|
+
let template = pmd_report.source_link_template;
|
|
39
|
+
template = template.replace('{file}', pmd_report.file_index[violation[COLUMN_FILE]]);
|
|
40
|
+
template = template.replace('{line}', violation[COLUMN_LINE]);
|
|
41
|
+
return template;
|
|
42
|
+
}
|
|
43
|
+
function renderCodeSnippet(violation) {
|
|
44
|
+
var node = document.createElement('p');
|
|
45
|
+
var url = pmd_report.source_link_base + '/' + pmd_report.file_index[violation[COLUMN_FILE]];
|
|
46
|
+
window.pmd_code_snippets.fetch(document, node, url, violation[COLUMN_LINE], makeCodeLink(violation));
|
|
47
|
+
return node;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
var table = $('#violationsTable').DataTable({
|
|
51
|
+
data: pmd_report.violations,
|
|
52
|
+
columns: [
|
|
53
|
+
{"data": COLUMN_FILE},
|
|
54
|
+
{"data": COLUMN_RULE},
|
|
55
|
+
{"data": COLUMN_MESSAGE},
|
|
56
|
+
{"data": COLUMN_TYPE},
|
|
57
|
+
],
|
|
58
|
+
deferRender: true,
|
|
59
|
+
// scrollY: "6000px",
|
|
60
|
+
dom: 'Pfrtipl', // Search Panes, filtering input, processing display element, table, table information summary, pagination control, length changing input control
|
|
61
|
+
searchPanes: {
|
|
62
|
+
viewTotal: true,
|
|
63
|
+
cascadePanes: true,
|
|
64
|
+
columns: [0, 1, 3],
|
|
65
|
+
order: ['Rule', 'Location (click row to expand)', 'Type'],
|
|
66
|
+
threshold: 1 // always show filters in search pane (default: 0.6)
|
|
90
67
|
},
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
68
|
+
// scrollCollapse: true,
|
|
69
|
+
// paging: false,
|
|
70
|
+
columnDefs: [
|
|
71
|
+
{ //file column
|
|
72
|
+
render(data, type, row) {
|
|
73
|
+
let filepath = pmd_report.file_index[data];
|
|
74
|
+
// display only the file name (not full path), but use full
|
|
75
|
+
// path for sorting and such
|
|
76
|
+
if (type === "display") {
|
|
77
|
+
let line = row[COLUMN_LOCATION];
|
|
78
|
+
if (row[COLUMN_OLD_LOCATION] !== undefined) {
|
|
79
|
+
line = row[COLUMN_OLD_LOCATION] + "→" + line;
|
|
80
|
+
}
|
|
81
|
+
//note : target='_blank' requires that the link open in a new tab
|
|
82
|
+
return "<a href='" + makeCodeLink(row) + "' target='_blank' rel='noopener noreferrer'>" + extractFilename(filepath) + " @ line " + line + "</a>";
|
|
83
|
+
} else if (type === "sort") {
|
|
84
|
+
return filepath + "#" + row[COLUMN_LINE];
|
|
85
|
+
} else if (type === 'shortFile') {
|
|
86
|
+
return extractFilename(filepath);
|
|
87
|
+
} else {
|
|
88
|
+
return filepath;
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
searchPanes :{
|
|
92
|
+
orthogonal: {
|
|
93
|
+
'display': 'shortFile',
|
|
94
|
+
'search': undefined
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
targets: 0
|
|
99
98
|
},
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
99
|
+
{ // rule column
|
|
100
|
+
render(data, type, row) {
|
|
101
|
+
let rulename = pmd_report.rule_index[data];
|
|
102
|
+
if (type === "display")
|
|
103
|
+
return "<a href='#rule-summary-" + rulename + "'>" + rulename + "</a>"
|
|
104
|
+
else
|
|
105
|
+
return rulename;
|
|
106
|
+
},
|
|
107
|
+
searchPanes: {
|
|
108
|
+
orthogonal: {
|
|
109
|
+
'display' : 'sort' // do not use the display, which is an <a>
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
targets: 1
|
|
104
113
|
},
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
114
|
+
{ // type column
|
|
115
|
+
visible: false,
|
|
116
|
+
render(data, type, row) {
|
|
117
|
+
return type ==='display' ? typeDisplay[data] : cssClass[data]
|
|
118
|
+
},
|
|
119
|
+
targets: 3
|
|
111
120
|
},
|
|
112
|
-
|
|
121
|
+
],
|
|
122
|
+
displayLength: 25,
|
|
123
|
+
lengthMenu: [ [10, 20, 25, 50, 100, -1], [10, 20, 25, 50, 100, "All"] ],
|
|
124
|
+
rowCallback(row, data, index) {
|
|
125
|
+
$(row).addClass(cssClass[data[COLUMN_TYPE]]);
|
|
113
126
|
},
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
$('#violationsTable tbody').on('click', 'tr', function() {
|
|
130
|
+
// the event handler might be executed on "tr" elements in sub tables, such as
|
|
131
|
+
// code snippets or it might be a child-row (a tr, whose previous sibling has class dt-hasChild)
|
|
132
|
+
if (this.parentElement.parentElement.id !== 'violationsTable') {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (this.previousElementSibling !== null && this.previousElementSibling.classList.contains('dt-hasChild')) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
var tr = $(this);
|
|
140
|
+
var row = table.row( tr );
|
|
141
|
+
|
|
142
|
+
if ( row.child.isShown() ) {
|
|
143
|
+
// This row is already open - close it
|
|
144
|
+
row.child.hide();
|
|
145
|
+
tr.removeClass('shown');
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
// Open this row
|
|
149
|
+
row.child( renderCodeSnippet(row.data()) ).show();
|
|
150
|
+
tr.addClass('shown');
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
131
154
|
|
|
132
|
-
|
|
133
|
-
|
|
155
|
+
function renderDuplicationTable() {
|
|
156
|
+
const COLUMN_LOCATION = 0; // location array
|
|
157
|
+
const COLUMN_LOCATION_FILE = 0; // in the location array: reference to file name in cpd_report.file_index
|
|
158
|
+
const COLUMN_LOCATION_BEGIN_LINE = 1;
|
|
159
|
+
const COLUMN_LOCATION_END_LINE = 2;
|
|
160
|
+
const COLUMN_LOCATION_STRING = 3;
|
|
161
|
+
const COLUMN_LINES = 1;
|
|
162
|
+
const COLUMN_TOKENS = 2;
|
|
163
|
+
const COLUMN_CODEFRAGMENT = 3; // codefragment
|
|
164
|
+
const COLUMN_TYPE = 4; // type (+, -, ~)
|
|
165
|
+
const COLUMN_OLD_LINES = 5; // only for changed duplications
|
|
166
|
+
const COLUMN_OLD_TOKENS = 6; // only for changed duplications
|
|
167
|
+
const COLUMN_OLD_LOCATION = 7; // [array] only for changed duplications
|
|
134
168
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
169
|
+
function makeCodeLinkDuplication(firstDuplication) {
|
|
170
|
+
let template = cpd_report.source_link_template;
|
|
171
|
+
template = template.replace('{file}', cpd_report.file_index[firstDuplication[COLUMN_LOCATION_FILE]]);
|
|
172
|
+
template = template.replace('{line}', `${firstDuplication[COLUMN_LOCATION_BEGIN_LINE]}-L${firstDuplication[COLUMN_LOCATION_END_LINE]}`);
|
|
173
|
+
return template;
|
|
139
174
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
175
|
+
function renderCodeFragment(data) {
|
|
176
|
+
var node = document.createElement('p');
|
|
177
|
+
var innerHTML = `${data[COLUMN_LOCATION].length} locations:<br>`;
|
|
178
|
+
data[COLUMN_LOCATION].forEach(location => {
|
|
179
|
+
let url = makeCodeLinkDuplication(location);
|
|
180
|
+
innerHTML += `<a href="${url}" target="_blank" rel="noopener noreferrer">${url} @ line ${location[COLUMN_LOCATION_STRING]}</a><br>`;
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
if (data[COLUMN_OLD_LOCATION] !== undefined) {
|
|
184
|
+
innerHTML += `changed from ${data[COLUMN_OLD_LOCATION].length} previous locations:<br>`;
|
|
185
|
+
data[COLUMN_OLD_LOCATION].forEach(location => {
|
|
186
|
+
let url = makeCodeLinkDuplication(location);
|
|
187
|
+
innerHTML += `<a href="${url}" target="_blank" rel="noopener noreferrer">${url} @ line ${location[COLUMN_LOCATION_STRING]}</a><br>`;
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
if (data[COLUMN_OLD_LINES] !== undefined && data[COLUMN_OLD_TOKENS] !== undefined) {
|
|
191
|
+
innerHTML += `code fragment (lines: ${data[COLUMN_OLD_LINES]} → ${data[COLUMN_LINES]}, tokens: ${data[COLUMN_OLD_TOKENS]} → ${data[COLUMN_TOKENS]}):<br>`;
|
|
192
|
+
} else {
|
|
193
|
+
innerHTML += `code fragment (lines: ${data[COLUMN_LINES]}, tokens: ${data[COLUMN_TOKENS]}):<br>`;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
let table = document.createElement('table');
|
|
197
|
+
table.classList.add('code-snippet');
|
|
198
|
+
let tableBody = document.createElement('tbody');
|
|
199
|
+
table.appendChild(tableBody);
|
|
200
|
+
// line number of first location
|
|
201
|
+
let lineNumber = data[COLUMN_LOCATION][0][COLUMN_LOCATION_BEGIN_LINE];
|
|
202
|
+
data[COLUMN_CODEFRAGMENT].split('\n').forEach(line => {
|
|
203
|
+
let tableRow = document.createElement('tr');
|
|
204
|
+
let lineNumberColumn = document.createElement('td');
|
|
205
|
+
lineNumberColumn.classList.add('line-number');
|
|
206
|
+
tableRow.appendChild(lineNumberColumn);
|
|
207
|
+
let lineNumberElement = document.createElement('code');
|
|
208
|
+
lineNumberColumn.appendChild(lineNumberElement);
|
|
209
|
+
lineNumberElement.setAttribute('data-line-number', lineNumber);
|
|
210
|
+
|
|
211
|
+
let codeColumn = document.createElement('td');
|
|
212
|
+
tableRow.appendChild(codeColumn);
|
|
213
|
+
let codeElement = document.createElement("code");
|
|
214
|
+
codeColumn.appendChild(codeElement);
|
|
215
|
+
// createTextNode escapes special chars
|
|
216
|
+
codeElement.appendChild(document.createTextNode(line));
|
|
217
|
+
|
|
218
|
+
tableBody.appendChild(tableRow); // append row to the table
|
|
219
|
+
lineNumber++; // increment line number for each line
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
node.innerHTML = innerHTML + table.outerHTML;
|
|
223
|
+
return node;
|
|
144
224
|
}
|
|
145
|
-
|
|
225
|
+
|
|
226
|
+
var cpdTable = $('#duplicationsTable').DataTable({
|
|
227
|
+
data: cpd_report.duplications,
|
|
228
|
+
columns: [
|
|
229
|
+
{"data": COLUMN_LOCATION},
|
|
230
|
+
{"data": COLUMN_LINES},
|
|
231
|
+
{"data": COLUMN_TOKENS},
|
|
232
|
+
{"data": COLUMN_CODEFRAGMENT},
|
|
233
|
+
{"data": COLUMN_TYPE},
|
|
234
|
+
],
|
|
235
|
+
deferRender: true,
|
|
236
|
+
dom: 'Pfrtipl', // Search Panes, filtering input, processing display element, table, table information summary, pagination control, length changing input control
|
|
237
|
+
searchPanes: {
|
|
238
|
+
viewTotal: true,
|
|
239
|
+
cascadePanes: true,
|
|
240
|
+
columns: [0, 4],
|
|
241
|
+
order: ['Location (click row to expand)', 'Type'],
|
|
242
|
+
threshold: 1 // always show filters in search pane (default: 0.6)
|
|
243
|
+
},
|
|
244
|
+
columnDefs: [
|
|
245
|
+
{ // locations column
|
|
246
|
+
render(data, type, row) {
|
|
247
|
+
let first = data[0];
|
|
248
|
+
let firstPath = cpd_report.file_index[first[COLUMN_LOCATION_FILE]];
|
|
249
|
+
let firstLocation = first[COLUMN_LOCATION_STRING];
|
|
250
|
+
let firstFilename = extractFilename(firstPath);
|
|
251
|
+
if (type === "display") {
|
|
252
|
+
return "<a href='" + makeCodeLinkDuplication(first) + "' target='_blank' rel='noopener noreferrer'>" + firstFilename + " @ line " + firstLocation + "</a>" + (data.length > 1 ? " (and " + (data.length - 1) + " more)" : "");
|
|
253
|
+
} else if (type === "sort") {
|
|
254
|
+
return firstPath + "#" + first[COLUMN_LOCATION_END_LINE];
|
|
255
|
+
} else if (type === 'filter') {
|
|
256
|
+
return firstFilename;
|
|
257
|
+
} else if (type === 'shortFile') {
|
|
258
|
+
return firstFilename;
|
|
259
|
+
} else {
|
|
260
|
+
return data;
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
searchPanes :{
|
|
264
|
+
orthogonal: {
|
|
265
|
+
'display': 'shortFile',
|
|
266
|
+
'search': undefined
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
targets: 0
|
|
270
|
+
},
|
|
271
|
+
{ // codefragment column
|
|
272
|
+
render(data, type, row) {
|
|
273
|
+
if (type === "display") {
|
|
274
|
+
data = data.replace(/\r\n|\n/g, "\\n"); // replace newlines with \n for better display in the table
|
|
275
|
+
return data.length > 50 ? data.substring(0, 50) + "..." : data;
|
|
276
|
+
}
|
|
277
|
+
return data;
|
|
278
|
+
},
|
|
279
|
+
targets: 3
|
|
280
|
+
},
|
|
281
|
+
{ // type column
|
|
282
|
+
visible: false,
|
|
283
|
+
render(data, type, row) {
|
|
284
|
+
return type ==='display' ? typeDisplay[data] : cssClass[data]
|
|
285
|
+
},
|
|
286
|
+
targets: 4
|
|
287
|
+
},
|
|
288
|
+
],
|
|
289
|
+
displayLength: 25,
|
|
290
|
+
lengthMenu: [ [10, 20, 25, 50, 100, -1], [10, 20, 25, 50, 100, "All"] ],
|
|
291
|
+
rowCallback(row, data, index) {
|
|
292
|
+
$(row).addClass(cssClass[data[4]]);
|
|
293
|
+
},
|
|
294
|
+
});
|
|
295
|
+
$('#duplicationsTable tbody').on('click', 'tr', function() {
|
|
296
|
+
// the event handler might be executed on "tr" elements in sub tables, such as
|
|
297
|
+
// a child-row (a tr, whose previous sibling has class dt-hasChild)
|
|
298
|
+
if (this.parentElement.parentElement.id !== 'duplicationsTable') {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (this.previousElementSibling !== null && this.previousElementSibling.classList.contains('dt-hasChild')) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
var tr = $(this);
|
|
306
|
+
var row = cpdTable.row( tr );
|
|
307
|
+
|
|
308
|
+
if ( row.child.isShown() ) {
|
|
309
|
+
// This row is already open - close it
|
|
310
|
+
row.child.hide();
|
|
311
|
+
tr.removeClass('shown');
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
// Open this row
|
|
315
|
+
row.child( renderCodeFragment(row.data()) ).show();
|
|
316
|
+
tr.addClass('shown');
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if ($('#violationsTable').length > 0) {
|
|
322
|
+
renderViolationsTable();
|
|
323
|
+
}
|
|
324
|
+
if ($('#duplicationsTable').length > 0) {
|
|
325
|
+
renderDuplicationTable();
|
|
326
|
+
}
|
|
146
327
|
|
|
147
328
|
});
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>CPD Report for {{project_name}}</title>
|
|
6
|
+
|
|
7
|
+
<link rel="stylesheet" type="text/css" href="../css/bootstrap-5.3.0-alpha3.min.css"/>
|
|
8
|
+
<link rel="stylesheet" type="text/css" href="../css/datatables.min.css"/>
|
|
9
|
+
<link rel="stylesheet" type="text/css" href="../css/pmd-tester.css">
|
|
10
|
+
|
|
11
|
+
<script src="../js/jquery-3.6.4.slim.min.js"></script>
|
|
12
|
+
<script src="../js/popper-2.11.7.min.js"></script>
|
|
13
|
+
<script src="../js/bootstrap-5.3.0-alpha3.min.js"></script>
|
|
14
|
+
<script src="../js/datatables.min.js"></script>
|
|
15
|
+
<script src="../js/code-snippets.js"></script>
|
|
16
|
+
<!-- This is generated -->
|
|
17
|
+
<script src="./{{branch}}_cpd_data.js"></script>
|
|
18
|
+
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
<div class="section">
|
|
22
|
+
<h1>CPD Report for {{project_name}}</h1>
|
|
23
|
+
</div>
|
|
24
|
+
<div class="section">
|
|
25
|
+
<h2>Summary</h2>
|
|
26
|
+
<div class="section-content">
|
|
27
|
+
<table id="table-summary" class="table">
|
|
28
|
+
<thead>
|
|
29
|
+
<tr>
|
|
30
|
+
<th></th>
|
|
31
|
+
<th>{{branch | capitalize}}</th>
|
|
32
|
+
</tr>
|
|
33
|
+
</thead>
|
|
34
|
+
<tbody>
|
|
35
|
+
<tr>
|
|
36
|
+
<td class="item"><a href="#section-duplications">Duplications</a></td>
|
|
37
|
+
<td class="{{branch}}">{{cpd_report.duplication_counts}}</td>
|
|
38
|
+
</tr>
|
|
39
|
+
<tr>
|
|
40
|
+
<td class="item"><a href="#section-cpd-errors">CPD Errors</a></td>
|
|
41
|
+
<td class="{{branch}}">{{cpd_report.error_counts}}</td>
|
|
42
|
+
</tr>
|
|
43
|
+
<tr>
|
|
44
|
+
<td class="item">Execution time</td>
|
|
45
|
+
<td class="{{branch}}">{{cpd_report.execution_time}}</td>
|
|
46
|
+
</tr>
|
|
47
|
+
<tr>
|
|
48
|
+
<td class="item">Timestamp</td>
|
|
49
|
+
<td class="{{branch}}">{{cpd_report.timestamp}}</td>
|
|
50
|
+
</tr>
|
|
51
|
+
<tr>
|
|
52
|
+
<td class="item">Exit Code</td>
|
|
53
|
+
<td class="{{branch}}">{{cpd_report.exit_code}} <a href="{{branch}}_cpd_stdout.txt">stdout</a> | <a href="{{branch}}_cpd_stderr.txt">stderr</a></td>
|
|
54
|
+
</tr>
|
|
55
|
+
<tr>
|
|
56
|
+
<td class="item">Full Report</td>
|
|
57
|
+
<td class="{{branch}}"><a href="{{branch}}_cpd_report.xml">{{branch}}_cpd_report.xml</a></td>
|
|
58
|
+
</tr>
|
|
59
|
+
<tr>
|
|
60
|
+
<td class="item">JFR Recording</td>
|
|
61
|
+
<td class="{{branch}}"><a href="{{branch}}_cpd_recording.jfr">{{branch}}_cpd_recording.jfr</a></td>
|
|
62
|
+
</tr>
|
|
63
|
+
<tr>
|
|
64
|
+
<td class="item">JFR Details</td>
|
|
65
|
+
<td class="{{branch}}">
|
|
66
|
+
<details><summary>Details</summary>
|
|
67
|
+
Execution Time: {{cpd_report.jfr_summary.execution_time}}<br>
|
|
68
|
+
Max Heap Memory: {{cpd_report.jfr_summary.max_heap_memory}}<br>
|
|
69
|
+
Max CPU Load: {{cpd_report.jfr_summary.max_cpu_load}}<br>
|
|
70
|
+
Avg CPU Load: {{cpd_report.jfr_summary.avg_cpu_load}}<br>
|
|
71
|
+
</details>
|
|
72
|
+
</td>
|
|
73
|
+
</tr>
|
|
74
|
+
</tbody>
|
|
75
|
+
</table>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
<div class="section" id="section-duplications">
|
|
81
|
+
|
|
82
|
+
<h2>Duplications</h2>
|
|
83
|
+
|
|
84
|
+
<div class="section-content">
|
|
85
|
+
|
|
86
|
+
<table id="duplicationsTable" width="100%" class="table">
|
|
87
|
+
<thead>
|
|
88
|
+
<tr>
|
|
89
|
+
<th>Location (click row to expand)</th>
|
|
90
|
+
<th>Lines</th>
|
|
91
|
+
<th>Tokens</th>
|
|
92
|
+
<th>Code Fragment</th>
|
|
93
|
+
<th>Type</th>
|
|
94
|
+
</tr>
|
|
95
|
+
</thead>
|
|
96
|
+
</table>
|
|
97
|
+
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<div class="section" id="section-cpd-errors">
|
|
103
|
+
|
|
104
|
+
<h2>CPD Errors</h2>
|
|
105
|
+
|
|
106
|
+
<div class="section-content">
|
|
107
|
+
|
|
108
|
+
<div class="table-responsive">
|
|
109
|
+
<table id="cpd-error-table" class="table">
|
|
110
|
+
<thead>
|
|
111
|
+
<tr>
|
|
112
|
+
<th>File</th>
|
|
113
|
+
<th>Description (click to expand)</th>
|
|
114
|
+
</tr>
|
|
115
|
+
</thead>
|
|
116
|
+
<tbody>
|
|
117
|
+
{% for error in cpd_report.errors %}
|
|
118
|
+
<tr id="cpd-error-{{forloop.index}}" data-bs-toggle="collapse" data-bs-target="#cpd-error-{{forloop.index}}-expanded">
|
|
119
|
+
<td><a href="{{error.file_url}}" target="_blank" rel="noopener noreferrer">{{error.short_filename}}</a></td>
|
|
120
|
+
<td>{{error.short_message | escape | replace: error.filename, "<span class='meta-var'>$FILE</span>" }}</td>
|
|
121
|
+
</tr>
|
|
122
|
+
<tr>
|
|
123
|
+
<td class="row-hidden" colspan="2">
|
|
124
|
+
<div class="accordion-body collapse" id="cpd-error-{{forloop.index}}-expanded">
|
|
125
|
+
<div class="collapsed-content-padder">
|
|
126
|
+
<pre>
|
|
127
|
+
{{ error.stack_trace_html }}
|
|
128
|
+
</pre>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
</td>
|
|
132
|
+
</tr>
|
|
133
|
+
{% endfor %}
|
|
134
|
+
</tbody>
|
|
135
|
+
</table>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<script src="../js/project-report.js"></script>
|
|
142
|
+
|
|
143
|
+
</body>
|
|
144
|
+
</html>
|