Merge branch 'main' into mocha-json

This commit is contained in:
Michal Dorner 2021-03-08 21:00:14 +01:00
commit 3768e4e756
No known key found for this signature in database
GPG key ID: 9EEE04B48DA36786
30 changed files with 14928 additions and 558 deletions

267
dist/index.js generated vendored
View file

@ -219,6 +219,7 @@ const get_annotations_1 = __nccwpck_require__(5867);
const get_report_1 = __nccwpck_require__(3737);
const dart_json_parser_1 = __nccwpck_require__(4528);
const dotnet_trx_parser_1 = __nccwpck_require__(2664);
const java_junit_parser_1 = __nccwpck_require__(676);
const jest_junit_parser_1 = __nccwpck_require__(1113);
const mocha_json_parser_1 = __nccwpck_require__(6043);
const path_utils_1 = __nccwpck_require__(4070);
@ -358,6 +359,8 @@ class TestReporter {
return new dotnet_trx_parser_1.DotnetTrxParser(options);
case 'flutter-json':
return new dart_json_parser_1.DartJsonParser(options, 'flutter');
case 'java-junit':
return new java_junit_parser_1.JavaJunitParser(options);
case 'jest-junit':
return new jest_junit_parser_1.JestJunitParser(options);
case 'mocha-json':
@ -673,6 +676,9 @@ class DotnetTrxParser {
}
getTestClasses(trx) {
var _a;
if (trx.TestRun.TestDefinitions === undefined || trx.TestRun.Results === undefined) {
return [];
}
const unitTests = {};
for (const td of trx.TestRun.TestDefinitions) {
for (const ut of td.UnitTest) {
@ -760,6 +766,206 @@ class DotnetTrxParser {
exports.DotnetTrxParser = DotnetTrxParser;
/***/ }),
/***/ 676:
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.JavaJunitParser = void 0;
const path = __importStar(__nccwpck_require__(5622));
const xml2js_1 = __nccwpck_require__(6189);
const path_utils_1 = __nccwpck_require__(4070);
const test_results_1 = __nccwpck_require__(2768);
class JavaJunitParser {
constructor(options) {
var _a;
this.options = options;
// Map to efficient lookup of all paths with given file name
this.trackedFiles = {};
for (const filePath of options.trackedFiles) {
const fileName = path.basename(filePath);
const files = (_a = this.trackedFiles[fileName]) !== null && _a !== void 0 ? _a : (this.trackedFiles[fileName] = []);
files.push(path_utils_1.normalizeFilePath(filePath));
}
}
async parse(filePath, content) {
const reportOrSuite = await this.getJunitReport(filePath, content);
const isReport = reportOrSuite.testsuites !== undefined;
// XML might contain:
// - multiple suites under <testsuites> root node
// - single <testsuite> as root node
let ju;
if (isReport) {
ju = reportOrSuite;
}
else {
// Make it behave the same way as if suite was inside <testsuites> root node
const suite = reportOrSuite.testsuite;
ju = {
testsuites: {
$: { time: suite.$.time },
testsuite: [suite]
}
};
}
return this.getTestRunResult(filePath, ju);
}
async getJunitReport(filePath, content) {
try {
return await xml2js_1.parseStringPromise(content);
}
catch (e) {
throw new Error(`Invalid XML at ${filePath}\n\n${e}`);
}
}
getTestRunResult(filePath, junit) {
const suites = junit.testsuites.testsuite === undefined
? []
: junit.testsuites.testsuite.map(ts => {
const name = ts.$.name.trim();
const time = parseFloat(ts.$.time) * 1000;
const sr = new test_results_1.TestSuiteResult(name, this.getGroups(ts), time);
return sr;
});
const time = parseFloat(junit.testsuites.$.time) * 1000;
return new test_results_1.TestRunResult(filePath, suites, time);
}
getGroups(suite) {
if (suite.testcase === undefined) {
return [];
}
const groups = [];
for (const tc of suite.testcase) {
// Normally classname is same as suite name - both refer to same Java class
// Therefore it doesn't make sense to process it as a group
// and tests will be added to default group with empty name
const className = tc.$.classname === suite.$.name ? '' : tc.$.classname;
let grp = groups.find(g => g.name === className);
if (grp === undefined) {
grp = { name: className, tests: [] };
groups.push(grp);
}
grp.tests.push(tc);
}
return groups.map(grp => {
const tests = grp.tests.map(tc => {
const name = tc.$.name.trim();
const result = this.getTestCaseResult(tc);
const time = parseFloat(tc.$.time) * 1000;
const error = this.getTestCaseError(tc);
return new test_results_1.TestCaseResult(name, result, time, error);
});
return new test_results_1.TestGroupResult(grp.name, tests);
});
}
getTestCaseResult(test) {
if (test.failure)
return 'failed';
if (test.skipped)
return 'skipped';
return 'success';
}
getTestCaseError(tc) {
if (!this.options.parseErrors || !tc.failure) {
return undefined;
}
const failure = tc.failure[0];
const details = failure._;
let filePath;
let line;
const src = this.exceptionThrowSource(details);
if (src) {
filePath = src.filePath;
line = src.line;
}
return {
path: filePath,
line,
details,
message: failure.message
};
}
exceptionThrowSource(stackTrace) {
const lines = stackTrace.split(/\r?\n/);
const re = /^at (.*)\((.*):(\d+)\)$/;
for (const str of lines) {
const match = str.match(re);
if (match !== null) {
const [_, tracePath, fileName, lineStr] = match;
const filePath = this.getFilePath(tracePath, fileName);
if (filePath !== undefined) {
const line = parseInt(lineStr);
return { filePath, line };
}
}
}
}
// Stacktrace in Java doesn't contain full paths to source file.
// There are only package, file name and line.
// Assuming folder structure matches package name (as it should in Java),
// we can try to match tracked file.
getFilePath(tracePath, fileName) {
// Check if there is any tracked file with given name
const files = this.trackedFiles[fileName];
if (files === undefined) {
return undefined;
}
// Remove class name and method name from trace.
// Take parts until first item with capital letter - package names are lowercase while class name is CamelCase.
const packageParts = tracePath.split(/\./g);
const packageIndex = packageParts.findIndex(part => part[0] <= 'Z');
if (packageIndex !== -1) {
packageParts.splice(packageIndex, packageParts.length - packageIndex);
}
if (packageParts.length === 0) {
return undefined;
}
// Get right file
// - file name matches
// - parent folders structure must reflect the package name
for (const filePath of files) {
const dirs = path.dirname(filePath).split(/\//g);
if (packageParts.length > dirs.length) {
continue;
}
// get only N parent folders, where N = length of package name parts
if (dirs.length > packageParts.length) {
dirs.splice(0, dirs.length - packageParts.length);
}
// check if parent folder structure matches package name
const isMatch = packageParts.every((part, i) => part === dirs[i]);
if (isMatch) {
return filePath;
}
}
return undefined;
}
}
exports.JavaJunitParser = JavaJunitParser;
/***/ }),
/***/ 1113:
@ -790,12 +996,14 @@ class JestJunitParser {
}
}
getTestRunResult(path, junit) {
const suites = junit.testsuites.testsuite.map(ts => {
const name = ts.$.name.trim();
const time = parseFloat(ts.$.time) * 1000;
const sr = new test_results_1.TestSuiteResult(name, this.getGroups(ts), time);
return sr;
});
const suites = junit.testsuites.testsuite === undefined
? []
: junit.testsuites.testsuite.map(ts => {
const name = ts.$.name.trim();
const time = parseFloat(ts.$.time) * 1000;
const sr = new test_results_1.TestSuiteResult(name, this.getGroups(ts), time);
return sr;
});
const time = parseFloat(junit.testsuites.$.time) * 1000;
return new test_results_1.TestRunResult(path, suites, time);
}
@ -1201,7 +1409,9 @@ function getSuitesReport(tr, runIndex, options) {
const icon = getResultIcon(tr.result);
sections.push(`## ${nameLink} ${icon}`);
const time = markdown_utils_1.formatTime(tr.time);
const headingLine2 = `**${tr.tests}** tests were completed in **${time}** with **${tr.passed}** passed, **${tr.failed}** failed and **${tr.skipped}** skipped.`;
const headingLine2 = tr.tests > 0
? `**${tr.tests}** tests were completed in **${time}** with **${tr.passed}** passed, **${tr.failed}** failed and **${tr.skipped}** skipped.`
: 'No tests found';
sections.push(headingLine2);
const suites = options.listSuites === 'failed' ? tr.failedSuites : tr.suites;
if (suites.length > 0) {
@ -1526,9 +1736,6 @@ function getCheckRunContext() {
if (!event.workflow_run) {
throw new Error("Event of type 'workflow_run' is missing 'workflow_run' field");
}
if (event.workflow_run.conclusion === 'cancelled') {
throw new Error(`Workflow run ${event.workflow_run.id} has been cancelled`);
}
return {
sha: event.workflow_run.head_commit.id,
runId: event.workflow_run.id
@ -1586,30 +1793,46 @@ async function downloadArtifact(octokit, artifactId, fileName, token) {
}
exports.downloadArtifact = downloadArtifact;
async function listFiles(octokit, sha) {
core.info('Fetching list of tracked files from GitHub');
const commit = await octokit.git.getCommit({
commit_sha: sha,
...github.context.repo
});
const files = await listGitTree(octokit, commit.data.tree.sha, '');
return files;
core.startGroup('Fetching list of tracked files from GitHub');
try {
const commit = await octokit.git.getCommit({
commit_sha: sha,
...github.context.repo
});
const files = await listGitTree(octokit, commit.data.tree.sha, '');
return files;
}
finally {
core.endGroup();
}
}
exports.listFiles = listFiles;
async function listGitTree(octokit, sha, path) {
const tree = await octokit.git.getTree({
const pathLog = path ? ` at ${path}` : '';
core.info(`Fetching tree ${sha}${pathLog}`);
let truncated = false;
let tree = await octokit.git.getTree({
recursive: 'true',
tree_sha: sha,
...github.context.repo
});
if (tree.data.truncated) {
truncated = true;
tree = await octokit.git.getTree({
tree_sha: sha,
...github.context.repo
});
}
const result = [];
for (const tr of tree.data.tree) {
const file = `${path}${tr.path}`;
if (tr.type === 'tree') {
if (tr.type === 'blob') {
result.push(file);
}
else if (tr.type === 'tree' && truncated) {
const files = await listGitTree(octokit, tr.sha, `${file}/`);
result.push(...files);
}
else {
result.push(file);
}
}
return result;
}

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long