openclaw/scripts/lib/check-limits.mts
Peter Steinberger 9ed5a04a65
ci: warn on size and performance limits in GitHub Actions
Source and performance budgets shared fatal exits with correctness checks,
so ordinary growth could block otherwise valid changes. Centralize limit
severity and GitHub annotations/summaries, keep local checks strict, and
carry warnings across native lint, container, and BuildKit boundaries.

Keep semantic lint, types, API inventories, source ownership, invalid
measurements, process failures, and runner admission guards blocking.

Validation: P2 review clean; three Linux owner-configuration replays and
20 standalone policy runs passed; typechecks, targeted type-aware lint,
Knip export scans, workflow checks, formatting, and diff checks passed.
The changed gate found a test environment typing error, corrected and
verified by the root-test typecheck. One unrelated preparation process
cleanup failure did not reproduce in its diagnostic replay; no fix claimed.
2026-09-23 02:35:32 -07:00

67 lines
2.2 KiB
TypeScript

import fs from "node:fs";
import { pathToFileURL } from "node:url";
export type LimitViolation = {
file: string;
title: string;
message: string;
line?: number;
};
export function limitsAreAdvisory(env: NodeJS.ProcessEnv = process.env) {
// Local check runners also set CI=1. Only GitHub Actions changes limit severity.
return env.GITHUB_ACTIONS === "true";
}
function escapeCommand(value: string, property = false) {
const escaped = value.replaceAll("%", "%25").replaceAll("\r", "%0D").replaceAll("\n", "%0A");
return property ? escaped.replaceAll(":", "%3A").replaceAll(",", "%2C") : escaped;
}
function summaryText(value: string) {
return value
.replaceAll("&", "&")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll("\r", " ")
.replaceAll("\n", " ");
}
/** Reports measured limit violations and returns whether they block this check. */
export function reportLimitViolations(
violations: readonly LimitViolation[],
env: NodeJS.ProcessEnv = process.env,
) {
const advisory = limitsAreAdvisory(env);
for (const { file, title, message, line = 1 } of violations) {
if (advisory) {
console.error(
`::warning file=${escapeCommand(file, true)},line=${line},col=0,title=${escapeCommand(title, true)}::${escapeCommand(message)}`,
);
} else {
console.error(`${title}\n ${file}: ${message}`);
}
}
if (advisory && violations.length > 0 && env.GITHUB_STEP_SUMMARY) {
fs.appendFileSync(
env.GITHUB_STEP_SUMMARY,
violations
.map(
({ file, title, message }) =>
`<p><strong>Warning: ${summaryText(title)}</strong> <code>${summaryText(file)}</code>: ${summaryText(message)}</p>\n`,
)
.join(""),
);
}
return !advisory && violations.length > 0;
}
if (process.argv[1] && pathToFileURL(process.argv[1]).href === import.meta.url) {
const [file, title, message, ...extra] = process.argv.slice(2);
if (!file || !title || !message || extra.length > 0) {
console.error("Usage: node scripts/lib/check-limits.mts <file> <title> <message>");
process.exitCode = 1;
} else {
process.exitCode = reportLimitViolations([{ file, title, message }]) ? 1 : 0;
}
}