mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-15 10:43:07 +00:00
- ci-pr.yml: split the serial checks job into parallel lint/format/ typecheck/knip/cycles + unit/int (vitest --changed vs PR base via scripts/test-affected.mjs, full fallback on high-risk paths) + e2e (manifest path->spec via scripts/e2e-affected.mjs, blocking) + build; migration-lock gains checkout + pull-requests:read (fixes the failures that blocked PR #50) - ci.yml (main): full safety net — seed:minimal + int full + build + e2e - package.json: gate:fast / gate:push; .husky/pre-push runs gate:push - docs: "Dono do PR, dono do CI" policy in AGENT-OPS + work-issue + engineering-standards; changelog entry; plans for OPS3-OPS7
94 lines
6.5 KiB
Markdown
94 lines
6.5 KiB
Markdown
# Testes afetados pelo diff no PR — vitest --changed + manifesto path→spec e2e
|
||
|
||
Status: entregue (2026-07-30 — executado em sessão única, fora do fluxo agent:register, a pedido do humano)
|
||
Atualizado em: 2026-07-30
|
||
Issue: —
|
||
Priority: P1
|
||
Model: composer-2.5
|
||
Impeccable: A — N/A (sem superfície UI)
|
||
Appetite: ~1–2 dias eng; script de seleção + manifesto + wiring nos jobs do OPS4 + pins
|
||
Responsável: —
|
||
|
||
## Dados → decisão → apresentação
|
||
|
||
Dados: N/A — infra de CI.
|
||
|
||
## Contexto
|
||
|
||
Com o ci-pr paralelizado (OPS4), o próximo corte é rodar **só o que o diff toca** em PRs de feature branch: hoje um PR de copy roda 523 testes int + 522 unit + build. Vitest suporta `--changed` contra uma base git; Playwright `--only-changed` **não** cobre mudanças em `src/` (specs e2e não importam o app), então a seleção e2e precisa de um **manifesto path → spec** curado no repo. Push em `stage`/`main` sempre roda suíte completa (decisão OPS4).
|
||
|
||
Decisão de produto (2026-07-30, brief do lote CI): fallback para suíte completa quando o diff tocar paths de alto risco — migrations, lockfile, configs de teste, seed manifest, collections/globals.
|
||
|
||
## Objetivos
|
||
|
||
- Job `unit`/`int` no ci-pr roda `vitest --changed origin/$GITHUB_BASE_REF` (fallback full nos paths de risco).
|
||
- Job `e2e` no ci-pr roda specs mapeadas pelo manifesto; fallback full idem.
|
||
- `scripts/e2e-affected.mjs` (ou equivalente) imprime a lista de specs e o motivo (decisão auditável no log do CI).
|
||
- Pins: unit test do manifesto (path→spec existe, spec existe no disco) + comportamento de fallback.
|
||
|
||
## Decisões travadas
|
||
|
||
- **Manifesto e2e = dados no repo, não inferência por import.** e2e não importa `src/`; a única fonte de verdade é uma tabela curada. **Rejeitado:** heurística por nome de spec (frágil — `campaignZoneMap` ≠ pasta `map/`); trace estático Playwright→app (não existe aresta de import).
|
||
- **Fallback full em paths de alto risco** (lista congelada no script): `src/migrations/`, `src/payload-types.ts`, `pnpm-lock.yaml`, `package.json`, `vitest*.config.*`, `playwright.config.ts`, `scripts/lib/seed-minimal-manifest.mjs`, `scripts/seed-minimal.mjs`, `src/collections/`, `src/globals/`, `src/payload.config.ts`, `tests/helpers/`, `tests/e2e/fixtures/`, `.env*`. **Rejeitado:** fallback por "mais de N arquivos" (tamanho ≠ risco); lista aberta por glob no workflow (regra fora de teste unitário).
|
||
- **Seleção só no ci-pr; `ci.yml`/`ci-stage.yml` sempre full.** Rede de segurança por alvo (decisão OPS4). **Rejeitado:** affected também no main (derrota o propósito do gate pós-merge).
|
||
- **`--changed` com fallback para full quando vitest retorna conjunto vazio mas o diff toca `src/`** (ex.: arquivo novo sem spec importando). **Rejeitado:** aceitar conjunto vazio como "nada a rodar" (falso verde em código novo sem teste ligado).
|
||
|
||
## Questões em aberto
|
||
|
||
- **e2e bloqueante no PR desde o dia 1?** **Decidido no gate (humano, 2026-07-30): bloqueante já.** A alternativa de 2 semanas em `continue-on-error` para calibrar o manifesto foi rejeitada pelo humano ("já resolve logo nessa sessão"). O manifesto fica visível nos logs (`unmapped`) para calibração contínua.
|
||
|
||
## Abordagem proposta
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
diff["git diff origin/base...HEAD"] --> script["scripts/e2e-affected.mjs + scripts/test-affected.mjs"]
|
||
script -->|paths de risco| full[suites completas]
|
||
script -->|paths mapeados| sel["specs selecionadas + vitest --changed"]
|
||
sel --> jobs["jobs unit/int/e2e do ci-pr"]
|
||
full --> jobs
|
||
```
|
||
|
||
Componentes:
|
||
|
||
- **`scripts/test-affected.mjs`** — computa diff vs `GITHUB_BASE_REF` (default `origin/stage`), aplica a lista de risco, emite `{ mode: 'full' | 'changed' }` + args vitest. Consumido pelos jobs `unit` e `int`.
|
||
- **`scripts/e2e-affected.mjs` + `scripts/lib/e2e-affected-manifest.mjs`** — tabela prefixo→specs. Esboço inicial (17 specs em `tests/e2e/`):
|
||
- `src/app/(campaign)/campanha/(app)/municipios`, `src/components/campaign/municipality`, `src/utilities/municipality/` → `campaignMunicipalities`, `campaignZoneMap`, `campaignNearestMunicipality`, `campaignSavedFilters`, `campaignColumnPicker`
|
||
- `…/atividades`, `components/campaign/activity` → `campaignActivity`
|
||
- `…/liderancas`, `components/campaign/leadership` → `campaignLeaderships`
|
||
- `…/territorios`, `components/campaign/territory` → `campaignTerritories`
|
||
- `campanha/login`, `utilities/campaignAuth`, `utilities/webauthn/` → `campaignAuth`, `campaignWebAuthn`
|
||
- `…/conceitos` → `campaignConcepts`; dashboard/home → `campaignHomeActions`
|
||
- `components/campaign/shell`, PWA → `campaign-pwa`, `campaignWizardChrome`
|
||
- `src/app/(payload)` → `admin`; `src/app/(frontend)` → `frontend`
|
||
- qualquer outro `src/` não mapeado → log explícito "sem spec mapeada" (modo e2e: nenhuma; o gap fica visível no log para o humano julgar — decisão: não falhar, e2e é camada fina sobre int).
|
||
- **`.github/workflows/ci-pr.yml`** — jobs `unit`/`int`/`e2e` (do OPS4) consomem os scripts; step de diff com `fetch-depth: 0` no checkout.
|
||
- **Tests** — `tests/unit/testAffected.unit.spec.ts` + `tests/unit/e2eAffectedManifest.unit.spec.ts` (manifesto aponta para specs existentes; paths de risco disparam full).
|
||
|
||
Sem migration, sem código de app.
|
||
|
||
## Dependências
|
||
|
||
- **OPS4** (jobs paralelos existem para receber a seleção) — dura.
|
||
- Reusa: padrão `scripts/lib/` (B5 F2), `tests/helpers/assertTestDatabase.ts` não é tocado.
|
||
|
||
## Não escopo
|
||
|
||
- Seleção de unit por manifesto (vitest `--changed` resolve por import graph real).
|
||
- Cache de resultados de teste entre runs (Turborepo-style) — sem evidência de necessidade.
|
||
- Nightly full e2e → OPS4 (adiado lá).
|
||
|
||
## Rabbit holes
|
||
|
||
- **Manifesto vira segundo grafo de dependências.** Se alguém "só completar" granularidade por arquivo, vira manutenção morta. **Mitigação:** granularidade de prefixo de domínio; pin de unit test só na existência, não na completude.
|
||
- **`vitest --changed` com worktrees/forks sem base fetchada.** `fetch-depth: 0` no checkout; fallback full se o merge-base não resolver (log + exit code do script).
|
||
|
||
## Adiado com gatilho
|
||
|
||
- **Completude do manifesto enforced (falhar CI quando `src/` novo não mapeia).** Revisitar quando: 3º fallback full causado por prefixo ausente.
|
||
|
||
## Referências
|
||
|
||
- `tests/e2e/` (17 specs + fixtures), `playwright.config.ts`, `vitest.unit.config.mts`, `vitest.config.mts`
|
||
- `.github/workflows/ci-pr.yml` (jobs do OPS4)
|
||
- `docs/AGENT-OPS.md` — linha E2E da tabela "CI por alvo" (atualizar neste item)
|
||
- Vitest `--changed`: https://vitest.dev/guide/cli.html#changed
|