-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathutils.js
123 lines (107 loc) · 4.5 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
const glob = require('@actions/glob');
const core = require('@actions/core');
const fs = require('fs');
const libxmljs = require("libxmljs");
const resolveFileAndLine = (file, classname, output, isFilenameInOutput) => {
// extract filename from classname and remove suffix
let filename;
let filenameWithPackage;
if (isFilenameInOutput) {
filename = output.split(':')[0].trim();
filenameWithPackage = filename
} else {
filename = file ? file : classname.split('.').slice(-1)[0].split('(')[0];
filenameWithPackage = classname.replace(/\./g, "/");
}
const matches = output.match(new RegExp(`${filename}.*?:\\d+`, 'g'));
if (!matches) return { filename: filename, filenameWithPackage: filenameWithPackage, line: 1 };
const [lastItem] = matches.slice(-1);
const [, line] = lastItem.split(':');
core.debug(`Resolved file ${filenameWithPackage} with name ${filename} and line ${line}`);
return { filename, filenameWithPackage, line: parseInt(line) };
};
const resolvePath = async filenameWithPackage => {
if (!filenameWithPackage) {
return '';
}
core.debug(`Resolving path for ${filenameWithPackage}`);
const globber = await glob.create([`**/${filenameWithPackage}.*`, `**/${filenameWithPackage}`].join('\n'), { 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__') && !r.endsWith('.class'));
if (found) path = found.slice(searchPath.length + 1);
else path = filenameWithPackage;
} else {
path = filenameWithPackage;
}
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, isFilenameInStackTrace) {
core.debug(`Parsing file ${file}`);
let count = 0;
let skipped = 0;
let annotations = [];
const data = await fs.promises.readFile(file);
const report = libxmljs.parseXml(data + "", {huge: true});
const testsuites = report.find('//testsuite');
for (const testsuite of testsuites) {
const testcases = testsuite.find('testcase');
for (const testcase of testcases) {
count++;
skipped += testcase.find('skipped').length;
let failures = testcase.find('failure | flakyFailure | error');
if (failures.length == 0) {
continue;
}
const stackTrace = failures.map(failure => failure.text()).join('').trim();
const message = (
failures.map(failure => failure.getAttribute('message')?.value()).join('') ||
stackTrace.split('\n').slice(0, 2).join('\n')
).trim();
const { filename, filenameWithPackage, line } = resolveFileAndLine(
testcase.getAttribute('file')?.value() || '',
testcase.getAttribute('classname')?.value() || '',
stackTrace,
isFilenameInStackTrace
);
const path = await resolvePath(filenameWithPackage);
const title = `${filename}.${testcase.getAttribute('name')?.value()}`;
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, isFilenameInStackTrace) => {
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, isFilenameInStackTrace);
if (c === 0) continue;
count += c;
skipped += s;
annotations = annotations.concat(a);
}
return { count, skipped, annotations };
};
module.exports = { resolveFileAndLine, resolvePath, parseFile, parseTestReports };