mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-02 13:22:11 +03:00
* fix(ci): raise the git ls-files buffer in check:tracked-artifacts `execFileSync` defaults to a 1 MiB stdout buffer and throws ENOBUFS past it. `git ls-files -s` on this repo is already at 1,042,494 bytes across 11,091 tracked files — 6,082 bytes from the ceiling. Any PR adding roughly sixty files crosses it. That matters more than a failing script: the check runs on pre-commit, so once the listing crosses 1 MiB, committing breaks for everyone working the repo, not just for the change that happened to cross it. It is not a hypothetical — the private EE fork hit it this week when a sync landed ~214 translation files and pushed the listing 504 bytes over; every commit there failed the hook until this same fix landed. Both call sites now share a GIT_LS_OPTS with a 64 MiB ceiling — far above any plausible tree, rather than just above today's, since the listing only grows. * docs(changelog): add fragment for #8844 Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
109 lines
3.8 KiB
JavaScript
109 lines
3.8 KiB
JavaScript
#!/usr/bin/env node
|
||
// scripts/check/check-tracked-artifacts.mjs
|
||
// Gate: falha se o git rastreia artefatos de build/artefatos gerados proibidos.
|
||
// Guarda contra `git add -A` acidental em worktrees que include node_modules symlinks.
|
||
// Incidente registrado 2× neste repo (v3.8.12 / v3.8.13) — Hard Rule #7 extensão.
|
||
//
|
||
// Artefatos proibidos:
|
||
// - node_modules/ — deps de build nunca devem entrar no repo
|
||
// - .next/ — output do build Next.js
|
||
// - coverage/ — relatórios de cobertura gerados pelo c8
|
||
// - quality-metrics.json — saída do collect-metrics.mjs (gerado, não-versionado)
|
||
// - symlinks rastreados (mode 120000) — indício de `git add -A` em worktree
|
||
|
||
import { execFileSync } from "node:child_process";
|
||
import { pathToFileURL } from "node:url";
|
||
|
||
const FORBIDDEN_PREFIXES = ["node_modules/", ".next/", "coverage/"];
|
||
const FORBIDDEN_EXACT = new Set([
|
||
"quality-metrics.json", // legacy root location (still forbidden if a stale run writes it)
|
||
"config/quality/quality-metrics.json", // current generated location (collect-metrics.mjs)
|
||
]);
|
||
|
||
/**
|
||
* Verifica se algum caminho na lista de arquivos rastreados corresponde a um
|
||
* artefato proibido. Também aceita uma lista separada de symlinks rastreados.
|
||
*
|
||
* @param {string[]} trackedFiles - saída de `git ls-files` (caminhos relativos)
|
||
* @param {string[]} trackedSymlinks - caminhos com mode 120000 (saída de git ls-files -s)
|
||
* @returns {string[]} lista de violações (strings descritivas)
|
||
*/
|
||
export function checkTrackedArtifacts(trackedFiles, trackedSymlinks = []) {
|
||
const violations = [];
|
||
|
||
for (const file of trackedFiles) {
|
||
if (FORBIDDEN_EXACT.has(file)) {
|
||
violations.push(`forbidden tracked artifact: ${file}`);
|
||
continue;
|
||
}
|
||
for (const prefix of FORBIDDEN_PREFIXES) {
|
||
if (file.startsWith(prefix)) {
|
||
violations.push(`forbidden tracked artifact (${prefix}*): ${file}`);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
for (const sym of trackedSymlinks) {
|
||
violations.push(`forbidden tracked symlink (mode 120000): ${sym}`);
|
||
}
|
||
|
||
return violations;
|
||
}
|
||
|
||
/**
|
||
* `execFileSync` defaults to a 1 MiB stdout buffer and throws ENOBUFS past it.
|
||
* This check runs on pre-commit, so crossing that line breaks committing for
|
||
* the whole repo, not just the change that crossed it. `git ls-files -s` is
|
||
* already at ~1.04 MB here and only grows, so the ceiling is set far above any
|
||
* plausible tree instead of just above today's.
|
||
*/
|
||
const GIT_LS_OPTS = { encoding: "utf8", maxBuffer: 64 * 1024 * 1024 };
|
||
|
||
function getTrackedFiles() {
|
||
const output = execFileSync("git", ["ls-files"], GIT_LS_OPTS);
|
||
return output
|
||
.split("\n")
|
||
.map((l) => l.trim())
|
||
.filter(Boolean);
|
||
}
|
||
|
||
function getTrackedSymlinks() {
|
||
// git ls-files -s prints: <mode> <hash> <stage>\t<path>
|
||
// mode 120000 = symlink
|
||
const output = execFileSync("git", ["ls-files", "-s"], GIT_LS_OPTS);
|
||
const symlinks = [];
|
||
for (const line of output.split("\n")) {
|
||
if (line.startsWith("120000")) {
|
||
const parts = line.split("\t");
|
||
if (parts[1]) symlinks.push(parts[1].trim());
|
||
}
|
||
}
|
||
return symlinks;
|
||
}
|
||
|
||
function main() {
|
||
const trackedFiles = getTrackedFiles();
|
||
const trackedSymlinks = getTrackedSymlinks();
|
||
const violations = checkTrackedArtifacts(trackedFiles, trackedSymlinks);
|
||
|
||
if (violations.length === 0) {
|
||
console.log("[tracked-artifacts] OK — no forbidden artifacts tracked by git");
|
||
process.exit(0);
|
||
}
|
||
|
||
console.error(
|
||
`[tracked-artifacts] FAIL — ${violations.length} forbidden artifact(s) tracked by git:`
|
||
);
|
||
for (const v of violations) {
|
||
console.error(` ✗ ${v}`);
|
||
}
|
||
console.error(
|
||
"\n → Run: git rm --cached <path> to untrack the artifact." +
|
||
"\n → Add the path to .gitignore to prevent re-tracking."
|
||
);
|
||
process.exit(1);
|
||
}
|
||
|
||
if (import.meta.url === pathToFileURL(process.argv[1] || "").href) main();
|