mirror of
https://github.com/dorny/test-reporter.git
synced 2025-12-17 06:47:09 +01:00
Tweak report
This commit is contained in:
parent
e1bf15b60e
commit
c032c9b993
4 changed files with 222 additions and 64 deletions
|
|
@ -70,6 +70,13 @@ inputs:
|
||||||
Detailed listing of test suites and test cases will be skipped.
|
Detailed listing of test suites and test cases will be skipped.
|
||||||
default: 'false'
|
default: 'false'
|
||||||
required: false
|
required: false
|
||||||
|
output-to:
|
||||||
|
description: |
|
||||||
|
The location to write the report to. Supported options:
|
||||||
|
- checks
|
||||||
|
- step-summary
|
||||||
|
default: 'step-summary'
|
||||||
|
required: false
|
||||||
token:
|
token:
|
||||||
description: GitHub Access Token
|
description: GitHub Access Token
|
||||||
required: false
|
required: false
|
||||||
|
|
|
||||||
125
dist/index.js
generated
vendored
125
dist/index.js
generated
vendored
|
|
@ -256,6 +256,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
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 crypto_1 = __nccwpck_require__(6113);
|
||||||
const artifact_provider_1 = __nccwpck_require__(7171);
|
const artifact_provider_1 = __nccwpck_require__(7171);
|
||||||
const local_file_provider_1 = __nccwpck_require__(9399);
|
const local_file_provider_1 = __nccwpck_require__(9399);
|
||||||
const get_annotations_1 = __nccwpck_require__(5867);
|
const get_annotations_1 = __nccwpck_require__(5867);
|
||||||
|
|
@ -267,7 +268,6 @@ const jest_junit_parser_1 = __nccwpck_require__(1113);
|
||||||
const mocha_json_parser_1 = __nccwpck_require__(6043);
|
const mocha_json_parser_1 = __nccwpck_require__(6043);
|
||||||
const path_utils_1 = __nccwpck_require__(4070);
|
const path_utils_1 = __nccwpck_require__(4070);
|
||||||
const github_utils_1 = __nccwpck_require__(3522);
|
const github_utils_1 = __nccwpck_require__(3522);
|
||||||
const markdown_utils_1 = __nccwpck_require__(6482);
|
|
||||||
function main() {
|
function main() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
try {
|
try {
|
||||||
|
|
@ -282,6 +282,15 @@ function main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function createSlugPrefix() {
|
||||||
|
const step_summary = process.env['GITHUB_STEP_SUMMARY'];
|
||||||
|
if (!step_summary || step_summary === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const hash = (0, crypto_1.createHash)('sha1');
|
||||||
|
hash.update(step_summary);
|
||||||
|
return hash.digest('hex').substring(0, 8);
|
||||||
|
}
|
||||||
class TestReporter {
|
class TestReporter {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.artifact = core.getInput('artifact', { required: false });
|
this.artifact = core.getInput('artifact', { required: false });
|
||||||
|
|
@ -296,7 +305,9 @@ class TestReporter {
|
||||||
this.workDirInput = core.getInput('working-directory', { required: false });
|
this.workDirInput = core.getInput('working-directory', { required: false });
|
||||||
this.buildDirInput = core.getInput('build-directory', { required: false });
|
this.buildDirInput = core.getInput('build-directory', { required: false });
|
||||||
this.onlySummary = core.getInput('only-summary', { required: false }) === 'true';
|
this.onlySummary = core.getInput('only-summary', { required: false }) === 'true';
|
||||||
|
this.outputTo = core.getInput('output-to', { required: false });
|
||||||
this.token = core.getInput('token', { required: true });
|
this.token = core.getInput('token', { required: true });
|
||||||
|
this.slugPrefix = '';
|
||||||
this.context = (0, github_utils_1.getCheckRunContext)();
|
this.context = (0, github_utils_1.getCheckRunContext)();
|
||||||
this.octokit = github.getOctokit(this.token);
|
this.octokit = github.getOctokit(this.token);
|
||||||
if (this.listSuites !== 'all' && this.listSuites !== 'failed') {
|
if (this.listSuites !== 'all' && this.listSuites !== 'failed') {
|
||||||
|
|
@ -311,6 +322,13 @@ class TestReporter {
|
||||||
core.setFailed(`Input parameter 'max-annotations' has invalid value`);
|
core.setFailed(`Input parameter 'max-annotations' has invalid value`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (this.outputTo !== 'checks' && this.outputTo !== 'step-summary') {
|
||||||
|
core.setFailed(`Input parameter 'output-to' has invalid value`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.outputTo === 'step-summary') {
|
||||||
|
this.slugPrefix = createSlugPrefix();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
run() {
|
run() {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
|
@ -376,6 +394,7 @@ class TestReporter {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
createReport(parser, name, files) {
|
createReport(parser, name, files) {
|
||||||
|
var _a, _b;
|
||||||
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}`);
|
||||||
|
|
@ -393,29 +412,82 @@ class TestReporter {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
core.info(`Creating check run ${name}`);
|
let createResp = null;
|
||||||
const createResp = yield this.octokit.rest.checks.create(Object.assign({ head_sha: this.context.sha, name, status: 'in_progress', output: {
|
let baseUrl = '';
|
||||||
title: name,
|
let check_run_id = 0;
|
||||||
summary: ''
|
switch (this.outputTo) {
|
||||||
} }, github.context.repo));
|
case 'checks': {
|
||||||
|
core.info(`Creating check run ${name}`);
|
||||||
|
createResp = yield this.octokit.rest.checks.create(Object.assign({ head_sha: this.context.sha, name, status: 'in_progress', output: {
|
||||||
|
title: name,
|
||||||
|
summary: ''
|
||||||
|
} }, github.context.repo));
|
||||||
|
baseUrl = (_a = createResp.data.html_url) !== null && _a !== void 0 ? _a : '';
|
||||||
|
check_run_id = createResp.data.id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'step-summary': {
|
||||||
|
const run_attempt = (_b = process.env['GITHUB_RUN_ATTEMPT']) !== null && _b !== void 0 ? _b : 1;
|
||||||
|
baseUrl = `https://github.com/${github.context.repo.owner}/${github.context.repo.repo}/actions/runs/${github.context.runId}/attempts/${run_attempt}`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
core.info('Creating report summary');
|
core.info('Creating report summary');
|
||||||
const { listSuites, listTests, onlySummary } = this;
|
const { listSuites, listTests, onlySummary, slugPrefix } = this;
|
||||||
const baseUrl = createResp.data.html_url;
|
const summary = (0, get_report_1.getReport)(results, { listSuites, listTests, baseUrl, slugPrefix, onlySummary });
|
||||||
const summary = (0, get_report_1.getReport)(results, { listSuites, listTests, baseUrl, onlySummary });
|
|
||||||
core.info('Creating annotations');
|
core.info('Creating annotations');
|
||||||
const annotations = (0, get_annotations_1.getAnnotations)(results, this.maxAnnotations);
|
const annotations = (0, get_annotations_1.getAnnotations)(results, this.maxAnnotations);
|
||||||
const isFailed = this.failOnError && results.some(tr => tr.result === 'failed');
|
const isFailed = this.failOnError && results.some(tr => tr.result === 'failed');
|
||||||
const conclusion = isFailed ? 'failure' : 'success';
|
const conclusion = isFailed ? 'failure' : 'success';
|
||||||
const icon = isFailed ? markdown_utils_1.Icon.fail : markdown_utils_1.Icon.success;
|
const passed = results.reduce((sum, tr) => sum + tr.passed, 0);
|
||||||
|
const failed = results.reduce((sum, tr) => sum + tr.failed, 0);
|
||||||
|
const skipped = results.reduce((sum, tr) => sum + tr.skipped, 0);
|
||||||
|
const shortSummary = `${passed} passed, ${failed} failed and ${skipped} skipped `;
|
||||||
core.info(`Updating check run conclusion (${conclusion}) and output`);
|
core.info(`Updating check run conclusion (${conclusion}) and output`);
|
||||||
const resp = yield this.octokit.rest.checks.update(Object.assign({ check_run_id: createResp.data.id, conclusion, status: 'completed', output: {
|
switch (this.outputTo) {
|
||||||
title: `${name} ${icon}`,
|
case 'checks': {
|
||||||
summary,
|
const resp = yield this.octokit.rest.checks.update(Object.assign({ check_run_id,
|
||||||
annotations
|
conclusion, status: 'completed', output: {
|
||||||
} }, github.context.repo));
|
title: shortSummary,
|
||||||
core.info(`Check run create response: ${resp.status}`);
|
summary,
|
||||||
core.info(`Check run URL: ${resp.data.url}`);
|
annotations
|
||||||
core.info(`Check run HTML: ${resp.data.html_url}`);
|
} }, github.context.repo));
|
||||||
|
core.info(`Check run create response: ${resp.status}`);
|
||||||
|
core.info(`Check run URL: ${resp.data.url}`);
|
||||||
|
core.info(`Check run HTML: ${resp.data.html_url}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'step-summary': {
|
||||||
|
core.summary.addRaw(`# ${shortSummary}`);
|
||||||
|
core.summary.addRaw(summary);
|
||||||
|
yield core.summary.write();
|
||||||
|
for (const annotation of annotations) {
|
||||||
|
let fn;
|
||||||
|
switch (annotation.annotation_level) {
|
||||||
|
case 'failure':
|
||||||
|
fn = core.error;
|
||||||
|
break;
|
||||||
|
case 'warning':
|
||||||
|
fn = core.warning;
|
||||||
|
break;
|
||||||
|
case 'notice':
|
||||||
|
fn = core.notice;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fn(annotation.message, {
|
||||||
|
title: annotation.title,
|
||||||
|
file: annotation.path,
|
||||||
|
startLine: annotation.start_line,
|
||||||
|
endLine: annotation.end_line,
|
||||||
|
startColumn: annotation.start_column,
|
||||||
|
endColumn: annotation.end_column
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
return results;
|
return results;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -1526,6 +1598,7 @@ const MAX_REPORT_LENGTH = 65535;
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
listSuites: 'all',
|
listSuites: 'all',
|
||||||
listTests: 'all',
|
listTests: 'all',
|
||||||
|
slugPrefix: '',
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
onlySummary: false
|
onlySummary: false
|
||||||
};
|
};
|
||||||
|
|
@ -1629,7 +1702,7 @@ function getTestRunsReport(testRuns, options) {
|
||||||
const tableData = testRuns.map((tr, runIndex) => {
|
const tableData = testRuns.map((tr, runIndex) => {
|
||||||
const time = (0, markdown_utils_1.formatTime)(tr.time);
|
const time = (0, markdown_utils_1.formatTime)(tr.time);
|
||||||
const name = tr.path;
|
const name = tr.path;
|
||||||
const addr = options.baseUrl + makeRunSlug(runIndex).link;
|
const addr = options.baseUrl + makeRunSlug(runIndex, options.slugPrefix).link;
|
||||||
const nameLink = (0, markdown_utils_1.link)(name, addr);
|
const nameLink = (0, markdown_utils_1.link)(name, addr);
|
||||||
const statusIcon = tr.failed > 0 ? markdown_utils_1.Icon.fail : tr.passed > 0 ? markdown_utils_1.Icon.success : markdown_utils_1.Icon.skip;
|
const statusIcon = tr.failed > 0 ? markdown_utils_1.Icon.fail : tr.passed > 0 ? markdown_utils_1.Icon.success : markdown_utils_1.Icon.skip;
|
||||||
const passed = tr.passed === 0 ? '' : tr.passed;
|
const passed = tr.passed === 0 ? '' : tr.passed;
|
||||||
|
|
@ -1648,7 +1721,7 @@ function getTestRunsReport(testRuns, options) {
|
||||||
}
|
}
|
||||||
function getSuitesReport(tr, runIndex, options) {
|
function getSuitesReport(tr, runIndex, options) {
|
||||||
const sections = [];
|
const sections = [];
|
||||||
const trSlug = makeRunSlug(runIndex);
|
const trSlug = makeRunSlug(runIndex, options.slugPrefix);
|
||||||
const nameLink = `<a id="${trSlug.id}" href="${options.baseUrl + trSlug.link}">${tr.path}</a>`;
|
const nameLink = `<a id="${trSlug.id}" href="${options.baseUrl + trSlug.link}">${tr.path}</a>`;
|
||||||
const icon = getResultIcon(tr.result);
|
const icon = getResultIcon(tr.result);
|
||||||
sections.push(`## ${icon}\xa0${nameLink}`);
|
sections.push(`## ${icon}\xa0${nameLink}`);
|
||||||
|
|
@ -1663,7 +1736,7 @@ function getSuitesReport(tr, runIndex, options) {
|
||||||
const tsTime = (0, markdown_utils_1.formatTime)(s.time);
|
const tsTime = (0, markdown_utils_1.formatTime)(s.time);
|
||||||
const tsName = s.name;
|
const tsName = s.name;
|
||||||
const skipLink = options.listTests === 'none' || (options.listTests === 'failed' && s.result !== 'failed');
|
const skipLink = options.listTests === 'none' || (options.listTests === 'failed' && s.result !== 'failed');
|
||||||
const tsAddr = options.baseUrl + makeSuiteSlug(runIndex, suiteIndex).link;
|
const tsAddr = options.baseUrl + makeSuiteSlug(runIndex, suiteIndex, options.slugPrefix).link;
|
||||||
const tsNameLink = skipLink ? tsName : (0, markdown_utils_1.link)(tsName, tsAddr);
|
const tsNameLink = skipLink ? tsName : (0, markdown_utils_1.link)(tsName, tsAddr);
|
||||||
const statusIcon = s.failed > 0 ? markdown_utils_1.Icon.fail : s.passed > 0 ? markdown_utils_1.Icon.success : markdown_utils_1.Icon.skip;
|
const statusIcon = s.failed > 0 ? markdown_utils_1.Icon.fail : s.passed > 0 ? markdown_utils_1.Icon.success : markdown_utils_1.Icon.skip;
|
||||||
const passed = s.passed === 0 ? '' : s.passed;
|
const passed = s.passed === 0 ? '' : s.passed;
|
||||||
|
|
@ -1692,7 +1765,7 @@ function getTestsReport(ts, runIndex, suiteIndex, options) {
|
||||||
}
|
}
|
||||||
const sections = [];
|
const sections = [];
|
||||||
const tsName = ts.name;
|
const tsName = ts.name;
|
||||||
const tsSlug = makeSuiteSlug(runIndex, suiteIndex);
|
const tsSlug = makeSuiteSlug(runIndex, suiteIndex, options.slugPrefix);
|
||||||
const tsNameLink = `<a id="${tsSlug.id}" href="${options.baseUrl + tsSlug.link}">${tsName}</a>`;
|
const tsNameLink = `<a id="${tsSlug.id}" href="${options.baseUrl + tsSlug.link}">${tsName}</a>`;
|
||||||
const icon = getResultIcon(ts.result);
|
const icon = getResultIcon(ts.result);
|
||||||
sections.push(`### ${icon}\xa0${tsNameLink}`);
|
sections.push(`### ${icon}\xa0${tsNameLink}`);
|
||||||
|
|
@ -1716,13 +1789,13 @@ function getTestsReport(ts, runIndex, suiteIndex, options) {
|
||||||
sections.push('```');
|
sections.push('```');
|
||||||
return sections;
|
return sections;
|
||||||
}
|
}
|
||||||
function makeRunSlug(runIndex) {
|
function makeRunSlug(runIndex, slugPrefix) {
|
||||||
// use prefix to avoid slug conflicts after escaping the paths
|
// use prefix to avoid slug conflicts after escaping the paths
|
||||||
return (0, slugger_1.slug)(`r${runIndex}`);
|
return (0, slugger_1.slug)(`r${slugPrefix}${runIndex}`);
|
||||||
}
|
}
|
||||||
function makeSuiteSlug(runIndex, suiteIndex) {
|
function makeSuiteSlug(runIndex, suiteIndex, slugPrefix) {
|
||||||
// use prefix to avoid slug conflicts after escaping the paths
|
// use prefix to avoid slug conflicts after escaping the paths
|
||||||
return (0, slugger_1.slug)(`r${runIndex}s${suiteIndex}`);
|
return (0, slugger_1.slug)(`r${slugPrefix}${runIndex}s${suiteIndex}`);
|
||||||
}
|
}
|
||||||
function getResultIcon(result) {
|
function getResultIcon(result) {
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
|
|
||||||
136
src/main.ts
136
src/main.ts
|
|
@ -1,5 +1,6 @@
|
||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import * as github from '@actions/github'
|
import * as github from '@actions/github'
|
||||||
|
import {createHash} from 'crypto'
|
||||||
import {GitHub} from '@actions/github/lib/utils'
|
import {GitHub} from '@actions/github/lib/utils'
|
||||||
|
|
||||||
import {ArtifactProvider} from './input-providers/artifact-provider'
|
import {ArtifactProvider} from './input-providers/artifact-provider'
|
||||||
|
|
@ -18,7 +19,6 @@ import {MochaJsonParser} from './parsers/mocha-json/mocha-json-parser'
|
||||||
|
|
||||||
import {normalizeDirPath, normalizeFilePath} from './utils/path-utils'
|
import {normalizeDirPath, normalizeFilePath} from './utils/path-utils'
|
||||||
import {getCheckRunContext} from './utils/github-utils'
|
import {getCheckRunContext} from './utils/github-utils'
|
||||||
import {Icon} from './utils/markdown-utils'
|
|
||||||
|
|
||||||
async function main(): Promise<void> {
|
async function main(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
|
|
@ -30,6 +30,16 @@ async function main(): Promise<void> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createSlugPrefix(): string {
|
||||||
|
const step_summary = process.env['GITHUB_STEP_SUMMARY']
|
||||||
|
if (!step_summary || step_summary === '') {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
const hash = createHash('sha1')
|
||||||
|
hash.update(step_summary)
|
||||||
|
return hash.digest('hex').substring(0, 8)
|
||||||
|
}
|
||||||
|
|
||||||
class TestReporter {
|
class TestReporter {
|
||||||
readonly artifact = core.getInput('artifact', {required: false})
|
readonly artifact = core.getInput('artifact', {required: false})
|
||||||
readonly name = core.getInput('name', {required: true})
|
readonly name = core.getInput('name', {required: true})
|
||||||
|
|
@ -43,7 +53,9 @@ class TestReporter {
|
||||||
readonly workDirInput = core.getInput('working-directory', {required: false})
|
readonly workDirInput = core.getInput('working-directory', {required: false})
|
||||||
readonly buildDirInput = core.getInput('build-directory', {required: false})
|
readonly buildDirInput = core.getInput('build-directory', {required: false})
|
||||||
readonly onlySummary = core.getInput('only-summary', {required: false}) === 'true'
|
readonly onlySummary = core.getInput('only-summary', {required: false}) === 'true'
|
||||||
|
readonly outputTo = core.getInput('output-to', {required: false})
|
||||||
readonly token = core.getInput('token', {required: true})
|
readonly token = core.getInput('token', {required: true})
|
||||||
|
readonly slugPrefix: string = ''
|
||||||
readonly octokit: InstanceType<typeof GitHub>
|
readonly octokit: InstanceType<typeof GitHub>
|
||||||
readonly context = getCheckRunContext()
|
readonly context = getCheckRunContext()
|
||||||
|
|
||||||
|
|
@ -64,6 +76,15 @@ class TestReporter {
|
||||||
core.setFailed(`Input parameter 'max-annotations' has invalid value`)
|
core.setFailed(`Input parameter 'max-annotations' has invalid value`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.outputTo !== 'checks' && this.outputTo !== 'step-summary') {
|
||||||
|
core.setFailed(`Input parameter 'output-to' has invalid value`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.outputTo === 'step-summary') {
|
||||||
|
this.slugPrefix = createSlugPrefix()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(): Promise<void> {
|
async run(): Promise<void> {
|
||||||
|
|
@ -164,45 +185,100 @@ class TestReporter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
core.info(`Creating check run ${name}`)
|
let createResp = null
|
||||||
const createResp = await this.octokit.rest.checks.create({
|
let baseUrl = ''
|
||||||
head_sha: this.context.sha,
|
let check_run_id = 0
|
||||||
name,
|
|
||||||
status: 'in_progress',
|
switch (this.outputTo) {
|
||||||
output: {
|
case 'checks': {
|
||||||
title: name,
|
core.info(`Creating check run ${name}`)
|
||||||
summary: ''
|
createResp = await this.octokit.rest.checks.create({
|
||||||
},
|
head_sha: this.context.sha,
|
||||||
...github.context.repo
|
name,
|
||||||
})
|
status: 'in_progress',
|
||||||
|
output: {
|
||||||
|
title: name,
|
||||||
|
summary: ''
|
||||||
|
},
|
||||||
|
...github.context.repo
|
||||||
|
})
|
||||||
|
baseUrl = createResp.data.html_url ?? ''
|
||||||
|
check_run_id = createResp.data.id
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'step-summary': {
|
||||||
|
const run_attempt = process.env['GITHUB_RUN_ATTEMPT'] ?? 1
|
||||||
|
baseUrl = `https://github.com/${github.context.repo.owner}/${github.context.repo.repo}/actions/runs/${github.context.runId}/attempts/${run_attempt}`
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
core.info('Creating report summary')
|
core.info('Creating report summary')
|
||||||
const {listSuites, listTests, onlySummary} = this
|
const {listSuites, listTests, onlySummary, slugPrefix} = this
|
||||||
const baseUrl = createResp.data.html_url as string
|
const summary = getReport(results, {listSuites, listTests, baseUrl, slugPrefix, onlySummary})
|
||||||
const summary = getReport(results, {listSuites, listTests, baseUrl, onlySummary})
|
|
||||||
|
|
||||||
core.info('Creating annotations')
|
core.info('Creating annotations')
|
||||||
const annotations = getAnnotations(results, this.maxAnnotations)
|
const annotations = getAnnotations(results, this.maxAnnotations)
|
||||||
|
|
||||||
const isFailed = this.failOnError && results.some(tr => tr.result === 'failed')
|
const isFailed = this.failOnError && results.some(tr => tr.result === 'failed')
|
||||||
const conclusion = isFailed ? 'failure' : 'success'
|
const conclusion = isFailed ? 'failure' : 'success'
|
||||||
const icon = isFailed ? Icon.fail : Icon.success
|
|
||||||
|
const passed = results.reduce((sum, tr) => sum + tr.passed, 0)
|
||||||
|
const failed = results.reduce((sum, tr) => sum + tr.failed, 0)
|
||||||
|
const skipped = results.reduce((sum, tr) => sum + tr.skipped, 0)
|
||||||
|
const shortSummary = `${passed} passed, ${failed} failed and ${skipped} skipped `
|
||||||
|
|
||||||
core.info(`Updating check run conclusion (${conclusion}) and output`)
|
core.info(`Updating check run conclusion (${conclusion}) and output`)
|
||||||
const resp = await this.octokit.rest.checks.update({
|
switch (this.outputTo) {
|
||||||
check_run_id: createResp.data.id,
|
case 'checks': {
|
||||||
conclusion,
|
const resp = await this.octokit.rest.checks.update({
|
||||||
status: 'completed',
|
check_run_id,
|
||||||
output: {
|
conclusion,
|
||||||
title: `${name} ${icon}`,
|
status: 'completed',
|
||||||
summary,
|
output: {
|
||||||
annotations
|
title: shortSummary,
|
||||||
},
|
summary,
|
||||||
...github.context.repo
|
annotations
|
||||||
})
|
},
|
||||||
core.info(`Check run create response: ${resp.status}`)
|
...github.context.repo
|
||||||
core.info(`Check run URL: ${resp.data.url}`)
|
})
|
||||||
core.info(`Check run HTML: ${resp.data.html_url}`)
|
core.info(`Check run create response: ${resp.status}`)
|
||||||
|
core.info(`Check run URL: ${resp.data.url}`)
|
||||||
|
core.info(`Check run HTML: ${resp.data.html_url}`)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'step-summary': {
|
||||||
|
core.summary.addRaw(`# ${shortSummary}`)
|
||||||
|
core.summary.addRaw(summary)
|
||||||
|
await core.summary.write()
|
||||||
|
for (const annotation of annotations) {
|
||||||
|
let fn
|
||||||
|
switch (annotation.annotation_level) {
|
||||||
|
case 'failure':
|
||||||
|
fn = core.error
|
||||||
|
break
|
||||||
|
case 'warning':
|
||||||
|
fn = core.warning
|
||||||
|
break
|
||||||
|
case 'notice':
|
||||||
|
fn = core.notice
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fn(annotation.message, {
|
||||||
|
title: annotation.title,
|
||||||
|
file: annotation.path,
|
||||||
|
startLine: annotation.start_line,
|
||||||
|
endLine: annotation.end_line,
|
||||||
|
startColumn: annotation.start_column,
|
||||||
|
endColumn: annotation.end_column
|
||||||
|
})
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ const MAX_REPORT_LENGTH = 65535
|
||||||
export interface ReportOptions {
|
export interface ReportOptions {
|
||||||
listSuites: 'all' | 'failed'
|
listSuites: 'all' | 'failed'
|
||||||
listTests: 'all' | 'failed' | 'none'
|
listTests: 'all' | 'failed' | 'none'
|
||||||
|
slugPrefix: string
|
||||||
baseUrl: string
|
baseUrl: string
|
||||||
onlySummary: boolean
|
onlySummary: boolean
|
||||||
}
|
}
|
||||||
|
|
@ -17,6 +18,7 @@ export interface ReportOptions {
|
||||||
const defaultOptions: ReportOptions = {
|
const defaultOptions: ReportOptions = {
|
||||||
listSuites: 'all',
|
listSuites: 'all',
|
||||||
listTests: 'all',
|
listTests: 'all',
|
||||||
|
slugPrefix: '',
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
onlySummary: false
|
onlySummary: false
|
||||||
}
|
}
|
||||||
|
|
@ -139,7 +141,7 @@ function getTestRunsReport(testRuns: TestRunResult[], options: ReportOptions): s
|
||||||
const tableData = testRuns.map((tr, runIndex) => {
|
const tableData = testRuns.map((tr, runIndex) => {
|
||||||
const time = formatTime(tr.time)
|
const time = formatTime(tr.time)
|
||||||
const name = tr.path
|
const name = tr.path
|
||||||
const addr = options.baseUrl + makeRunSlug(runIndex).link
|
const addr = options.baseUrl + makeRunSlug(runIndex, options.slugPrefix).link
|
||||||
const nameLink = link(name, addr)
|
const nameLink = link(name, addr)
|
||||||
const statusIcon = tr.failed > 0 ? Icon.fail : tr.passed > 0 ? Icon.success : Icon.skip
|
const statusIcon = tr.failed > 0 ? Icon.fail : tr.passed > 0 ? Icon.success : Icon.skip
|
||||||
const passed = tr.passed === 0 ? '' : tr.passed
|
const passed = tr.passed === 0 ? '' : tr.passed
|
||||||
|
|
@ -166,7 +168,7 @@ function getTestRunsReport(testRuns: TestRunResult[], options: ReportOptions): s
|
||||||
function getSuitesReport(tr: TestRunResult, runIndex: number, options: ReportOptions): string[] {
|
function getSuitesReport(tr: TestRunResult, runIndex: number, options: ReportOptions): string[] {
|
||||||
const sections: string[] = []
|
const sections: string[] = []
|
||||||
|
|
||||||
const trSlug = makeRunSlug(runIndex)
|
const trSlug = makeRunSlug(runIndex, options.slugPrefix)
|
||||||
const nameLink = `<a id="${trSlug.id}" href="${options.baseUrl + trSlug.link}">${tr.path}</a>`
|
const nameLink = `<a id="${trSlug.id}" href="${options.baseUrl + trSlug.link}">${tr.path}</a>`
|
||||||
const icon = getResultIcon(tr.result)
|
const icon = getResultIcon(tr.result)
|
||||||
sections.push(`## ${icon}\xa0${nameLink}`)
|
sections.push(`## ${icon}\xa0${nameLink}`)
|
||||||
|
|
@ -187,7 +189,7 @@ function getSuitesReport(tr: TestRunResult, runIndex: number, options: ReportOpt
|
||||||
const tsTime = formatTime(s.time)
|
const tsTime = formatTime(s.time)
|
||||||
const tsName = s.name
|
const tsName = s.name
|
||||||
const skipLink = options.listTests === 'none' || (options.listTests === 'failed' && s.result !== 'failed')
|
const skipLink = options.listTests === 'none' || (options.listTests === 'failed' && s.result !== 'failed')
|
||||||
const tsAddr = options.baseUrl + makeSuiteSlug(runIndex, suiteIndex).link
|
const tsAddr = options.baseUrl + makeSuiteSlug(runIndex, suiteIndex, options.slugPrefix).link
|
||||||
const tsNameLink = skipLink ? tsName : link(tsName, tsAddr)
|
const tsNameLink = skipLink ? tsName : link(tsName, tsAddr)
|
||||||
const statusIcon = s.failed > 0 ? Icon.fail : s.passed > 0 ? Icon.success : Icon.skip
|
const statusIcon = s.failed > 0 ? Icon.fail : s.passed > 0 ? Icon.success : Icon.skip
|
||||||
const passed = s.passed === 0 ? '' : s.passed
|
const passed = s.passed === 0 ? '' : s.passed
|
||||||
|
|
@ -222,7 +224,7 @@ function getTestsReport(ts: TestSuiteResult, runIndex: number, suiteIndex: numbe
|
||||||
const sections: string[] = []
|
const sections: string[] = []
|
||||||
|
|
||||||
const tsName = ts.name
|
const tsName = ts.name
|
||||||
const tsSlug = makeSuiteSlug(runIndex, suiteIndex)
|
const tsSlug = makeSuiteSlug(runIndex, suiteIndex, options.slugPrefix)
|
||||||
const tsNameLink = `<a id="${tsSlug.id}" href="${options.baseUrl + tsSlug.link}">${tsName}</a>`
|
const tsNameLink = `<a id="${tsSlug.id}" href="${options.baseUrl + tsSlug.link}">${tsName}</a>`
|
||||||
const icon = getResultIcon(ts.result)
|
const icon = getResultIcon(ts.result)
|
||||||
sections.push(`### ${icon}\xa0${tsNameLink}`)
|
sections.push(`### ${icon}\xa0${tsNameLink}`)
|
||||||
|
|
@ -251,14 +253,14 @@ function getTestsReport(ts: TestSuiteResult, runIndex: number, suiteIndex: numbe
|
||||||
return sections
|
return sections
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeRunSlug(runIndex: number): {id: string; link: string} {
|
function makeRunSlug(runIndex: number, slugPrefix: string): {id: string; link: string} {
|
||||||
// use prefix to avoid slug conflicts after escaping the paths
|
// use prefix to avoid slug conflicts after escaping the paths
|
||||||
return slug(`r${runIndex}`)
|
return slug(`r${slugPrefix}${runIndex}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeSuiteSlug(runIndex: number, suiteIndex: number): {id: string; link: string} {
|
function makeSuiteSlug(runIndex: number, suiteIndex: number, slugPrefix: string): {id: string; link: string} {
|
||||||
// use prefix to avoid slug conflicts after escaping the paths
|
// use prefix to avoid slug conflicts after escaping the paths
|
||||||
return slug(`r${runIndex}s${suiteIndex}`)
|
return slug(`r${slugPrefix}${runIndex}s${suiteIndex}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getResultIcon(result: TestExecutionResult): string {
|
function getResultIcon(result: TestExecutionResult): string {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue