Skip to content

Commit 29ac3f6

Browse files
committed
chore(ci): sincroniza templates e declara divergências deliberadas
Converge com os templates canônicos do @precisa-saude/cli 1.13.0. O precisa doctor deste repo passa a sair 0. ignoreTemplates: .commitlintrc.cjs, .github/workflows/_checks.yml, .github/workflows/ci.yml Os workflows entram na lista porque a estrutura deste repo não bate com a do template — sincronizá-los quebrou o CI. Ver Precisa-Saude/tooling#44.
1 parent e25937a commit 29ac3f6

5 files changed

Lines changed: 135 additions & 81 deletions

File tree

.github/workflows/doctor.yml

Lines changed: 114 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: Template drift audit
33
# Monthly audit — runs `precisa doctor` to detect drift between this
44
# repo's templated files (workflows, dotfiles, configs) and the current
55
# `@precisa-saude/cli` templates. When drift shows up, open a PR running
6-
# `pnpm exec precisa sync` to absorb the changes.
6+
# `precisa sync` to absorb the changes.
77
#
88
# Runs on the 1st of each month at 06:00 America/Sao_Paulo (09:00 UTC).
99
# `workflow_dispatch` is wired so you can trigger it ad-hoc.
@@ -13,6 +13,12 @@ name: Template drift audit
1313
# in each repo. See fhir-brasil#26 (PAT_TOKEN → GitHub App) for the
1414
# concrete failure mode — drift went undetected until a conditional
1515
# job finally fired in production.
16+
#
17+
# Roda via `npx @precisa-saude/cli`, não via `pnpm exec`. O CLI não é
18+
# devDependency de nenhum repo consumidor, então `pnpm exec precisa` saía
19+
# "command not found" — não-zero, indistinguível de drift real. Todo repo
20+
# com este workflow abriu uma issue de "drift" por mês sem nunca ter
21+
# inspecionado um template. Ver a separação de exit codes abaixo.
1622

