mirror of
https://github.com/dorny/test-reporter.git
synced 2025-12-17 06:47:09 +01:00
feat: when failed to wrote the results, and having failed tests, make sure the build fails
This commit is contained in:
parent
39a2ecbea2
commit
a3bd4352e9
3 changed files with 94 additions and 14 deletions
49
dist/index.js
generated
vendored
49
dist/index.js
generated
vendored
|
|
@ -129,6 +129,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const github = __importStar(__nccwpck_require__(5438));
|
const github = __importStar(__nccwpck_require__(5438));
|
||||||
const local_file_provider_1 = __nccwpck_require__(9399);
|
const local_file_provider_1 = __nccwpck_require__(9399);
|
||||||
|
const test_results_1 = __nccwpck_require__(2768);
|
||||||
const get_annotations_1 = __nccwpck_require__(5867);
|
const get_annotations_1 = __nccwpck_require__(5867);
|
||||||
const get_report_1 = __nccwpck_require__(3737);
|
const get_report_1 = __nccwpck_require__(3737);
|
||||||
const dart_json_parser_1 = __nccwpck_require__(4528);
|
const dart_json_parser_1 = __nccwpck_require__(4528);
|
||||||
|
|
@ -236,13 +237,15 @@ class TestReporter {
|
||||||
try {
|
try {
|
||||||
core.startGroup(`Creating test report ${reportName}`);
|
core.startGroup(`Creating test report ${reportName}`);
|
||||||
const tr = yield this.createReport(parser, reportName, files);
|
const tr = yield this.createReport(parser, reportName, files);
|
||||||
results.push(...tr);
|
if (tr != null) {
|
||||||
|
results.push(tr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
core.endGroup();
|
core.endGroup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const isFailed = results.some(tr => tr.result === 'failed');
|
const isFailed = results.some(tr => tr.results.some(r => r.isFailed));
|
||||||
const conclusion = isFailed ? 'failure' : 'success';
|
const conclusion = isFailed ? 'failure' : 'success';
|
||||||
const passed = results.reduce((sum, tr) => sum + tr.passed, 0);
|
const passed = results.reduce((sum, tr) => sum + tr.passed, 0);
|
||||||
const failed = results.reduce((sum, tr) => sum + tr.failed, 0);
|
const failed = results.reduce((sum, tr) => sum + tr.failed, 0);
|
||||||
|
|
@ -253,6 +256,10 @@ class TestReporter {
|
||||||
core.setOutput('failed', failed);
|
core.setOutput('failed', failed);
|
||||||
core.setOutput('skipped', skipped);
|
core.setOutput('skipped', skipped);
|
||||||
core.setOutput('time', time);
|
core.setOutput('time', time);
|
||||||
|
if (results.some(r => r.shouldFail)) {
|
||||||
|
core.setFailed(`Failed test were found and the results could not be written to github, so fail this step.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (this.failOnError && isFailed) {
|
if (this.failOnError && isFailed) {
|
||||||
core.setFailed(`Failed test were found and 'fail-on-error' option is set to ${this.failOnError}`);
|
core.setFailed(`Failed test were found and 'fail-on-error' option is set to ${this.failOnError}`);
|
||||||
return;
|
return;
|
||||||
|
|
@ -267,10 +274,11 @@ class TestReporter {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
if (files.length === 0) {
|
if (files.length === 0) {
|
||||||
core.warning(`No file matches path ${this.path}`);
|
core.warning(`No file matches path ${this.path}`);
|
||||||
return [];
|
return null;
|
||||||
}
|
}
|
||||||
core.info(`Processing test results for check run ${name}`);
|
core.info(`Processing test results for check run ${name}`);
|
||||||
const results = [];
|
const results = [];
|
||||||
|
const result = new test_results_1.TestRunResultWithUrl(results, null);
|
||||||
for (const { file, content } of files) {
|
for (const { file, content } of files) {
|
||||||
try {
|
try {
|
||||||
core.info(`Processing test results from ${file}`);
|
core.info(`Processing test results from ${file}`);
|
||||||
|
|
@ -309,6 +317,7 @@ class TestReporter {
|
||||||
core.setOutput('url', resp.data.url);
|
core.setOutput('url', resp.data.url);
|
||||||
core.setOutput('url_html', resp.data.html_url);
|
core.setOutput('url_html', resp.data.html_url);
|
||||||
core.info(`Check run details: ${resp.data.details_url}`);
|
core.info(`Check run details: ${resp.data.details_url}`);
|
||||||
|
result.checkUrl = resp.data.html_url;
|
||||||
if (this.slackWebhook && this.context.branch === 'master') {
|
if (this.slackWebhook && this.context.branch === 'master') {
|
||||||
const webhook = new webhook_1.IncomingWebhook(this.slackWebhook);
|
const webhook = new webhook_1.IncomingWebhook(this.slackWebhook);
|
||||||
const passed = results.reduce((sum, tr) => sum + tr.passed, 0);
|
const passed = results.reduce((sum, tr) => sum + tr.passed, 0);
|
||||||
|
|
@ -343,7 +352,7 @@ class TestReporter {
|
||||||
catch (error) {
|
catch (error) {
|
||||||
core.error(`Could not create check to store the results`);
|
core.error(`Could not create check to store the results`);
|
||||||
}
|
}
|
||||||
return results;
|
return result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getParser(reporter, options) {
|
getParser(reporter, options) {
|
||||||
|
|
@ -1686,8 +1695,33 @@ function getResultIcon(result) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.TestCaseResult = exports.TestGroupResult = exports.TestSuiteResult = exports.TestRunResult = void 0;
|
exports.TestCaseResult = exports.TestGroupResult = exports.TestSuiteResult = exports.TestRunResult = exports.TestRunResultWithUrl = void 0;
|
||||||
const node_utils_1 = __nccwpck_require__(5824);
|
const node_utils_1 = __nccwpck_require__(5824);
|
||||||
|
class TestRunResultWithUrl {
|
||||||
|
constructor(results, checkUrl) {
|
||||||
|
this.results = results;
|
||||||
|
this.checkUrl = checkUrl;
|
||||||
|
}
|
||||||
|
get hasCheck() {
|
||||||
|
return !!this.checkUrl;
|
||||||
|
}
|
||||||
|
get shouldFail() {
|
||||||
|
return !this.hasCheck && this.results.some(r => r.isFailed);
|
||||||
|
}
|
||||||
|
get passed() {
|
||||||
|
return this.results.reduce((sum, g) => sum + g.passed, 0);
|
||||||
|
}
|
||||||
|
get failed() {
|
||||||
|
return this.results.reduce((sum, g) => sum + g.failed, 0);
|
||||||
|
}
|
||||||
|
get skipped() {
|
||||||
|
return this.results.reduce((sum, g) => sum + g.skipped, 0);
|
||||||
|
}
|
||||||
|
get time() {
|
||||||
|
return this.results.reduce((sum, g) => sum + g.time, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.TestRunResultWithUrl = TestRunResultWithUrl;
|
||||||
class TestRunResult {
|
class TestRunResult {
|
||||||
constructor(path, suites, totalTime) {
|
constructor(path, suites, totalTime) {
|
||||||
this.path = path;
|
this.path = path;
|
||||||
|
|
@ -1710,8 +1744,11 @@ class TestRunResult {
|
||||||
var _a;
|
var _a;
|
||||||
return (_a = this.totalTime) !== null && _a !== void 0 ? _a : this.suites.reduce((sum, g) => sum + g.time, 0);
|
return (_a = this.totalTime) !== null && _a !== void 0 ? _a : this.suites.reduce((sum, g) => sum + g.time, 0);
|
||||||
}
|
}
|
||||||
|
get isFailed() {
|
||||||
|
return this.suites.some(t => t.result === 'failed');
|
||||||
|
}
|
||||||
get result() {
|
get result() {
|
||||||
return this.suites.some(t => t.result === 'failed') ? 'failed' : 'success';
|
return this.isFailed ? 'failed' : 'success';
|
||||||
}
|
}
|
||||||
get failedSuites() {
|
get failedSuites() {
|
||||||
return this.suites.filter(s => s.result === 'failed');
|
return this.suites.filter(s => s.result === 'failed');
|
||||||
|
|
|
||||||
25
src/main.ts
25
src/main.ts
|
|
@ -5,7 +5,7 @@ import {GitHub} from '@actions/github/lib/utils'
|
||||||
import {LocalFileProvider} from './input-providers/local-file-provider'
|
import {LocalFileProvider} from './input-providers/local-file-provider'
|
||||||
import {FileContent} from './input-providers/input-provider'
|
import {FileContent} from './input-providers/input-provider'
|
||||||
import {ParseOptions, TestParser} from './test-parser'
|
import {ParseOptions, TestParser} from './test-parser'
|
||||||
import {TestRunResult} from './test-results'
|
import {TestRunResult, TestRunResultWithUrl} from './test-results'
|
||||||
import {getAnnotations} from './report/get-annotations'
|
import {getAnnotations} from './report/get-annotations'
|
||||||
import {getReport} from './report/get-report'
|
import {getReport} from './report/get-report'
|
||||||
|
|
||||||
|
|
@ -102,7 +102,7 @@ class TestReporter {
|
||||||
core.info(`Using test report parser '${this.reporter}'`)
|
core.info(`Using test report parser '${this.reporter}'`)
|
||||||
const parser = this.getParser(this.reporter, options)
|
const parser = this.getParser(this.reporter, options)
|
||||||
|
|
||||||
const results: TestRunResult[] = []
|
const results: TestRunResultWithUrl[] = []
|
||||||
const input = await inputProvider.load()
|
const input = await inputProvider.load()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -134,13 +134,15 @@ class TestReporter {
|
||||||
try {
|
try {
|
||||||
core.startGroup(`Creating test report ${reportName}`)
|
core.startGroup(`Creating test report ${reportName}`)
|
||||||
const tr = await this.createReport(parser, reportName, files)
|
const tr = await this.createReport(parser, reportName, files)
|
||||||
results.push(...tr)
|
if (tr != null) {
|
||||||
|
results.push(tr)
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
core.endGroup()
|
core.endGroup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isFailed = results.some(tr => tr.result === 'failed')
|
const isFailed = results.some(tr => tr.results.some(r => r.isFailed))
|
||||||
const conclusion = isFailed ? 'failure' : 'success'
|
const conclusion = isFailed ? 'failure' : 'success'
|
||||||
const passed = results.reduce((sum, tr) => sum + tr.passed, 0)
|
const passed = results.reduce((sum, tr) => sum + tr.passed, 0)
|
||||||
const failed = results.reduce((sum, tr) => sum + tr.failed, 0)
|
const failed = results.reduce((sum, tr) => sum + tr.failed, 0)
|
||||||
|
|
@ -153,6 +155,11 @@ class TestReporter {
|
||||||
core.setOutput('skipped', skipped)
|
core.setOutput('skipped', skipped)
|
||||||
core.setOutput('time', time)
|
core.setOutput('time', time)
|
||||||
|
|
||||||
|
if (results.some(r => r.shouldFail)) {
|
||||||
|
core.setFailed(`Failed test were found and the results could not be written to github, so fail this step.`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (this.failOnError && isFailed) {
|
if (this.failOnError && isFailed) {
|
||||||
core.setFailed(`Failed test were found and 'fail-on-error' option is set to ${this.failOnError}`)
|
core.setFailed(`Failed test were found and 'fail-on-error' option is set to ${this.failOnError}`)
|
||||||
return
|
return
|
||||||
|
|
@ -164,14 +171,17 @@ class TestReporter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async createReport(parser: TestParser, name: string, files: FileContent[]): Promise<TestRunResult[]> {
|
async createReport(parser: TestParser, name: string, files: FileContent[]): Promise<TestRunResultWithUrl | null> {
|
||||||
if (files.length === 0) {
|
if (files.length === 0) {
|
||||||
core.warning(`No file matches path ${this.path}`)
|
core.warning(`No file matches path ${this.path}`)
|
||||||
return []
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
core.info(`Processing test results for check run ${name}`)
|
core.info(`Processing test results for check run ${name}`)
|
||||||
|
|
||||||
const results: TestRunResult[] = []
|
const results: TestRunResult[] = []
|
||||||
|
const result: TestRunResultWithUrl = new TestRunResultWithUrl(results, null)
|
||||||
|
|
||||||
for (const {file, content} of files) {
|
for (const {file, content} of files) {
|
||||||
try {
|
try {
|
||||||
core.info(`Processing test results from ${file}`)
|
core.info(`Processing test results from ${file}`)
|
||||||
|
|
@ -226,6 +236,7 @@ class TestReporter {
|
||||||
core.setOutput('url', resp.data.url)
|
core.setOutput('url', resp.data.url)
|
||||||
core.setOutput('url_html', resp.data.html_url)
|
core.setOutput('url_html', resp.data.html_url)
|
||||||
core.info(`Check run details: ${resp.data.details_url}`)
|
core.info(`Check run details: ${resp.data.details_url}`)
|
||||||
|
result.checkUrl = resp.data.html_url
|
||||||
|
|
||||||
if (this.slackWebhook && this.context.branch === 'master') {
|
if (this.slackWebhook && this.context.branch === 'master') {
|
||||||
const webhook = new IncomingWebhook(this.slackWebhook)
|
const webhook = new IncomingWebhook(this.slackWebhook)
|
||||||
|
|
@ -264,7 +275,7 @@ class TestReporter {
|
||||||
core.error(`Could not create check to store the results`)
|
core.error(`Could not create check to store the results`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return results
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
getParser(reporter: string, options: ParseOptions): TestParser {
|
getParser(reporter: string, options: ParseOptions): TestParser {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,33 @@
|
||||||
import {DEFAULT_LOCALE} from './utils/node-utils'
|
import {DEFAULT_LOCALE} from './utils/node-utils'
|
||||||
|
|
||||||
|
export class TestRunResultWithUrl {
|
||||||
|
constructor(
|
||||||
|
public results: TestRunResult[],
|
||||||
|
public checkUrl: string | null
|
||||||
|
) {}
|
||||||
|
|
||||||
|
get hasCheck(): boolean {
|
||||||
|
return !!this.checkUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
get shouldFail(): boolean {
|
||||||
|
return !this.hasCheck && this.results.some(r => r.isFailed)
|
||||||
|
}
|
||||||
|
|
||||||
|
get passed(): number {
|
||||||
|
return this.results.reduce((sum, g) => sum + g.passed, 0)
|
||||||
|
}
|
||||||
|
get failed(): number {
|
||||||
|
return this.results.reduce((sum, g) => sum + g.failed, 0)
|
||||||
|
}
|
||||||
|
get skipped(): number {
|
||||||
|
return this.results.reduce((sum, g) => sum + g.skipped, 0)
|
||||||
|
}
|
||||||
|
get time(): number {
|
||||||
|
return this.results.reduce((sum, g) => sum + g.time, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class TestRunResult {
|
export class TestRunResult {
|
||||||
constructor(
|
constructor(
|
||||||
readonly path: string,
|
readonly path: string,
|
||||||
|
|
@ -25,8 +53,12 @@ export class TestRunResult {
|
||||||
return this.totalTime ?? this.suites.reduce((sum, g) => sum + g.time, 0)
|
return this.totalTime ?? this.suites.reduce((sum, g) => sum + g.time, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isFailed(): boolean {
|
||||||
|
return this.suites.some(t => t.result === 'failed')
|
||||||
|
}
|
||||||
|
|
||||||
get result(): TestExecutionResult {
|
get result(): TestExecutionResult {
|
||||||
return this.suites.some(t => t.result === 'failed') ? 'failed' : 'success'
|
return this.isFailed ? 'failed' : 'success'
|
||||||
}
|
}
|
||||||
|
|
||||||
get failedSuites(): TestSuiteResult[] {
|
get failedSuites(): TestSuiteResult[] {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue