diff --git a/.github/workflows/test-litellm-ui-lint.yml b/.github/workflows/test-litellm-ui-lint.yml index 226cbf6a879a..5a5c4709ca21 100644 --- a/.github/workflows/test-litellm-ui-lint.yml +++ b/.github/workflows/test-litellm-ui-lint.yml @@ -85,7 +85,7 @@ jobs: if: ${{ !cancelled() && steps.changed.outputs.has_files == 'true' }} run: | npx eslint . -f json -o "$RUNNER_TEMP/lint-report.json" || true - node scripts/check-lint-budgets.mjs "$RUNNER_TEMP/lint-report.json" eslint-budgets.json --check eslint-metrics.json + node scripts/check-lint-budgets.mjs "$RUNNER_TEMP/lint-report.json" eslint-budgets.json - name: Check for dead code (knip) if: ${{ !cancelled() && steps.changed.outputs.has_files == 'true' }} diff --git a/scripts/pre_commit_lint.sh b/scripts/pre_commit_lint.sh index bd416ab814d0..d6b79f0111a7 100755 --- a/scripts/pre_commit_lint.sh +++ b/scripts/pre_commit_lint.sh @@ -75,19 +75,12 @@ EOF npx eslint --no-warn-ignored --pass-on-unpruned-suppressions "${eslint_rel[@]}" || rc=1 fi # Whole-folder lint budgets, exactly as the frontend-lint job runs them: the - # counts and the committed metrics file are not diff-scoped, so a local pass - # here means the budget step will pass in CI too. Unlike CI (which --checks and - # fails), regenerate eslint-metrics.json from the same report — same as the - # gen:api block below regenerates schema.d.ts — then flag drift so you re-stage - # it, instead of making you run npm run lint:metrics by hand. + # counts are not diff-scoped, so a local pass here means the budget step will + # pass in CI too. report=$(mktemp) npx eslint . -f json -o "$report" || true - node scripts/check-lint-budgets.mjs "$report" eslint-budgets.json --write eslint-metrics.json || rc=1 + node scripts/check-lint-budgets.mjs "$report" eslint-budgets.json || rc=1 rm -f "$report" - if ! git diff --quiet -- eslint-metrics.json; then - echo "✗ eslint-metrics.json was stale; regenerated it. Stage it and re-run make pre-commit." >&2 - rc=1 - fi exit $rc ) } diff --git a/ui/litellm-dashboard/eslint-metrics.json b/ui/litellm-dashboard/eslint-metrics.json deleted file mode 100644 index 8ae7dc88c3d2..000000000000 --- a/ui/litellm-dashboard/eslint-metrics.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "@typescript-eslint/no-explicit-any": 1971, - "complexity": 129, - "local/no-large-inline-object-arg": 501, - "local/no-long-condition-chain": 234, - "max-depth": 59, - "no-console": 16 -} diff --git a/ui/litellm-dashboard/package.json b/ui/litellm-dashboard/package.json index e35620c4996f..40c495cebf1f 100644 --- a/ui/litellm-dashboard/package.json +++ b/ui/litellm-dashboard/package.json @@ -8,7 +8,6 @@ "build": "next build", "start": "next start", "lint": "eslint .", - "lint:metrics": "node scripts/update-lint-metrics.mjs", "test": "vitest", "test:dot": "vitest --reporter=dot", "test:watch": "vitest -w", diff --git a/ui/litellm-dashboard/scripts/check-lint-budgets.mjs b/ui/litellm-dashboard/scripts/check-lint-budgets.mjs index db0842fb2ec5..3eec15a3a260 100644 --- a/ui/litellm-dashboard/scripts/check-lint-budgets.mjs +++ b/ui/litellm-dashboard/scripts/check-lint-budgets.mjs @@ -1,20 +1,7 @@ -import { readFileSync, writeFileSync } from "fs"; -import { countBudgetViolations, findDrift } from "./lint-budget-lib.mjs"; +import { readFileSync } from "fs"; +import { countBudgetViolations } from "./lint-budget-lib.mjs"; -const argv = process.argv.slice(2); -const positional = []; -const flags = {}; -for (let i = 0; i < argv.length; i += 1) { - if (argv[i] === "--check") { - flags.check = argv[(i += 1)]; - } else if (argv[i] === "--write") { - flags.write = argv[(i += 1)]; - } else { - positional.push(argv[i]); - } -} - -const [reportPath, budgetsPath] = positional; +const [reportPath, budgetsPath] = process.argv.slice(2); const report = JSON.parse(readFileSync(reportPath, "utf8")); const budgets = JSON.parse(readFileSync(budgetsPath, "utf8")); const counts = countBudgetViolations(report, budgets); @@ -32,25 +19,4 @@ for (const [rule, { max, target }] of Object.entries(budgets)) { } } -if (flags.write) { - writeFileSync(flags.write, JSON.stringify(counts, null, 2) + "\n"); - console.log(`Wrote ${flags.write}.`); -} - -if (flags.check) { - const committed = JSON.parse(readFileSync(flags.check, "utf8")); - const drift = findDrift(committed, counts); - for (const { rule, committed: was, actual } of drift) { - console.error( - `::error::${flags.check} is stale for ${rule}: committed ${was ?? "missing"}, actual ${actual ?? "not a tracked rule"}.`, - ); - } - if (drift.length > 0) { - console.error(`::error::Run \`npm run lint:metrics\` and commit ${flags.check}.`); - failed = true; - } else { - console.log(`${flags.check} is up to date.`); - } -} - process.exit(failed ? 1 : 0); diff --git a/ui/litellm-dashboard/scripts/lint-budget-lib.mjs b/ui/litellm-dashboard/scripts/lint-budget-lib.mjs index a43305fc4edc..9b32bb0d3a0c 100644 --- a/ui/litellm-dashboard/scripts/lint-budget-lib.mjs +++ b/ui/litellm-dashboard/scripts/lint-budget-lib.mjs @@ -13,10 +13,3 @@ export function countBudgetViolations(report, budgets) { .map((rule) => [rule, counts[rule] || 0]), ); } - -export function findDrift(committed, actual) { - const rules = [...new Set([...Object.keys(actual), ...Object.keys(committed)])].sort(); - return rules - .filter((rule) => committed[rule] !== actual[rule]) - .map((rule) => ({ rule, committed: committed[rule] ?? null, actual: actual[rule] ?? null })); -} diff --git a/ui/litellm-dashboard/scripts/update-lint-metrics.mjs b/ui/litellm-dashboard/scripts/update-lint-metrics.mjs deleted file mode 100644 index 16704d1f7a29..000000000000 --- a/ui/litellm-dashboard/scripts/update-lint-metrics.mjs +++ /dev/null @@ -1,25 +0,0 @@ -import { execSync } from "child_process"; -import { mkdtempSync, readFileSync, writeFileSync, rmSync } from "fs"; -import { tmpdir } from "os"; -import { join } from "path"; -import { countBudgetViolations } from "./lint-budget-lib.mjs"; - -const ESLINT_EXIT_LINT_ERRORS = 1; - -const budgets = JSON.parse(readFileSync("eslint-budgets.json", "utf8")); -const dir = mkdtempSync(join(tmpdir(), "litellm-lint-")); -const reportPath = join(dir, "report.json"); - -try { - execSync(`npx eslint . -f json -o "${reportPath}"`, { stdio: "inherit" }); -} catch (err) { - if (err.status !== ESLINT_EXIT_LINT_ERRORS) throw err; -} - -const report = JSON.parse(readFileSync(reportPath, "utf8")); -rmSync(dir, { recursive: true, force: true }); - -const metrics = countBudgetViolations(report, budgets); -writeFileSync("eslint-metrics.json", JSON.stringify(metrics, null, 2) + "\n"); -console.log("Updated eslint-metrics.json"); -console.table(metrics); diff --git a/ui/litellm-dashboard/tests/lint-budget-lib.test.ts b/ui/litellm-dashboard/tests/lint-budget-lib.test.ts index 75b5efe6d1de..c66cdd1e2abb 100644 --- a/ui/litellm-dashboard/tests/lint-budget-lib.test.ts +++ b/ui/litellm-dashboard/tests/lint-budget-lib.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from "vitest"; -import { countBudgetViolations, findDrift } from "../scripts/lint-budget-lib.mjs"; +import { countBudgetViolations } from "../scripts/lint-budget-lib.mjs"; const budgets = { "@typescript-eslint/no-explicit-any": { max: 10, target: 5 }, @@ -35,21 +35,3 @@ describe("countBudgetViolations", () => { ]); }); }); - -describe("findDrift", () => { - it("reports no drift when the snapshot matches the actual counts", () => { - expect(findDrift({ complexity: 5 }, { complexity: 5 })).toEqual([]); - }); - - it("detects a changed count", () => { - expect(findDrift({ complexity: 5 }, { complexity: 7 })).toEqual([{ rule: "complexity", committed: 5, actual: 7 }]); - }); - - it("detects a rule missing from the committed snapshot", () => { - expect(findDrift({}, { complexity: 7 })).toEqual([{ rule: "complexity", committed: null, actual: 7 }]); - }); - - it("detects a phantom rule the committed snapshot still carries", () => { - expect(findDrift({ "removed-rule": 3 }, {})).toEqual([{ rule: "removed-rule", committed: 3, actual: null }]); - }); -});