Diagnóstico no CI
O comando regua-pro diagnostico roda o mesmo Diagnóstico do painel numa página aberta pelo Playwright e reprova o build quando uma página fica abaixo da nota que você definir ou tem um erro.
Instalar
O comando vem no pacote @mcardoso.dev/regua-pro. O Playwright, que abre a página num Chromium headless, é uma dependência opcional: fica fora dos bundles do navegador, e o comando diz exatamente o que instalar quando ele ou o Chromium faltam.
npm install --save-dev @mcardoso.dev/regua-pro playwright
npx playwright install --with-deps chromiumA chave da licença vem da variável REGUA_LICENSE_KEY, nunca de um argumento: argumentos acabam em logs e no histórico do shell. O comando não imprime a chave em lugar nenhum.
export REGUA_LICENSE_KEY=RG-XXXX-XXXX-XXXX-XXXX
npx regua-pro diagnostico http://localhost:3000/ http://localhost:3000/precos --min-score 85✗ http://localhost:3000/precos failed
Interface 90 · SEO 51 · 4 errors, 3 warnings, 2 suggestions
Fails: SEO score 51 is below 85; 4 errors
✗ Low contrast (contrast) · Interface · error · 1
1. p.faint
<p.faint> “Plans for every team size, billed monthly or yearly.”
Text contrast is 1.91:1; text needs 4.5:1 (WCAG AA).
Measured: Contrast 1.91:1 (needs 4.5:1) · Text #bbbbbb · Background #ffffff
Fix: Use #777676 for the text (4.52:1 on #ffffff), or a background that contrasts more.Cada problema vem agrupado pela regra, com o seletor do elemento, o que foi medido e a correção sugerida, como no painel. Arquivos HTML locais também valem: regua-pro diagnostico dist/index.html.
Opções
--categoryall- interface, seo ou all.
--min-score0- Nota mínima de 0 a 100 para cada categoria, ou por categoria: interface=90,seo=80.
--fail-onerror- O problema menos grave que reprova a página: error, warning, info ou never.
--ignore- Ids de regras a deixar de fora, separados por vírgula. Saem da lista, das contagens e da nota. regua-pro rules lista todas.
--ignore-issue- Um problema específico, pelo id que o formato json mostra. Pode repetir.
--width, --height1440, 900- Viewport em px.
--mobile- Viewport de celular: 390 × 844, toque e escala 3.
--wait-forload- O que esperar antes de varrer: load, networkidle, um número de milissegundos ou um seletor CSS visível.
--timeout30000- Por página, para carregar e para o --wait-for.
--channel- Um navegador instalado (chrome, msedge) no lugar do Chromium do Playwright.
--formattext- text, json, markdown ou github.
--output- Grava o relatório num arquivo em vez do stdout. Com github, grava o Markdown.
--localepelo LANG- en ou pt, para o texto do próprio comando.
Códigos de saída
0- Todas as páginas foram aprovadas.
1- Uma página ficou abaixo de --min-score ou tem um problema no nível de --fail-on.
2- Erro de uso, de licença ou do navegador, ou uma página que não carregou: HTTP 4xx/5xx, timeout, --wait-for que não aconteceu.
Formatos
- text: notas por categoria e problemas agrupados por regra, com cores no terminal.
- json: o relatório completo num formato estável, descrito pelo JSON Schema em
@mcardoso.dev/regua-pro/diagnostico-report.schema.json. A versão do formato só muda quando um campo sai ou muda de sentido. - markdown: a tabela de notas e os problemas de cada página, pronto para um comentário de pull request. A primeira linha,
<!-- regua-diagnostico -->, permite atualizar sempre o mesmo comentário. - github: o log agrupado por página, uma anotação por problema e o relatório em Markdown no resumo do job. Só o que reprova vira anotação de erro; o resto vira aviso ou nota.
{
"schemaVersion": 1,
"passed": false,
"totals": { "pages": 1, "passed": 0, "failed": 1, "errored": 0, "issues": { "error": 4, "warning": 3, "info": 2 } },
"pages": [{
"url": "http://localhost:3000/precos",
"status": "failed",
"scores": { "interface": 90, "seo": 51 },
"failures": [{ "type": "score", "category": "seo", "score": 51, "min": 85 }, { "type": "severity", "severity": "error", "count": 4 }],
"issues": [{
"id": "contrast||p.faint",
"rule": "contrast",
"severity": "error",
"selector": "p.faint",
"message": "Text contrast is 1.91:1; text needs 4.5:1 (WCAG AA).",
"fix": "Use #777676 for the text (4.52:1 on #ffffff), or a background that contrasts more."
}]
}]
}GitHub Actions
Um workflow que serve o app, revisa as páginas, anota o resultado no run e mantém um comentário no pull request. Cadastre a chave como o secret REGUA_LICENSE_KEY do repositório.
name: Diagnóstico
on: pull_request
permissions:
contents: read
pull-requests: write
jobs:
diagnostico:
# PRs de forks não recebem secrets.
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 22
cache: npm
- run: npm ci && npm run build
- run: |
npm run start -- --port 3000 &
for i in $(seq 60); do curl -fs http://localhost:3000/ > /dev/null && exit 0; sleep 1; done; exit 1
- run: npx playwright install --with-deps chromium
# O token da licença entre execuções: verificado offline, sem ativar de novo.
- uses: actions/cache@v4
with:
path: ~/.cache/regua-pro
key: regua-pro-licence-${{ github.run_id }}
restore-keys: regua-pro-licence-
- run: npx regua-pro diagnostico http://localhost:3000/ --min-score 85 --format github --output diagnostico.md
env:
REGUA_LICENSE_KEY: ${{ secrets.REGUA_LICENSE_KEY }}
- if: always() && hashFiles('diagnostico.md') != ''
uses: actions/github-script@v7
with:
script: |
const body = require("node:fs").readFileSync("diagnostico.md", "utf8")
const { owner, repo } = context.repo
const issue_number = context.issue.number
const comments = await github.paginate(github.rest.issues.listComments, { owner, repo, issue_number })
const previous = comments.find((c) => c.body?.startsWith("<!-- regua-diagnostico -->"))
if (previous) await github.rest.issues.updateComment({ owner, repo, comment_id: previous.id, body })
else await github.rest.issues.createComment({ owner, repo, issue_number, body })Licença e vagas no CI
Runners de CI são descartáveis. Se cada execução se apresentasse como uma instalação nova, a licença bateria no limite de 3 instalações na quarta. Por isso o comando usa uma vaga só dele, a Régua CLI: o identificador da instalação é derivado da chave, igual em todo runner e em todo computador, e ativar uma instalação que já está ativa não ocupa vaga nova.
- O token assinado fica em cache em
~/.cache/regua-pro(ou$XDG_CACHE_HOME/regua-pro, ouREGUA_CACHE_DIR), sem a chave. Com o cache, a execução seguinte verifica a licença offline; a cada 3 dias ela é renovada. - Sem cache, cada execução ativa de novo. Não ocupa vaga, mas conta no limite de requisições do servidor: guarde o diretório entre execuções, como no
actions/cachedo exemplo. - Quer uma vaga separada, para outro time? Defina
REGUA_INSTALLATION_IDcom 16 a 64 caracteres. - A vaga aparece como Régua CLI em Minha conta. Liberada lá, a próxima execução ocupa uma vaga de novo, se houver.
Como no navegador, o conteúdo das páginas nunca sai da máquina: só a chave, o identificador da vaga e o nome Régua CLI chegam ao servidor de licenças.