mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
ci(server): lint:warnings holds the ESLint warnings per rule to a baseline
Server lint ran without --max-warnings or a baseline, so the rules left on warn could grow without limit. lint:warnings runs ESLint with the server's own config through the shared tally, fails on any error or inline rule config, and holds the warnings per rule for src, tests and eslint-disable'd messages to scripts/eslint-baseline.json, which only falls. It replaces lint:check in CI. no-await-in-loop, no-non-null-assertion and no-console come in as warnings held at today's counts. npm run lint no longer rewrites files; lint:fix does.
This commit is contained in:
@@ -252,11 +252,13 @@ jobs:
|
||||
run: cd server && npm run check:db-types
|
||||
|
||||
- name: Lint
|
||||
# Type-aware rules build the src + tests program, which outgrows
|
||||
# Node's default ~4 GB heap on the runner.
|
||||
# Errors fail, and the warnings per rule may not pass
|
||||
# scripts/eslint-baseline.json (src, tests and eslint-disable'd
|
||||
# messages counted apart). Type-aware rules build the src + tests
|
||||
# program, which outgrows Node's default ~4 GB heap on the runner.
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=8192
|
||||
run: cd server && npm run lint:check
|
||||
run: cd server && npm run lint:warnings
|
||||
|
||||
- name: DB call-graph gate (no sync DB-touching methods, no raw transactions)
|
||||
run: cd server && npm run db:call-graph -- --sync --tx
|
||||
|
||||
@@ -39,6 +39,7 @@ cd client && npm run lint:dup # lines in copied code may on
|
||||
cd client && npm run lint:pairs # desktop and phone views of a feature import its shared hook; every phone screen is listed (CI gate)
|
||||
cd client && npm run lint:size # no source file past 1000 lines, longer ones only shrink (CI gate; server has the same)
|
||||
cd client && npm run lint:warnings # eslint errors fail, warnings per rule may only shrink (CI gate)
|
||||
cd server && npm run lint:warnings # the same for the server, against server/scripts/eslint-baseline.json (CI gate)
|
||||
cd client && npm run lint:format # Prettier outside the baseline list (CI gate)
|
||||
cd client && npm run lint:layers # components never import pages/ or mobile/ (CI gate)
|
||||
cd client && npm run lint:offline # views may not import src/api/ beyond the baseline (CI gate)
|
||||
@@ -123,7 +124,7 @@ These principles come out of a full-repo audit and shape all new code:
|
||||
|
||||
## Quality gates in CI
|
||||
|
||||
`.github/workflows/test.yml` runs, per package: typecheck (server also `typecheck:tests`), lint (client through `lint:warnings`, which also holds the warning count per rule), `lint:pages`, `lint:rtl`, `lint:size` (client and server), the server's `lint:boundaries`, `lint:tx`, `lint:dialect` and `lint:test-sql`, the client's `lint:format`, `lint:layers`, `lint:offline`, `lint:dup`, `lint:pairs`, `lint:skips` and `lint:i18n-keys`, shared's `contracts:open`, `check:plugin-facts`, `i18n:parity:strict` (with the untranslated-strings ratchet), the S3 contract suite, the Postgres probe (`postgres-probe`: every dialect helper on SQLite and Postgres, and the statements every repository method reaches with sample arguments against a Postgres service; the SQL errors per method and the list of methods it cannot measure are held to a baseline that only shrinks and fails while it is still unmeasured; see `server/CLAUDE.md`), the browser end-to-end flows (Chromium and WebKit), a client build with `check:gl-split`, coverage for all four packages, then a SonarCloud scan. It also builds the Docker image and boots it until `/api/health/ready` answers (`docker-image`), and lints and renders the Helm chart against the Kubernetes schemas and runs `docker compose config` on every compose file (`deploy-manifests`). `lint-prettier.yml` additionally runs `lint` + `format:check` on `shared/`. `plugin-sdk` has no lint script and is outside the eslint gates. **Not in CI**: `theme:lint` and the screenshot and help-media Playwright projects; run them locally. There are no git hooks; nothing runs before a commit except you. Other workflows build Docker images, scan them, and publish `trek-plugin-sdk` on `plugin-sdk-v*` tags.
|
||||
`.github/workflows/test.yml` runs, per package: typecheck (server also `typecheck:tests`), lint (client and server through `lint:warnings`, which also holds the warning count per rule), `lint:pages`, `lint:rtl`, `lint:size` (client and server), the server's `lint:boundaries`, `lint:tx`, `lint:dialect` and `lint:test-sql`, the client's `lint:format`, `lint:layers`, `lint:offline`, `lint:dup`, `lint:pairs`, `lint:skips` and `lint:i18n-keys`, shared's `contracts:open`, `check:plugin-facts`, `i18n:parity:strict` (with the untranslated-strings ratchet), the S3 contract suite, the Postgres probe (`postgres-probe`: every dialect helper on SQLite and Postgres, and the statements every repository method reaches with sample arguments against a Postgres service; the SQL errors per method and the list of methods it cannot measure are held to a baseline that only shrinks and fails while it is still unmeasured; see `server/CLAUDE.md`), the browser end-to-end flows (Chromium and WebKit), a client build with `check:gl-split`, coverage for all four packages, then a SonarCloud scan. It also builds the Docker image and boots it until `/api/health/ready` answers (`docker-image`), and lints and renders the Helm chart against the Kubernetes schemas and runs `docker compose config` on every compose file (`deploy-manifests`). `lint-prettier.yml` additionally runs `lint` + `format:check` on `shared/`. `plugin-sdk` has no lint script and is outside the eslint gates. **Not in CI**: `theme:lint` and the screenshot and help-media Playwright projects; run them locally. There are no git hooks; nothing runs before a commit except you. Other workflows build Docker images, scan them, and publish `trek-plugin-sdk` on `plugin-sdk-v*` tags.
|
||||
|
||||
- **`ci-ok` is the required check.** The branch ruleset requires `ci-ok` (plus `lint` and `check-target` from their own workflows), and `ci-ok` needs every job above except the scan. It fails if any of them failed or was cancelled and passes if they passed or were skipped. A new gate job counts only once it is listed in `ci-ok`'s `needs:`.
|
||||
- **Guides name paths that exist**: the `changes` job runs `scripts/ci/doc-paths.mjs`, which resolves every backtick path in the CLAUDE.md files, `README.md`, `server/src/nest/README.md` and the wiki against the tracked files; the missing ones are listed in `scripts/ci/doc-paths-baseline.json`, which only shrinks (`--update` after a fix).
|
||||
|
||||
+3
-2
@@ -9,8 +9,9 @@ npm run dev # scripts/dev.mjs: tsc -w then node --watch dist/index
|
||||
npm run build # scripts/build.mjs — emits even on type errors (see below)
|
||||
npm run typecheck # tsc --noEmit — the real type gate
|
||||
npm run typecheck:tests # tsc over tests/ — CI runs this too; vitest green does NOT mean typed mocks compile
|
||||
npm run lint # eslint --fix
|
||||
npm run lint:check # eslint, no fix (CI)
|
||||
npm run lint # eslint, no fix
|
||||
npm run lint:fix # eslint --fix
|
||||
npm run lint:warnings # eslint errors fail, warnings per rule may only shrink (CI gate, scripts/eslint-baseline.json)
|
||||
npm run test # vitest run; also test:unit / test:integration / test:ws / test:e2e
|
||||
npm run test:coverage # istanbul coverage; per-domain ratchet over src/nest/**
|
||||
npm run gen:plugin-facts # regenerate the plugin-protocol tables into plugin-sdk/ + shared/
|
||||
|
||||
@@ -201,6 +201,13 @@ export default tseslint.config(
|
||||
'no-empty': 'warn',
|
||||
'no-useless-escape': 'warn',
|
||||
'prefer-const': 'warn',
|
||||
// Held per rule by lint:warnings (scripts/eslint-baseline.json), so their
|
||||
// count may only fall: sequential awaits in a loop (N round trips where
|
||||
// one batch would do), `!` assertions that strict null checks would have
|
||||
// to prove instead, and console output that bypasses the audit logger.
|
||||
'no-await-in-loop': 'warn',
|
||||
'@typescript-eslint/no-non-null-assertion': 'warn',
|
||||
'no-console': 'warn',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
+3
-1
@@ -16,6 +16,7 @@
|
||||
"typecheck:scripts": "tsc -p tsconfig.scripts.json --noEmit",
|
||||
"db:call-graph": "node scripts/db-call-graph.mjs",
|
||||
"lint:size": "node scripts/size-lint.mjs",
|
||||
"lint:warnings": "node scripts/eslint-ratchet.mjs",
|
||||
"lint:boundaries": "node scripts/import-boundaries.mjs",
|
||||
"lint:dialect": "node scripts/dialect-lint.mjs",
|
||||
"lint:tx": "node scripts/tx-writes.mjs",
|
||||
@@ -30,7 +31,8 @@
|
||||
"probe:pg": "node --import tsx scripts/pg-probe.ts",
|
||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||
"format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"lint:check": "eslint .",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"src": {
|
||||
"@typescript-eslint/no-explicit-any": 93,
|
||||
"@typescript-eslint/no-non-null-assertion": 297,
|
||||
"@typescript-eslint/no-require-imports": 18,
|
||||
"@typescript-eslint/no-unsafe-function-type": 1,
|
||||
"@typescript-eslint/no-unused-vars": 43,
|
||||
"no-await-in-loop": 566,
|
||||
"no-console": 237,
|
||||
"no-empty": 6
|
||||
},
|
||||
"suppressed": {
|
||||
"@typescript-eslint/no-explicit-any": 128,
|
||||
"@typescript-eslint/no-require-imports": 20,
|
||||
"no-control-regex": 7,
|
||||
"no-misleading-character-class": 1
|
||||
},
|
||||
"tests": {
|
||||
"@typescript-eslint/no-explicit-any": 1571,
|
||||
"@typescript-eslint/no-non-null-assertion": 1757,
|
||||
"@typescript-eslint/no-require-imports": 25,
|
||||
"@typescript-eslint/no-unsafe-function-type": 7,
|
||||
"@typescript-eslint/no-unused-vars": 101,
|
||||
"no-await-in-loop": 459,
|
||||
"no-console": 18,
|
||||
"no-empty": 2,
|
||||
"no-useless-escape": 1,
|
||||
"prefer-const": 3
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env node
|
||||
/*
|
||||
* lint:warnings: ESLint errors fail, warnings may only go down.
|
||||
*
|
||||
* Several rules in eslint.config.mjs are warnings (no-explicit-any,
|
||||
* no-unused-vars, no-require-imports, no-await-in-loop, no-non-null-assertion,
|
||||
* no-console and a few js.recommended ones), set that way because the code
|
||||
* had hits when they came in, and a warning never fails a build. So this runs
|
||||
* ESLint over the server with its own config, as `eslint .` does, and counts
|
||||
* the warnings per rule, separately for src/ and tests/, plus the messages an
|
||||
* eslint-disable comment silenced as a third group. Each count may not pass
|
||||
* its entry in scripts/eslint-baseline.json, and an entry above its count
|
||||
* fails as well until --update lowers it, so a fixed warning cannot come back
|
||||
* unseen. Any error fails, so the check stands in for `npm run lint:check`,
|
||||
* and so does a block comment that configures a rule inline: it leaves no
|
||||
* message to count, so it would otherwise be the free way past the ratchet.
|
||||
*
|
||||
* npm run lint:warnings check against the baseline (CI)
|
||||
* npm run lint:warnings -- --update lower the baseline to today's counts;
|
||||
* it never raises an entry
|
||||
*
|
||||
* The tally lives in scripts/lib/eslint-warnings.mjs at the repository root;
|
||||
* ESLint comes from this workspace, so the server lints with the major its
|
||||
* config was written for.
|
||||
*/
|
||||
import { ESLint } from 'eslint';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { check, lintWith } from '../../scripts/lib/eslint-warnings.mjs';
|
||||
import { runCli } from '../../scripts/lib/ratchet.mjs';
|
||||
|
||||
const root = fileURLToPath(new URL('..', import.meta.url));
|
||||
await runCli('lint:warnings', (args) => check({ root, update: args.includes('--update'), lint: lintWith(ESLint) }));
|
||||
@@ -171,7 +171,8 @@ The `@trek/shared` package is the single source of truth for code shared between
|
||||
| `npm run test:watch` | Run tests in watch mode |
|
||||
| `npm run test:coverage` | Run tests with coverage report |
|
||||
| `npm run lint` | Lint source |
|
||||
| `npm run lint:check` | Lint everything, no `--fix` (CI gate) |
|
||||
| `npm run lint:check` | Lint everything, no `--fix` |
|
||||
| `npm run lint:warnings` | ESLint, failing on any error and on warnings above the per-rule baseline (CI gate, replaces `lint:check`) |
|
||||
| `npm run check:plugin-facts` | Verify generated plugin facts (CI gate) |
|
||||
| `npm run lint:size` | No source file grows past its line limit or its baseline entry (CI gate) |
|
||||
| `npm run lint:boundaries` | Import cycles and domain boundaries may not grow past their baseline (CI gate) |
|
||||
|
||||
Reference in New Issue
Block a user