Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions .github/workflows/templates.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Templates
name: Templates & Drift Check

on:
push:
Expand All @@ -11,10 +11,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v7

- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v7
with:
python-version: "3.11"

Expand Down Expand Up @@ -54,3 +54,14 @@ jobs:
if errors:
raise SystemExit("Template validation failed:\n" + "\n".join(errors))
PY

drift-check:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v7

- name: Drift-check repo org vs componenti condivisi
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: python scripts/drift_check.py
2 changes: 1 addition & 1 deletion .github/workflows/test-audit-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
audit-markers:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
fetch-depth: 0

Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
__pycache__/
*.pyc
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Non è l'hub pubblico del Lab. È il posto in cui teniamo ordine su GitHub.
- community health files
- policy comuni di collaborazione
- template per issue, pull request e discussions
- decisioni architetturali sul layer GitHub ([`docs/adr`](docs/adr/))
- profilo pubblico dell'organizzazione
- istruzioni minime su supporto, sicurezza e canali

Expand Down
95 changes: 95 additions & 0 deletions actions/python-ci/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
name: 'Python CI (org-level)'
description: |
Lint (ruff) + type check (mypy) + test (pytest) come step composabili,
con soglia coverage opzionale. Da usare DOPO python-setup in un job
del repo consumer (il checkout deve essere fatto PRIMA).

Ogni repo tiene il proprio scheletro di job e aggiunge step extra dopo
(build, upload coverage, validazioni specifiche): la composite action
rende uguali solo i passi comuni, non il job intero.

Usage:
- uses: actions/checkout@v7
- uses: dataciviclab/.github/actions/python-setup@main
with:
extra-packages: -e ".[dev]"
- uses: dataciviclab/.github/actions/python-ci@main
with:
lint_paths: "src tests"
mypy_paths: "src"
test_dir: "tests"
pytest_args: "-q -m \"not smoke\""
cov_module: "src"
cov_report: "term-missing xml"
cov_threshold: "80"

inputs:
lint_paths:
description: Path per `ruff check`.
required: true
mypy_paths:
description: Path per `mypy`; vuoto = step saltato.
required: false
default: ""
test_dir:
description: Directory dei test per pytest.
required: false
default: "tests"
pytest_args:
description: >
Argomenti pytest extra, passati tal quali alla shell
(es. "-q -m \"not smoke\"").
required: false
default: "-q"
cov_module:
description: >
Modulo per `--cov`; vuoto = nessuna misura coverage.
required: false
default: ""
cov_report:
description: >
Nomi report coverage separati da spazio (es. "term-missing xml").
Ogni nome diventa `--cov-report=<nome>`. Usato solo se cov_module
è valorizzato.
required: false
default: "term"
cov_threshold:
description: >
Soglia per `--cov-fail-under`; vuoto = nessun gate. Applicata anche
senza cov_module (per repo che misurano coverage dal config, es.
source-observatory con --cov-fail-under=60).
required: false
default: ""

runs:
using: "composite"
steps:
- name: Lint (ruff)
shell: bash
run: python -m ruff check ${{ inputs.lint_paths }}

- name: Type check (mypy)
if: inputs.mypy_paths != ''
shell: bash
run: python -m mypy ${{ inputs.mypy_paths }}

- name: Test (pytest)
shell: bash
env:
TEST_DIR: ${{ inputs.test_dir }}
PYTEST_ARGS: ${{ inputs.pytest_args }}
COV_MODULE: ${{ inputs.cov_module }}
COV_REPORT: ${{ inputs.cov_report }}
COV_THRESHOLD: ${{ inputs.cov_threshold }}
run: |
echo "::group::pytest"
cmd="python -m pytest $TEST_DIR $PYTEST_ARGS"
if [ -n "$COV_MODULE" ]; then
cmd="$cmd --cov=$COV_MODULE"
for r in $COV_REPORT; do cmd="$cmd --cov-report=$r"; done
fi
if [ -n "$COV_THRESHOLD" ]; then
cmd="$cmd --cov-fail-under=$COV_THRESHOLD"
fi
eval "$cmd"
echo "::endgroup::"
2 changes: 1 addition & 1 deletion actions/python-setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ inputs:
runs:
using: "composite"
steps:
- uses: actions/setup-python@v6
- uses: actions/setup-python@v7
with:
python-version: ${{ inputs.python-version }}
cache: 'pip'
Expand Down
151 changes: 151 additions & 0 deletions docs/adr/001-workflow-architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# ADR-001: Architettura dei workflow CI/pipeline del Lab

