Files
orca/config/scripts/ci-e2e-failure-summary.mjs
T
Neil 9179b93ebf ci: reduce repeated runner work and validate affected-test selection (#23540)
* ci: stage heavy checks and measure affected-test selection

* fix(ci): exercise the real Git boundary in unit selection planning

* Harden review cancellation and CI demand reporting
2026-09-27 23:25:20 -07:00

93 lines
3.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { appendFileSync, readFileSync } from 'node:fs'
import { pathToFileURL } from 'node:url'
import { trackE2eFailures } from './ci-e2e-failure-tracking.mjs'
export function e2eFailureSummary(report) {
const failures = []
let passed = 0
let skipped = 0
function visit(suite, parents = [], parentFile) {
const titles = [...parents, suite.title].filter(Boolean)
const file = suite.file ?? parentFile
for (const spec of suite.specs ?? []) {
for (const test of spec.tests ?? []) {
if (test.status === 'expected') {
passed++
continue
}
if (test.status === 'skipped') {
skipped++
continue
}
const errors = test.results.flatMap((result) => result.errors ?? [])
failures.push({
file: spec.file ?? file,
title: [...titles, spec.title].join(' › '),
project: test.projectName,
status: test.status,
message: errors
.map((error) => error.message ?? error.value ?? '')
.join('\n')
.slice(0, 2000)
})
}
}
for (const child of suite.suites ?? []) {
visit(child, titles, file)
}
}
for (const suite of report.suites ?? []) {
visit(suite)
}
return { passed, skipped, failures, errors: report.errors ?? [] }
}
export function renderE2eFailures(summary, records = [], now = new Date()) {
const escape = (value) =>
String(value ?? '')
.replaceAll('&', '&')
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;')
const tracked = trackE2eFailures(summary.failures, records, now)
const details = (failure) =>
`<details><summary>${escape(failure.status)}: ${escape(failure.file)} — ${escape(failure.title)}</summary><pre>${escape(failure.message)}</pre></details>`
return [
'## E2E results',
'',
`${summary.passed} expected results; ${summary.skipped} skipped; ${summary.failures.length} unexpected/flaky results; ${summary.errors.length} run errors.`,
'',
`### Untracked failures (${tracked.untracked.length})`,
'',
...tracked.untracked.map(details),
'',
`### Tracked failures (${tracked.known.length})`,
'',
...tracked.known.flatMap((failure) => [
details(failure),
`Owner: ${escape(failure.tracking.owner)}; ${escape(failure.tracking.issue)}; expires ${escape(failure.tracking.expires)}.`
]),
...(tracked.invalid.length
? [`${tracked.invalid.length} invalid/expired tracking entries were not used.`]
: []),
...summary.errors.map((error) => `<pre>${escape(error.message ?? error.value)}</pre>`),
'',
'Failures retain their original verdict. Repeated failures need a tracked owner, reproduction and review date; do not treat a red baseline as passing.',
''
].join('\n')
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
try {
const summary = e2eFailureSummary(JSON.parse(readFileSync(process.argv[2], 'utf8')))
const records = JSON.parse(
readFileSync(new URL('../e2e-failure-tracking.json', import.meta.url), 'utf8')
)
appendFileSync(process.env.GITHUB_STEP_SUMMARY, renderE2eFailures(summary, records))
} catch (error) {
appendFileSync(
process.env.GITHUB_STEP_SUMMARY,
`E2E report unavailable (${error.code ?? 'invalid report'}); inspect the failing step and traces.\n`
)
}
}