Files
orca/config/scripts/check-flaky-test-pattern-ratchet.mjs
T
Blue DaydreamingandNeil b3089eef1d fix(scripts): preserve Git-quoted paths in ratchet checks (#34397)
Read git ls-files and git diff --name-only with -z so non-ASCII paths are
not C-quoted and still match ast-grep's real filenames; otherwise new
flaky-test findings in such files were silently dropped.

Fixes #34395

Co-authored-by: Neil <neil@stably.ai>
2026-10-27 09:48:41 -07:00

107 lines
3.6 KiB
JavaScript

import { execFileSync } from 'node:child_process'
import process from 'node:process'
import { pathToFileURL } from 'node:url'
import { baseRuleId, scanAstGrep } from './ast-grep-scan.mjs'
import { resolvePullRequestDiffBase } from './git-pull-request-diff-base.mjs'
import { listTrackedFiles, runCountRatchet } from './ratchet-baseline.mjs'
// Count each flaky-test rule per file so fixing one pattern cannot pay for adding another.
const BASELINE_PATH = 'config/flaky-test-pattern-baseline.txt'
const RULE_FILTER = '^test-'
const FLAKY_RULE = new RegExp(RULE_FILTER)
const HEADER = [
'# Flaky-test pattern findings per rule and file (config/ast-grep/rules/flaky-tests).',
'# This is a RATCHET: counts may only go DOWN. Run `pnpm lint:ast-grep:flaky-tests` to list them.',
'# Prune after a fix: pnpm check:flaky-test-pattern-ratchet --prune'
]
export function countFindings(matches, isTracked = () => true) {
const counts = new Map()
for (const match of matches) {
const file = match.file.split('\\').join('/')
if (!isTracked(file)) {
continue
}
const key = `${baseRuleId(match.ruleId)}:${file}`
counts.set(key, (counts.get(key) ?? 0) + 1)
}
return counts
}
/** `matches` may come from an unfiltered scan another gate shares; only `test-*` rules count. */
export function collectFlakyTestPatternCounts(root = process.cwd(), matches = undefined) {
// Tracked files only, so untracked scratch never changes the baseline.
const tracked = new Set(listTrackedFiles(root, []))
const flaky = (matches ?? scanAstGrep(root, { filter: RULE_FILTER })).filter((match) =>
FLAKY_RULE.test(match.ruleId)
)
return countFindings(flaky, (file) => tracked.has(file))
}
function git(root, args) {
return execFileSync('git', args, {
cwd: root,
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'ignore']
})
}
// Scope enforcement to changed files so unrelated merges cannot invalidate every PR's baseline.
export function listChangedFiles(root = process.cwd()) {
if (process.env.ORCA_FLAKY_TEST_RATCHET_ALL === '1') {
return null
}
let base
try {
const requested = process.env.ORCA_CODE_QUALITY_BASE || 'origin/main'
const mergeBase = git(root, ['merge-base', 'HEAD', requested]).trim()
base = resolvePullRequestDiffBase(root, mergeBase)
} catch {
try {
base = resolvePullRequestDiffBase(root, undefined)
} catch {
return null
}
}
if (!base) {
return null
}
const changed = git(root, ['diff', '--name-only', '--no-renames', '-z', base])
.split('\0')
.filter(Boolean)
return new Set(changed)
}
export function changedFileScope(changed) {
if (!changed) {
return undefined
}
return (key) => changed.has(key.slice(key.indexOf(':') + 1))
}
export function main(root = process.cwd(), arg = undefined, matches = undefined) {
return runCountRatchet(
{
name: 'flaky-test-pattern',
baselinePath: BASELINE_PATH,
header: HEADER,
collect: (dir) => collectFlakyTestPatternCounts(dir, matches),
scope: (dir) => changedFileScope(listChangedFiles(dir)),
unit: 'flaky-test finding(s)',
fix: [
'Wait on the condition (expect.poll, vi.waitFor, locator assertions) instead of sleeping or',
'polling, use fake timers or fixed timestamps instead of the wall clock, put',
'`// quarantine: #<issue> <reason>` above a skip, and a reason comment above a timeout bump.',
'A deliberate exception takes `// ast-grep-ignore: <rule-id> -- <reason>` above the line.'
]
},
root,
arg
)
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
process.exit(main(process.cwd(), process.argv[2]))
}