**Status:** proposed (2026-08-16)

## Contesto

I workflow GitHub Actions sono distribuiti in ~15 repo e crescono con logica
e dialetti diversi. Evidenza raccolta a 2026-08-16:

- **Versioni action disallineate**: `actions/checkout@v4/v5/v6/v6.0.3/v7` e
`actions/setup-python@v5/v6/v6.2.0/v7` mescolati tra repo.
- **Setup Python duplicato** con implementazioni diverse: 4 repo usano
`dataciviclab/.github/actions/python-setup@main`, ma `lab-connectors` e
`lab-dashboard` fanno `setup-python` + `pip install` inline.
- **Stesso passo reimplementato**:
- blocco preflight dei `dataset.yml` in 4 repo (eurostat, open-siope,
open-conto-annuale, dcl-bologna) con logiche simili ma eccezioni diverse;
- blocco "registry → diff → draft PR" post-merge in eurostat e open-siope
(~40 righe ciascuno);
- blocco "auth GCS (JSON/base64) → gcloud" duplicato.
- **Migrazione incompleta**: `test-audit-reusable.yml` è adottato da 3 repo,
ma `lab-connectors` ha ancora la copia inline.
- **Naming ambiguo**: `smoke-weekly.yml` significa cose diverse in
`lab-connectors` (probe manifest GCS) e `dataset-incubator` (probe
raggiungibilità fonti).
- **Soglie coverage arbitrarie**: 60/65/70/80/81 a seconda del repo.

Sintomo operativo: ogni modifica a un workflow rischia di "spaccare" o di
lasciare repo indietro (dimenticanze).

Alternative considerate:
- **Status quo** (logica in YAML, copie per-repo): non risolve drift e
dimenticanze; ogni fix va replicato a mano in ogni repo.
- **Centralizzazione totale in `.github`** (workflow unico per tutti i repo):
i workflow diventano un monolito con troppi input; le semantiche dataset
(dipendenze SIOPE, codelist, bootstrap varchi) non sono esprimibili senza
stravolgere il modello; perde visibilità e contesto per-repo.
- **Modello a 4 layer con delega** (scelta).

## Decisione

### 1. Modello a 4 layer

Dipendenza in una sola direzione, top-down:

```
YAML workflow = ORCHESTRATORE trigger, schedule, secrets, ambiente.
Nessuna logica: chiama solo target make.
Makefile per-repo = INTERFACCIA target stabili (lint/test/pipeline),
delega a comandi condivisi, zero logica.
Package org = IMPLEMENTAZIONE toolkit, lab-connectors: CLI versionati
e testati (toolkit run, registry build,
preflight, verify).
.github = COMPONENTI+REGOLE reusable workflow, composite action,
drift-check che impone il modello.
```

### 2. Regola d'oro

1. **La logica non vive mai in YAML.** Passi >10 righe di shell → package org
o script versionato.
2. **Stesso passo in 2+ repo → componente condiviso in `.github`**, non copia.
3. **Il Makefile non contiene logica**, solo delega a comandi condivisi.
4. **Locale == CI**: lo stesso comando `make` gira identico in locale e in CI;
il workflow chiama i target Makefile invece di replicare i comandi.

### 3. Confine semantico

Le semantiche dataset (dipendenze tra dataset, support seed, verify
specifici) restano per-repo: vivono in `dataset.yml` (dati, già dichiarativi)
e nel `pipeline.yml` orchestratore ridotto all'osso.

Criterio: *se il passo è piattaforma → condiviso; se è specifico del dataset
→ per-repo*. Le eccezioni (es. `varchi-ztl` skip, dipendenze SIOPE) restano
nel repo come input/condizioni, non come codice duplicato.

### 4. Catalogo componenti `.github` (target)

