forked from ScaCap/action-surefire-report
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutils.js
135 lines (118 loc) · 5.05 KB
/
utils.js
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
const glob = require('@actions/glob');
const core = require('@actions/core');
const fs = require('fs');
const parser = require('xml-js');
const resolveFileAndLine = (file, classname, output) => {
// extract filename from classname and remove suffix
const filename = file ? file : classname.split('.').slice(-1)[0].split('(')[0];
const matches = output.match(new RegExp(`${filename}.*?:\\d+`, 'g'));
if (!matches) return { filename: filename, line: 1 };
const [lastItem] = matches.slice(-1);
const [, line] = lastItem.split(':');
core.debug(`Resolved file ${filename} and line ${line}`);
return { filename, line: parseInt(line) };
};
const resolvePath = async filename => {
core.debug(`Resolving path for ${filename}`);
const globber = await glob.create(`**/${filename}.*`, { followSymbolicLinks: false });
const results = await globber.glob();
core.debug(`Matched files: ${results}`);
const searchPath = globber.getSearchPaths()[0];
let path = '';
if (results.length) {
// skip various temp folders
const found = results.find(r => !r.includes('__pycache__'));
if (found) path = found.slice(searchPath.length + 1);
else path = filename;
} else {
path = filename;
}
core.debug(`Resolved path: ${path}`);
// canonicalize to make windows paths use forward slashes
const canonicalPath = path.replace(/\\/g, '/');
core.debug(`Canonical path: ${canonicalPath}`);
return canonicalPath;
};
async function parseFile(file) {
core.debug(`Parsing file ${file}`);
let count = 0;
let skipped = 0;
let annotations = [];
const data = await fs.promises.readFile(file);
const report = JSON.parse(parser.xml2json(data, { compact: true }));
const testsuites = report.testsuite
? [report.testsuite]
: Array.isArray(report.testsuites.testsuite)
? report.testsuites.testsuite
: [report.testsuites.testsuite];
for (const testsuite of testsuites) {
const testcases = Array.isArray(testsuite.testcase)
? testsuite.testcase
: testsuite.testcase
? [testsuite.testcase]
: [];
for (const testcase of testcases) {
count++;
if (testcase.skipped) skipped++;
if (testcase.failure || testcase.flakyFailure || testcase.error) {
let testcaseData =
(testcase.failure && testcase.failure._cdata) ||
(testcase.failure && testcase.failure._text) ||
(testcase.flakyFailure && testcase.flakyFailure._cdata) ||
(testcase.flakyFailure && testcase.flakyFailure._text) ||
(testcase.error && testcase.error._cdata) ||
(testcase.error && testcase.error._text) ||
'';
testcaseData = Array.isArray(testcaseData) ? testcaseData : [testcaseData];
const stackTrace = (testcaseData.length ? testcaseData.join('') : '').trim();
const message = (
(testcase.failure &&
testcase.failure._attributes &&
testcase.failure._attributes.message) ||
(testcase.flakyFailure &&
testcase.flakyFailure._attributes &&
testcase.flakyFailure._attributes.message) ||
(testcase.error &&
testcase.error._attributes &&
testcase.error._attributes.message) ||
stackTrace.split('\n').slice(0, 2).join('\n')
).trim();
const { filename, line } = resolveFileAndLine(
testcase._attributes.file,
testcase._attributes.classname,
stackTrace
);
const path = await resolvePath(filename);
const title = `${filename}.${testcase._attributes.name}`;
core.info(`${path}:${line} | ${message.replace(/\n/g, ' ')}`);
annotations.push({
path,
start_line: line,
end_line: line,
start_column: 0,
end_column: 0,
annotation_level: 'failure',
title,
message,
raw_details: stackTrace
});
}
}
}
return { count, skipped, annotations };
}
const parseTestReports = async reportPaths => {
const globber = await glob.create(reportPaths, { followSymbolicLinks: false });
let annotations = [];
let count = 0;
let skipped = 0;
for await (const file of globber.globGenerator()) {
const { count: c, skipped: s, annotations: a } = await parseFile(file);
if (c == 0) continue;
count += c;
skipped += s;
annotations = annotations.concat(a);
}
return { count, skipped, annotations };
};
module.exports = { resolveFileAndLine, resolvePath, parseFile, parseTestReports };