fix(ci): address bot review feedback on policy guard and baseline generator

- Drive Tier B/C validation from each policy entry's validationCommand
  (falling back to nx test), skipping projects with an e2e target since
  the E2E workflow already runs them (Codex).
- Fail when a Tier A entry has no test target (Greptile, adapted:
  checking all entries against test targets would false-positive on the
  intentionally spec-less e2e/mock-server tiers).
- Guard against missing JSON array in nx show projects output (Greptile).
- Scan .tsx files in the max-lines baseline generator to match the
  ESLint rule's file patterns (Greptile).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Fable 5 committed 2026-07-02 00:49:44 +02:00
1 parent b0e5f292a1
commit bfd29e7561
4 files changed
+79 -27

No files matched your search

+2 -8
View File
@@ -70,14 +70,8 @@ jobs:
CI: true
NX_TASKS_RUNNER_DYNAMIC_OUTPUT: false
- name: Run Tier B/C unit tests without coverage
run: |
projects="$(node tools/coverage/check-coverage-policy.mjs --list-non-tier-a)"
if [ -n "$projects" ]; then
pnpm nx run-many --target=test --projects "$projects" --parallel=3 --output-style=static
else
echo "No Tier B/C projects with a test target."
fi
- name: Run Tier B/C validation commands
run: node tools/coverage/check-coverage-policy.mjs --run-non-tier-a
env:
CI: true
NX_TASKS_RUNNER_DYNAMIC_OUTPUT: false
+5 -3
View File
@@ -44,9 +44,11 @@ the baseline.
Use `tools/coverage/coverage-policy.json` as the source of truth for coverage
ownership. Every project with a `test` target must be classified in a tier;
`pnpm run coverage:policy:check` (part of `coverage:ci`) fails CI when a new
project is missing from the policy or a listed project no longer exists.
CI runs Tier A with coverage (uploaded to Codecov) and Tier B/C tests without
coverage.
project is missing from the policy, a listed project no longer exists, or a
Tier A entry has no test target. CI runs Tier A with coverage (uploaded to
Codecov) and each Tier B/C project's `validationCommand` (falling back to
`nx test`) without coverage; projects with an `e2e` target are skipped there
because the E2E workflow already runs them on every PR.
| Tier | Rule | Validation |
| --- | --- | --- |
+71 -15
View File
@@ -9,13 +9,16 @@
*
* Usage:
* node tools/coverage/check-coverage-policy.mjs
* Validate the policy. Exits non-zero on unclassified or stale entries.
* node tools/coverage/check-coverage-policy.mjs --list-non-tier-a
* Print a comma-separated list of Tier B/C projects that have a test
* target, for running them in CI without coverage.
* Validate the policy. Exits non-zero on unclassified projects, stale
* entries, or Tier A entries without a test target.
* node tools/coverage/check-coverage-policy.mjs --run-non-tier-a
* Run the validation command for each Tier B/C project. Uses the
* entry's `validationCommand` when present, falling back to
* `pnpm nx test <project>`. Projects with an `e2e` target are skipped
* because the E2E workflow already runs them on every PR.
*/
import { execFileSync } from 'node:child_process';
import { execFileSync, spawnSync } from 'node:child_process';
import { readFileSync } from 'node:fs';
import path from 'node:path';
import process from 'node:process';
@@ -36,11 +39,59 @@ function showProjects(extraArgs = []) {
['nx', 'show', 'projects', '--json', ...extraArgs],
{ cwd: workspaceRoot, encoding: 'utf8' }
);
return new Set(JSON.parse(output.slice(output.indexOf('['))));
const start = output.indexOf('[');
if (start === -1) {
throw new Error(
`nx show projects --json produced no JSON array.\nRaw output:\n${output}`
);
}
return new Set(JSON.parse(output.slice(start)));
}
const testProjects = showProjects(['--withTarget', 'test']);
const allProjects = showProjects();
const e2eProjects = showProjects(['--withTarget', 'e2e']);
function runNonTierA() {
let failed = false;
for (const project of [...tiers.tierB, ...tiers.tierC]) {
if (e2eProjects.has(project.name)) {
console.log(
`==> Skipping ${project.name}: covered by the E2E workflow.`
);
continue;
}
const command =
project.validationCommand ??
(testProjects.has(project.name)
? `pnpm nx test ${project.name}`
: null);
if (!command) {
console.log(
`==> Skipping ${project.name}: no validation command or test target.`
);
continue;
}
console.log(`\n==> Validating ${project.name}: ${command}`);
const result = spawnSync(command, {
cwd: workspaceRoot,
shell: true,
stdio: 'inherit',
});
if (result.status !== 0) {
failed = true;
}
}
process.exit(failed ? 1 : 0);
}
if (process.argv.includes('--run-non-tier-a')) {
runNonTierA();
}
const classified = new Map(
Object.entries(tiers).flatMap(([tier, projects]) =>
@@ -48,16 +99,11 @@ const classified = new Map(
)
);
if (process.argv.includes('--list-non-tier-a')) {
const nonTierA = [...tiers.tierB, ...tiers.tierC]
.map((project) => project.name)
.filter((name) => testProjects.has(name));
process.stdout.write(nonTierA.join(','));
process.exit(0);
}
const unclassified = [...testProjects].filter((name) => !classified.has(name));
const stale = [...classified.keys()].filter((name) => !allProjects.has(name));
const tierAWithoutTest = tiers.tierA
.map((project) => project.name)
.filter((name) => !testProjects.has(name));
if (unclassified.length > 0) {
console.error(
@@ -72,13 +118,23 @@ if (unclassified.length > 0) {
if (stale.length > 0) {
console.error(
'Coverage policy lists projects that no longer have a test target:\n' +
'Coverage policy lists projects that do not exist in the workspace:\n' +
stale.map((name) => ` - ${name}`).join('\n') +
'\n\nRemove them from tools/coverage/coverage-policy.json.'
);
process.exit(1);
}
if (tierAWithoutTest.length > 0) {
console.error(
'Tier A projects must have a test target, but these do not:\n' +
tierAWithoutTest.map((name) => ` - ${name}`).join('\n') +
'\n\nRestore the test target or move the project to Tier B/C in ' +
'tools/coverage/coverage-policy.json.'
);
process.exit(1);
}
console.log(
`Coverage policy OK: ${testProjects.size} test projects classified ` +
`(${tiers.tierA.length} Tier A, ${tiers.tierB.length} Tier B, ${tiers.tierC.length} Tier C).`
+1 -1
View File
@@ -25,7 +25,7 @@ function collectTsFiles(dir, results) {
collectTsFiles(path.join(dir, entry.name), results);
}
} else if (
entry.name.endsWith('.ts') &&
(entry.name.endsWith('.ts') || entry.name.endsWith('.tsx')) &&
!entry.name.endsWith('.d.ts')
) {
results.push(path.join(dir, entry.name));