1723
on:
1824
schedule:
@@ -30,42 +36,130 @@ jobs:
3036
timeout-minutes: 10
3137
steps:
3238
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
33-
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
3439
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
3540
with:
3641
node-version: 22
37-
cache: 'pnpm'
38-
- run: pnpm install --frozen-lockfile
42+
43+
# `npx --yes` dispensa o CLI como devDependency (nenhum repo o tem) e
44+
# dispensa `pnpm install` — o doctor só lê `.precisa.json` e os templates
45+
# que vêm dentro do próprio pacote.
46+
#
47+
# O exit code é capturado em vez de virar falha do step, para separar os
48+
# dois casos que antes colidiam:
49+
# 0 — sem drift
50+
# 1 — drift encontrado (o doctor rodou e comparou)
51+
# 2 — `.precisa.json` ausente ou inválido (nada comparado)
52+
# qualquer outro — o audit não rodou (rede, versão quebrada, etc.)
53+
# `PIPESTATUS[0]` pega o código do npx, não do `tee`.
3954
- name: Audit templates
4055
id: doctor
41-
run: pnpm exec precisa doctor
42-
continue-on-error: true
43-
- name: Open issue on drift
44-
if: steps.doctor.outcome == 'failure'
56+
# `shell: bash` explícito: `PIPESTATUS` é bashismo. É o default em
57+
# runners Linux, mas depender do default deixa o passo frágil se o
58+
# workflow for reaproveitado em outro runner.
59+
shell: bash
60+
env:
61+
NO_COLOR: '1'
62+
run: |
63+
set +e
64+
npx --yes @precisa-saude/cli@latest doctor 2>&1 | tee "$RUNNER_TEMP/precisa-doctor.log"
65+
echo "exit_code=${PIPESTATUS[0]}" >> "$GITHUB_OUTPUT"
66+
67+
# Falha barulhenta e visível quando a própria auditoria quebra. Antes
68+
# isso virava uma issue mensal de "drift" — o modo de falha que fez o
69+
# sinal perder credibilidade.
70+
- name: Fail when the manifest is invalid
71+
if: steps.doctor.outputs.exit_code == '2'
72+
run: |
73+
echo "::error title=.precisa.json inválido::O manifesto deste repo não valida contra o schema atual do CLI, então nenhum template foi comparado. Isto NÃO é drift — rodar 'sync' não resolve. Corrija os campos listados no log acima."
74+
exit 1
75+
76+
- name: Fail when the audit could not run
77+
if: steps.doctor.outputs.exit_code != '0' && steps.doctor.outputs.exit_code != '1' && steps.doctor.outputs.exit_code != '2'
78+
run: |
79+
echo "::error title=precisa doctor não rodou::exit ${{ steps.doctor.outputs.exit_code }} — isto NÃO é drift; a auditoria em si falhou."
80+
exit 1
81+
82+
# Uma issue por repo, atualizada a cada rodada. A versão anterior criava
83+
# uma issue nova todo mês, acumulando duplicatas até ninguém mais ler.
84+
- name: Report drift
85+
if: steps.doctor.outputs.exit_code == '1'
4586
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
4687
with:
4788
script: |
89+
const fs = require('node:fs');
4890
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
91+
const MARKER = '<!-- precisa-doctor-drift -->';
92+
93+
let log = '';
94+
try {
95+
// `RUNNER_TEMP` em vez de `/tmp`: é limpo por job e não colide
96+
// com outro job no mesmo runner (relevante em self-hosted).
97+
log = fs.readFileSync(`${process.env.RUNNER_TEMP}/precisa-doctor.log`, 'utf8').trim();
98+
} catch {
99+
log = '(log indisponível)';
100+
}
101+
// Cabe folgado no limite de 65536 chars do corpo de uma issue.
102+
// Corta em fronteira de linha: cada linha do doctor é um arquivo,
103+
// e cortar no meio produziria um nome de arquivo pela metade.
104+
const LIMITE = 20000;
105+
if (log.length > LIMITE) {
106+
const corte = log.lastIndexOf('\n', LIMITE);
107+
log = `${log.slice(0, corte > 0 ? corte : LIMITE)}\n… (truncado — ver o log completo do run)`;
108+
}
109+
49110
const body = [
50-
'`precisa doctor` detected drift between this repo and the canonical templates.',
111+
MARKER,
112+
'`precisa doctor` encontrou divergência entre este repo e os templates canônicos.',
51113
'',
52-
`Full log: ${runUrl}`,
114+
'### Saída do doctor',
53115
'',
54-
'To fix:',
116+
'```',
117+
log,
118+
'```',
119+
'',
120+
`Log completo do run: ${runUrl}`,
121+
'',
122+
'### Como resolver',
55123
'',
56124
'```bash',
57-
'pnpm exec precisa sync --dry-run # review the diff',
58-
'pnpm exec precisa sync # apply',
125+
'npx @precisa-saude/cli@latest sync --dry-run # revisar o diff',
126+
'npx @precisa-saude/cli@latest sync # aplicar',
59127
'```',
60128
'',
61-
'Drift typically shows up when `@precisa-saude/cli` publishes',
62-
'new templates (workflow changes, dotfile updates) and this',
63-
'repo has not run `precisa sync` since.',
129+
'> **Revise o `--dry-run` antes de aplicar.** Templates marcados',
130+
'> `overwrite` são reescritos sem backup nem confirmação — se este',
131+
'> repo tem customização deliberada num arquivo templatizado, o',
132+
'> sync a descarta. Nesse caso, leve a mudança para o `tooling`',
133+
'> em vez de rodar o sync.',
134+
'',
135+
`Atualizado em ${new Date().toISOString()} pelo run ${context.runId}.`,
64136
].join('\n');
65-
await github.rest.issues.create({
137+
138+
const title = 'precisa doctor: template drift detected';
139+
const existing = await github.paginate(github.rest.issues.listForRepo, {
66140
owner: context.repo.owner,
67141
repo: context.repo.repo,
68-
title: 'precisa doctor: template drift detected',
69-
body,
70-
labels: ['dependencies', 'tooling-drift'],
142+
state: 'open',
143+
labels: 'tooling-drift',
144+
per_page: 100,
71145
});
146+
const open = existing.find((i) => !i.pull_request && (i.body ?? '').includes(MARKER));
147+
148+
if (open) {
149+
await github.rest.issues.update({
150+
owner: context.repo.owner,
151+
repo: context.repo.repo,
152+
issue_number: open.number,
153+
body,
154+
});
155+
core.notice(`Drift persiste — issue #${open.number} atualizada.`);
156+
} else {
157+
const { data } = await github.rest.issues.create({
158+
owner: context.repo.owner,
159+
repo: context.repo.repo,
160+
title,
161+
body,
162+
labels: ['dependencies', 'tooling-drift'],
163+
});
164+
core.notice(`Drift detectado — issue #${data.number} aberta.`);
165+
}

.precisa.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,10 @@
1212
"conduct": "conduct@precisa-saude.com.br"
1313
},
1414
"nodeVersion": "22",
15-
"pnpmVersion": "9.15.9"
15+
"pnpmVersion": "9.15.9",
16+
"ignoreTemplates": [
17+
".commitlintrc.cjs",
18+
".github/workflows/_checks.yml",
19+
".github/workflows/ci.yml"
20+
]
1621
}