| Componente | Tipo | Sostituisce |
|---|---|---|
| `python-setup` | composite action | setup Python (già adottato, estendere a lab-connectors, lab-dashboard) |
| `python-ci` | composite action | CI Python (ruff+mypy+pytest) |
| `gcs-auth` | composite action | blocco auth GCS JSON/base64 |
| `dataset-config-check-reusable` | reusable workflow | blocchi preflight dei dataset |
| `registry-update-pr-reusable` | reusable workflow | blocco registry→diff→draft PR |
| `test-audit-reusable` | reusable workflow | già esistente; completare migrazione lab-connectors |

**Nota su `python-ci` (composite action, non reusable workflow):** i CI Python
dei repo differiscono per build job, upload coverage, validazioni extra e
soglie; un job reusable rigido costringerebbe a tagli o a troppi input.
La composite action rende uguali solo i passi comuni (lint/type/test) e lascia
a ogni repo il proprio scheletro con step extra dopo (stesso pattern di
`python-setup`).

### 5. Versioni e pinning

`checkout`, `setup-python` e dipendenze stanno dentro i componenti condivisi,
non nei workflow per-repo → il drift versioni si risolve in un solo posto e
dependabot si configura solo nel `.github`.

I consumer restano su `@main` finché il `.github` ha review; tag semver
(`@v1`) sono evoluzione futura se la frequenza di cambio cresce.

### 6. Processo di cambiamento

1. La modifica condivisa atterra in `.github` (o nel package org), mai nel
workflow di un singolo repo.
2. La CI di `.github` valida: actionlint + validate template + drift-check.
3. Il drift-check segnala i repo non migrati → issue + PR piccola per repo.
4. I repo nuovi nascono allineati via `project-template`.

### 7. Naming

Disambiguare `smoke-weekly` per scopo: `probe-weekly` (raggiungibilità fonti)
e `manifest-smoke-weekly` (catalog manifest GCS).

## Conseguenze

**Positive:**
- La logica vive una sola volta, versionata e testata nei package org → meno
"si spacca quando cambiamo un workflow".
- Le dimenticanze diventano visibili: il drift-check le segnala invece di
scoprirle per caso.
- Locale == CI: spariscono i bug "funziona in locale ma non in CI".
- I repo pipeline si leggono in ~15 righe di YAML + un Makefile.
- I repo nuovi (project-template) nascono conformi.

**Negative:**
- Indirezione iniziale: per capire un workflow serve seguire la catena
YAML → Makefile → package.
- Costo di migrazione dei repo esistenti (da fare uno alla volta).
- Rischio over-engineering se si estraggono componenti per passi usati da un
solo repo → la regola "2+ repo" è il gate.
- Rischio di Makefile per-repo che riproducono la stessa logica in dialetti
diversi → mitigato dal drift-check che verifica anche i target Makefile.

## Implementazione

1. [x] Questo ADR — review in `.github`
2. [x] `templates.yml` → drift-check (`scripts/drift_check.py`: ERROR su copie
inline dei reusable, WARN su setup-python inline e versioni action
fuori allowlist) — componenti condivisi allineati a canonical v7
3. [ ] Migrare `lab-connectors` su `python-setup` + `test-audit-reusable`
4. [x] Estrarre `python-ci` (composite action ruff+mypy+pytest) e migrare i
CI Python (toolkit, lab-connectors, source-observatory,
agent-context-builder, lab-dashboard)
5. [ ] Estrarre `dataset-config-check-reusable`, `gcs-auth`,
`registry-update-pr-reusable` e migrare i repo dataset (eurostat,
open-siope, open-conto-annuale, dcl-bologna)
6. [ ] Disambiguare `smoke-weekly`
7. [ ] Allineare `project-template` al modello
8 changes: 8 additions & 0 deletions docs/adr/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Architecture Decision Records

Decisioni architetturali sul layer GitHub dell'organizzazione
(workflow, template, policy), in ordine cronologico.

| ADR | Titolo | Data |
|---|---|---|
| [001](001-workflow-architecture.md) | Architettura dei workflow CI/pipeline del Lab | 2026-08-16 |
Loading
Loading