mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-02 05:12:11 +03:00
* feat(quality): no-new-warnings per PR via native ESLint bulk suppressions Pacote 4 do plano mestre testes+CI (aprovado 2026-07-04). O ratchet de eslintWarnings so rodava no CI pesado (release-PR) -> o drift acumulava invisivel e explodia na release (+41/+37/+88 por ciclo, rebaselinado as cegas — historico no proprio quality-baseline.json). Modelo novo (SonarSource Clean-as-You-Code + ESLint bulk suppressions nativo >=9.24): - config/quality/eslint-suppressions.json congela a divida existente por arquivo+regra: 476 arquivos / 4.273 violacoes. - npm run lint + lint-staged (pre-commit) + novo job lint-guard no quality.yml rodam suppressions-aware: violacao NOVA fica vermelha NO PR que a introduz (bulk suppressions ainda eleva estouros de baseline por arquivo a error). - 3 regras warn promovidas a error em src/** (react-hooks/exhaustive-deps, @next/next/no-img-element, import/no-anonymous-default-export) — divida existente congelada, ocorrencia nova = erro imediato. - collect-metrics mede sob o baseline congelado -> a metrica eslintWarnings vira 'divida liquida nova' (~0 em regime); baseline apertado 4279->0 no mesmo PR (exigencia do require-tighten). Aperto do ESTOQUE congelado: npx eslint . --prune-suppressions na reconciliacao da release. - Principio Zero: lint-guard usa continue-on-error para PR de FORK (report-only; a campanha /green-prs aplica o fix via co-autoria) — bloqueante so para branches internas, a origem real do drift. Validacao: negativo (any novo em tests/) exit 1; negativo (img em src/, regra promovida) exit 1; positivo escopado exit 0; baseline gerado por --suppress-all no tip (tree inteiro passa por construcao); YAML js-yaml ok. * fix(quality): clear the 6 residual warnings so lint-guard runs clean at --max-warnings 0 The committed baseline still let 6 warnings through the lint-guard gate: 5 now-unused inline eslint-disable directives (the file-level suppressions made them redundant — removed via eslint --fix, suppressions regenerated to absorb the re-exposed occurrences) and 1 anonymous default export in tests/load/k6-soak.js (outside the src/** severity-override scope — named the k6 scenario function instead). Verified on the clean tree: lint-guard exit=0; any-canary (new 'const x: any' in open-sse) exit=1 — the gate bites on NEW violations while the 4,273 frozen ones stay suppressed (476 files). * fix(ci): lint-guard continue-on-error must be boolean on non-PR events github.event.pull_request is undefined on workflow_dispatch — the bare property expression made the job fail at plan time (run 28722888456: 4 jobs green, run red, lint-guard never materialized). Guard with event_name check so the expression is always boolean: PR de fork = report-only (Principio Zero), resto = blocking.
177 lines
7.9 KiB
YAML
177 lines
7.9 KiB
YAML
name: Quality Gates
|
|
|
|
on:
|
|
pull_request:
|
|
branches: ["release/**"]
|
|
types: [opened, synchronize, reopened, ready_for_review]
|
|
workflow_dispatch:
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
env:
|
|
CI_NODE_VERSION: "24"
|
|
|
|
jobs:
|
|
fast-gates:
|
|
name: Fast Quality Gates
|
|
runs-on: ubuntu-latest
|
|
# tsx gates (known-symbols, route-guard-membership) import modules that open
|
|
# SQLite on load; provide DB env so a fresh CI DB initializes cleanly.
|
|
env:
|
|
JWT_SECRET: ci-lint-secret-with-sufficient-length-for-validation
|
|
API_KEY_SECRET: ci-lint-api-key-secret-long
|
|
DISABLE_SQLITE_AUTO_BACKUP: "true"
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
with:
|
|
fetch-depth: 0
|
|
persist-credentials: false
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.CI_NODE_VERSION }}
|
|
cache: npm
|
|
- run: npm ci
|
|
- run: npm run check:provider-consistency
|
|
- run: npm run check:fetch-targets
|
|
- run: npm run check:openapi-routes
|
|
- run: npm run check:docs-symbols
|
|
- name: Docs accuracy (fabricated-docs + i18n mirrors, strict)
|
|
run: npm run check:docs-all
|
|
- run: npm run check:deps
|
|
- run: npm run check:file-size
|
|
- run: npm run check:error-helper
|
|
- run: npm run check:migration-numbering
|
|
- run: npm run check:public-creds
|
|
- run: npm run check:db-rules
|
|
- run: npm run check:known-symbols
|
|
- run: npm run check:route-guard-membership
|
|
- run: npm run check:test-discovery
|
|
- run: npm run check:test-runner-api
|
|
# Guards tap.testFiles drift: a covering unit test absent from stryker.conf.json
|
|
# tap.testFiles makes its module's mutants survive on a cold nightly-mutation run,
|
|
# false-failing the blocking mutationScore ratchet. See check-mutation-test-coverage.mjs.
|
|
- run: npm run check:mutation-test-coverage
|
|
- run: npm run check:any-budget:t11
|
|
# Build-scope guard: fails if worktrees/cruft leak into the tsconfig include
|
|
# scope (would OOM `next build`). Instant. See incident 2026-06-25 / #5031.
|
|
- run: npm run check:build-scope
|
|
# Pack-policy (unexpected-files allowlist) WITHOUT a build — catches a stray file
|
|
# leaking into the npm tarball (v3.8.36: 6 ops bin/*.sh) per-PR instead of only on
|
|
# the release PR's heavy Package Artifact job.
|
|
- run: npm run check:pack-policy
|
|
# Complexity + cognitive-complexity ratchets on the fast-path (PR→release) so
|
|
# cycle drift is rebaselined PER-PR instead of cascading onto the release PR's
|
|
# Quality Ratchet (v3.8.36: +30 complexity / +15 cognitive surfaced only post-merge).
|
|
- run: npm run check:complexity
|
|
- run: npm run check:cognitive-complexity
|
|
- name: Typecheck (core)
|
|
run: npm run typecheck:core
|
|
# TIA: build the impact map at runtime (gitignored, ~21MB) and run only the
|
|
# unit tests impacted by this PR's changed files. Fail-safe runs the FULL
|
|
# unit suite on hub/unmapped changes — TIA accelerates, never replaces, the net.
|
|
#
|
|
# BLOCKING (flipped 2026-06-17). The pre-existing release unit test-debt that kept
|
|
# this advisory was cleared: #4030 (16 Zod/registry reds, lossless restore) and
|
|
# #4063 (the last red — the LiveWS boot test — root-caused as a real event-loop
|
|
# stall in the WS sidecar, fixed + relocated to the integration suite). A full
|
|
# ci.yml run on release/v3.8.28 then showed all 8 unit shards green, so PR->release
|
|
# now blocks on unit-test regressions in the impacted set (typecheck:core already
|
|
# blocked above). Fail-safe still runs the FULL unit suite on hub/unmapped changes.
|
|
- name: Impacted unit tests (TIA, fail-safe full; blocking)
|
|
env:
|
|
GITHUB_BASE_REF: ${{ github.base_ref }}
|
|
run: |
|
|
git fetch --no-tags origin "$GITHUB_BASE_REF" || true
|
|
node scripts/quality/build-test-impact-map.mjs
|
|
SEL="$(node scripts/quality/select-impacted-tests.mjs)"
|
|
if [ -z "$SEL" ]; then echo "No source/test changes — skipping unit tests"; exit 0; fi
|
|
# CI runners are 4-vCPU; run at --test-concurrency=4 (matching the ci.yml unit
|
|
# job) rather than test:unit's local-tuned concurrency=20. Oversubscribing the
|
|
# runner makes timing-sensitive tests (db-backup, upstream-timeout, ...) flake,
|
|
# which must not happen on a blocking gate. DATA_DIR isolation keeps the parallel
|
|
# run race-free regardless of concurrency.
|
|
if echo "$SEL" | grep -q "__RUN_ALL__"; then
|
|
echo "Fail-safe: running FULL unit suite (CI concurrency)"; npm run test:unit:ci; exit $?
|
|
fi
|
|
echo "Running impacted tests:"; echo "$SEL"
|
|
mapfile -t FILES <<< "$SEL"
|
|
node --import tsx/esm --import ./open-sse/utils/setupPolyfill.ts --import ./tests/_setup/isolateDataDir.ts --test --test-force-exit --test-concurrency=4 "${FILES[@]}"
|
|
|
|
fast-vitest:
|
|
name: Vitest (fast-path)
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
JWT_SECRET: ci-lint-secret-with-sufficient-length-for-validation
|
|
API_KEY_SECRET: ci-lint-api-key-secret-long
|
|
DISABLE_SQLITE_AUTO_BACKUP: "true"
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
with:
|
|
persist-credentials: false
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.CI_NODE_VERSION }}
|
|
cache: npm
|
|
- run: npm ci
|
|
- run: npm run test:vitest
|
|
|
|
fast-unit:
|
|
name: Unit Tests fast-path (${{ matrix.shard }}/2)
|
|
runs-on: ubuntu-latest
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
shard: [1, 2]
|
|
env:
|
|
JWT_SECRET: ci-lint-secret-with-sufficient-length-for-validation
|
|
API_KEY_SECRET: ci-lint-api-key-secret-long
|
|
DISABLE_SQLITE_AUTO_BACKUP: "true"
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
with:
|
|
persist-credentials: false
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.CI_NODE_VERSION }}
|
|
cache: npm
|
|
- run: npm ci
|
|
# QW-d: fonte única — o mesmo npm script do CI pesado/local. Fecha dois drifts do
|
|
# comando inline antigo: os dirs `memory` e `usage` estavam FORA do glob (testes
|
|
# silenciosamente não rodavam no fast path) e o setupPolyfill não era importado.
|
|
- run: npm run test:unit:ci:shard
|
|
env:
|
|
TEST_SHARD: ${{ matrix.shard }}/2
|
|
|
|
# ── Pacote 4 (plano mestre testes+CI, aprovado 2026-07-04) ─────────────────────────
|
|
# No-new-warnings por PR via ESLint bulk suppressions nativo (>=9.24). O baseline
|
|
# config/quality/eslint-suppressions.json congela as violações EXISTENTES por
|
|
# arquivo+regra; qualquer warning NOVO aparece e o --max-warnings 0 falha o job — o
|
|
# drift de +41/+88 warnings por ciclo passa a morrer no PR que o introduz, em vez de
|
|
# ser rebaselinado às cegas na release. Aperto do baseline (na reconciliação da
|
|
# release): npx eslint . --prune-suppressions --suppressions-location config/quality/eslint-suppressions.json
|
|
#
|
|
# Princípio Zero: bloqueante SÓ para branches internas (as campanhas/sessões são a
|
|
# origem do drift). PR de FORK roda em modo report (continue-on-error → o job fica
|
|
# verde com anotação; a campanha /green-prs aplica o fix via co-autoria — o
|
|
# contribuidor NUNCA é bloqueado nem cobrado).
|
|
lint-guard:
|
|
name: No new ESLint warnings
|
|
runs-on: ubuntu-latest
|
|
continue-on-error: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true }}
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
with:
|
|
persist-credentials: false
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: ${{ env.CI_NODE_VERSION }}
|
|
cache: npm
|
|
- run: npm ci
|
|
- name: ESLint (baseline congelado — warning novo = vermelho)
|
|
run: npx eslint . --suppressions-location config/quality/eslint-suppressions.json --max-warnings 0
|