mirror of
https://github.com/stablyai/orca.git
synced 2026-10-24 00:04:01 +00:00
Make baseline regeneration discoverable and cover the CI guard
Drift failures are routine here: any PR that incidentally fixes an e2e or mobile type error trips the stale-entry check. Finding the fix meant opening the script to learn --write exists, so the failure now prints the exact regenerate command, and both packages expose it as a script. Resolve the env-supplied PR base against the repo root like the flag already was. Mobile CI runs with working-directory: mobile, so a repo-relative value would have resolved against the wrong directory. Cover the growth guard on the check path and the env form CI actually uses; both branches were previously exercised only through --write.
This commit is contained in:
@@ -136,6 +136,12 @@ function subtractDiagnostics(left, right) {
|
||||
})
|
||||
}
|
||||
|
||||
/** Failures here are routine, so the message carries its own fix. */
|
||||
function regenerationHint() {
|
||||
const argv = process.argv.slice(2).filter((value) => value !== '--write')
|
||||
return `Regenerate with: node ${relative(repoRoot, import.meta.filename)} ${argv.join(' ')} --write`
|
||||
}
|
||||
|
||||
function formatDiagnostic(diagnostic) {
|
||||
const location = diagnostic.file
|
||||
? `${diagnostic.file}:${diagnostic.line}:${diagnostic.column}`
|
||||
@@ -168,9 +174,9 @@ async function main() {
|
||||
const options = parseArgs(process.argv.slice(2))
|
||||
const projectPath = resolve(repoRoot, options.project)
|
||||
const baselinePath = resolve(repoRoot, options.baseline)
|
||||
const baseBaselinePath = options.baseBaseline
|
||||
? resolve(repoRoot, options.baseBaseline)
|
||||
: process.env.TYPECHECK_BASELINE_BASE_PATH
|
||||
// Resolve the env form like the flag: mobile runs with working-directory: mobile.
|
||||
const baseBaselineOption = options.baseBaseline ?? process.env.TYPECHECK_BASELINE_BASE_PATH
|
||||
const baseBaselinePath = baseBaselineOption ? resolve(repoRoot, baseBaselineOption) : undefined
|
||||
const tscPath = resolve(repoRoot, options.tsc ?? 'node_modules/typescript/bin/tsc')
|
||||
const diagnostics = collectDiagnostics(projectPath, tscPath)
|
||||
const baseBaseline = baseBaselinePath ? await readBaseline(baseBaselinePath) : null
|
||||
@@ -207,6 +213,7 @@ async function main() {
|
||||
console.error(formatDiagnostic(diagnostic))
|
||||
}
|
||||
}
|
||||
console.error(regenerationHint())
|
||||
process.exitCode = 1
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ function runBaseline(paths, extraArgs = [], spawnOptions = {}) {
|
||||
...extraArgs
|
||||
],
|
||||
{
|
||||
cwd: repoRoot,
|
||||
cwd: spawnOptions.cwd ?? repoRoot,
|
||||
encoding: 'utf8',
|
||||
env: { ...process.env, ...spawnOptions.env }
|
||||
}
|
||||
@@ -151,6 +151,80 @@ describe('typecheck diagnostic baseline', () => {
|
||||
expect(result.stdout).toContain('1 known diagnostics, no drift')
|
||||
})
|
||||
|
||||
it('rejects a committed baseline that grew from the PR base', () => {
|
||||
const paths = createFixture("const first: number = 'bad'\n")
|
||||
expect(runBaseline(paths, ['--write']).status).toBe(0)
|
||||
// Base knows only the first error; the committed baseline was raised to cover a second.
|
||||
const base = JSON.parse(readFileSync(paths.baseline, 'utf8'))
|
||||
writeFileSync(paths.baseBaseline, JSON.stringify(base))
|
||||
writeFileSync(paths.source, "const first: number = 'bad'\nconst second: boolean = 'also-bad'\n")
|
||||
expect(runBaseline(paths, ['--write', '--base-baseline', paths.baseBaseline]).status).toBe(1)
|
||||
writeFileSync(
|
||||
paths.baseline,
|
||||
JSON.stringify({
|
||||
version: 1,
|
||||
diagnostics: [
|
||||
...base.diagnostics,
|
||||
{
|
||||
file: 'source.ts',
|
||||
line: 2,
|
||||
column: 7,
|
||||
code: 2322,
|
||||
message: "Type 'string' is not assignable to type 'boolean'."
|
||||
}
|
||||
]
|
||||
})
|
||||
)
|
||||
|
||||
const check = runBaseline(paths, ['--base-baseline', paths.baseBaseline])
|
||||
|
||||
expect(check.status).toBe(1)
|
||||
expect(check.stderr).toContain('Diagnostic baseline grew (1)')
|
||||
})
|
||||
|
||||
it('reads the PR base from the environment the way CI passes it', () => {
|
||||
const paths = createFixture("const value: number = 'bad'\n")
|
||||
expect(runBaseline(paths, ['--write']).status).toBe(0)
|
||||
writeFileSync(paths.baseBaseline, JSON.stringify({ version: 1, diagnostics: [] }))
|
||||
|
||||
const result = runBaseline(paths, [], {
|
||||
env: { TYPECHECK_BASELINE_BASE_PATH: paths.baseBaseline }
|
||||
})
|
||||
|
||||
expect(result.status).toBe(1)
|
||||
expect(result.stderr).toContain('Diagnostic baseline grew (1)')
|
||||
})
|
||||
|
||||
it('resolves the env-supplied PR base against the repo, not the working directory', () => {
|
||||
// Mobile CI runs this with working-directory: mobile, so a repo-relative base
|
||||
// path must not resolve against the caller's cwd.
|
||||
const result = runBaseline(
|
||||
{
|
||||
project: 'config/tsconfig.e2e.json',
|
||||
baseline: 'config/typecheck-e2e-diagnostics.json'
|
||||
},
|
||||
[],
|
||||
{
|
||||
cwd: join(repoRoot, 'mobile'),
|
||||
env: { TYPECHECK_BASELINE_BASE_PATH: 'config/typecheck-e2e-diagnostics.json' }
|
||||
}
|
||||
)
|
||||
|
||||
expect(result.stderr).not.toContain('ENOENT')
|
||||
expect(result.status).toBe(0)
|
||||
})
|
||||
|
||||
it('names the regeneration command when the baseline drifts', () => {
|
||||
const paths = createFixture("const value: number = 'bad'\n")
|
||||
expect(runBaseline(paths, ['--write']).status).toBe(0)
|
||||
writeFileSync(paths.source, 'const value: number = 1\n')
|
||||
|
||||
const stale = runBaseline(paths)
|
||||
|
||||
expect(stale.status).toBe(1)
|
||||
expect(stale.stderr).toContain('--write')
|
||||
})
|
||||
|
||||
it('refuses to regenerate a baseline that grows from the PR base', () => {
|
||||
const paths = createFixture("const first: number = 'bad'\n")
|
||||
expect(runBaseline(paths, ['--write']).status).toBe(0)
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"postinstall": "node scripts/build-terminal-webview-engine.mjs && node scripts/build-mermaid-webview-engine.mjs",
|
||||
"test": "vitest run",
|
||||
"typecheck": "node ../config/scripts/typecheck-diagnostic-baseline.mjs --project mobile/tsconfig.json --baseline mobile/typecheck-test-diagnostics.json --tsc mobile/node_modules/typescript/bin/tsc",
|
||||
"typecheck:write": "node ../config/scripts/typecheck-diagnostic-baseline.mjs --project mobile/tsconfig.json --baseline mobile/typecheck-test-diagnostics.json --tsc mobile/node_modules/typescript/bin/tsc --write",
|
||||
"lint": "oxlint",
|
||||
"format": "oxfmt --write .",
|
||||
"format:check": "oxfmt --check .",
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
"typecheck:cli": "tsc --noEmit -p config/tsconfig.tc.cli.json",
|
||||
"typecheck:web": "tsc --noEmit -p config/tsconfig.tc.web.json",
|
||||
"typecheck:e2e": "node config/scripts/typecheck-diagnostic-baseline.mjs --project config/tsconfig.e2e.json --baseline config/typecheck-e2e-diagnostics.json",
|
||||
"typecheck:e2e:write": "node config/scripts/typecheck-diagnostic-baseline.mjs --project config/tsconfig.e2e.json --baseline config/typecheck-e2e-diagnostics.json --write",
|
||||
"typecheck": "node config/scripts/run-typecheck-projects-in-parallel.mjs",
|
||||
"typecheck:tsc:node": "tsc --noEmit -p config/tsconfig.node.json --composite false",
|
||||
"typecheck:tsc:cli": "tsc --noEmit -p config/tsconfig.cli.json --composite false",
|
||||
|
||||
Reference in New Issue
Block a user