CITATION.cff

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,8 @@
11
cff-version: 1.2.0
22
title: 'datasus-parquet'
3-
message: >-
4-
Se você utilizar este arquivo em pesquisa, publicação ou software,
5-
cite conforme abaixo. Cada release do dataset recebe um DOI
6-
individual via Zenodo — troque o campo `doi` pelo DOI emitido para
7-
a versão específica utilizada (visível em
8-
https://zenodo.org/search?q=Precisa-Saude/datasus-parquet).
9-
type: dataset
3+
message: 'Se você utilizar este software, por favor cite-o conforme abaixo.'
4+
type: software
105
authors:
11-
- name: Precisa Saúde
12-
website: https://precisa-saude.com.br
13-
repository-code: https://github.com/Precisa-Saude/datasus-parquet
14-
url: https://github.com/Precisa-Saude/datasus-parquet
15-
license: CC-BY-4.0
16-
keywords:
17-
- datasus
18-
- sus
19-
- sia-sus
20-
- brazil
21-
- microdados
22-
- open-data
23-
- epidemiology
24-
- parquet
25-
- public-health
26-
identifiers:
27-
- type: doi
28-
value: 10.5281/zenodo.PENDING
29-
description: >-
30-
Concept DOI (Zenodo) — placeholder. Preenchido após habilitar o
31-
webhook GitHub ↔ Zenodo e publicar a primeira release.
32-
abstract: >-
33-
Arquivo público de microdados do DATASUS em formato Parquet, com
34-
conversão 1:1 a partir dos DBC/DBF originais do FTP oficial.
35-
Provenance com SHA256 permite validação byte-a-byte contra a fonte.
36-
Atualmente cobre SIA-PA (Produção Ambulatorial, 2008+);
37-
contribuições para outros subdatasets são bem-vindas.
38-
references:
39-
- type: data
40-
title: SIA-SUS — Produção Ambulatorial (fonte original)
41-
authors:
42-
- name: 'Ministério da Saúde / DATASUS'
43-
url: ftp://ftp.datasus.gov.br/dissemin/publicos/SIASUS/200801_/Dados/
44-
notes: >-
45-
Fonte oficial, distribuída sob regime de dados abertos
46-
(Lei 12.527/2011 e Decreto 8.777/2016).
6+
- name: 'Precisa-Saude'
7+
repository-code: 'https://github.com/Precisa-Saude/datasus-parquet'
8+
license: Apache-2.0

renovate.json

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,20 @@
1111
"labels": ["dependencies"],
1212
"prConcurrentLimit": 5,
1313
"packageRules": [
14+
{
15+
"matchUpdateTypes": ["minor", "patch"],
16+
"matchDepTypes": ["devDependencies"],
17+
"automerge": true,
18+
"automergeType": "pr"
19+
},
1420
{
1521
"matchUpdateTypes": ["major"],
1622
"automerge": false,
1723
"labels": ["dependencies", "major-update"]
1824
},
1925
{
2026
"matchPackagePatterns": ["^@precisa-saude/"],
21-
"groupName": "precisa-saude packages",
22-
"automerge": true,
23-
"automergeType": "pr"
27+
"groupName": "precisa-saude packages"
2428
},
2529
{
2630
"matchManagers": ["github-actions"],
@@ -30,6 +34,6 @@
3034
],
3135
"vulnerabilityAlerts": {
3236
"labels": ["security"],
33-
"automerge": false
37+
"automerge": true
3438
}
3539
}

tsconfig.json

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,4 @@
11
{
2-
"compilerOptions": {
3-
"target": "ES2022",
4-
"module": "NodeNext",
5-
"moduleResolution": "NodeNext",
6-
"lib": ["ES2022"],
7-
"strict": true,
8-
"noUncheckedIndexedAccess": true,
9-
"esModuleInterop": true,
10-
"skipLibCheck": true,
11-
"resolveJsonModule": true,
12-
"isolatedModules": true
13-
},
14-
"include": ["scripts/**/*.ts"]
2+
"extends": "@precisa-saude/tsconfig/library",
3+
"exclude": ["node_modules", "dist"]
154
}

0 commit comments

Comments
 (0)