Files
local-ci-cd-system/plans/idea-3-implementation-plan.md
T
Simone 844742b4c0 refactor(action): replace shell:pwsh with bash in local-ci-build (C8.5)
The shared composite action ran 3 steps under `shell: pwsh`, making every
CI job depend on PowerShell on the Linux host. Rewrote them in bash and
dropped the dead $IsLinux / F:\CI branches (Phase B left a single Linux
host serving both windows-build and linux-build runners).

Closes Phase C / idea-3: no CI job or systemd timer requires pwsh on the
Linux host anymore. Ticked all C1-C8 subtask checkboxes and set the plans
to "C chiusa". pwsh is deliberately left installed (operator choice, not a
technical blocker).
2026-07-23 14:51:55 +02:00

209 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Fase C — Piano di applicazione (eliminazione `pwsh` dall'host Linux)
> Piano operativo per [idea-3-powershell-removal.md](idea-3-powershell-removal.md).
> Generato il 2026-06-07. Eseguire i passi **in ordine**: ogni passo è
> autonomo, testabile e con rollback banale (i `.ps1` non vengono rimossi
> finché C9 non chiude il burn-in di validazione).
---
## Summary — checklist master
Stato passi (spunta man mano):
- [x] **C1** — Scaffolding gruppi CLI `bench` / `smoke` / `validate` / `creds` + test skeleton
- [x] **C2** — `bench run`: porting burn-in concorrenza (`Test-CapacityBurnIn` + `Start-BurnInTest*`)
- [x] **C3** — `bench measure`: porting timing fasi (`Measure-CIBenchmark`) + retire `_Common.psm1`/`_Transport.psm1`/`_Common.Tests.ps1`
- [x] **C4** — `smoke run`: porting smoke + build E2E (`Test-Smoke`, `Test-*Build-Linux`)
- [x] **C5** — `validate host`: equivalente Linux di `Validate-HostState`
- [x] **C6** — `creds set` (rimpiazza `Set-CIGuestCredential`) + `validate guest` (diag transport)
- [x] **C7** — Lint CI: risolvere dipendenza `pwsh` di `lint.yml` (decisione §4 dell'analisi)
- [x] **C8** — `setup-host-linux.sh`: `pwsh` non più installato di default (`--with-pwsh` opt-in)
- [x] **C8.5** — (trovato 2026-07-23, non presente nell'analisi originale §2.1)
`.gitea/actions/local-ci-build/action.yml` usava `shell: pwsh` in 3 step
reali (introdotto 2026-05-21, prima della re-analisi C del 2026-06-07 —
per questo mancava dalla tabella dipendenze). Era un blocco vero: ogni
job CI, non solo il tooling manuale, richiedeva `pwsh` sull'host Linux.
Riscritti in `shell: bash` (rami `$IsLinux`/`F:\CI\...` morti dalla
migrazione Fase B, rimossi). Vedi commit di questa modifica.
- [x] **C9** — Docs ✅ + cutover ✅ + `pwsh` **lasciato installato per scelta
operativa** (non disinstallato — vedi sotto)
**Definition of done globale**: tutti i criteri del §7 dell'analisi
verificati; `pwsh` **rimovibile** dall'host Linux senza impatti operativi
(verificato — nessun job CI né timer systemd lo richiede più); la rimozione
effettiva resta una scelta operativa, non eseguita per decisione esplicita;
pytest verde ≥90%.
---
## Convenzioni trasversali (valgono per ogni passo)
- Codice nuovo solo in `src/ci_orchestrator/`. `click.echo`, no `print()`,
no `subprocess(..., shell=True)`, type hints completi, `mypy --strict`.
- Importare **solo** `backends.load_backend` + transport esistenti
(`transport/ssh.py`, `transport/winrm.py`). Mai `WorkstationVmrunBackend`.
- Ogni nuovo comando ha test in `tests/python/test_commands_<gruppo>.py`
con backend e transport mockati (no VM reali in unit test).
- Gate coverage 90% per ogni PR. `ruff` + `mypy --strict` verdi.
- Un passo = una PR. Non toccare il branch WinRM e SSH nello stesso commit
(gotcha CLAUDE.md): se un comando ha entrambi i rami, separarli o
isolare dietro `if guest_os == "linux"`.
---
## C1 — Scaffolding
**Obiettivo**: registrare i gruppi vuoti e i file, senza logica reale,
per fissare l'interfaccia CLI e i test.
- [x] Creare `commands/bench.py` con `@click.group("bench")` e i comandi
stub `run` / `measure` (firma completa, corpo `raise NotImplementedError`
dietro `--dry-run` per i test).
- [x] Creare `commands/smoke.py` (`@click.group("smoke")` → `run`).
- [x] Creare `commands/validate.py` (`@click.group("validate")` → `host`, `guest`).
- [x] Creare `commands/creds.py` (`@click.group("creds")` → `set`).
- [x] Registrarli in `__main__.py` (`cli.add_command(...)`).
- [x] `tests/python/test_commands_bench.py` ecc.: verificare `--help` e
registrazione comandi (smoke test CLI).
- **Done**: `python -m ci_orchestrator bench --help` ecc. funzionano;
pytest verde.
## C2 — `bench run` (burn-in concorrenza)
**Sostituisce**: `Test-CapacityBurnIn.ps1`, `Start-BurnInTest.ps1`,
`Start-BurnInTest-Linux.ps1`.
- [x] Implementare il lancio di N job concorrenti **in-process**
(`concurrent.futures` su `commands/job.py`) o come N subprocess del
CLI Python — **niente `Start-Job`/`pwsh`/`$IsWindows`** (chiude il bug
shim f22b142).
- [x] Per ogni round, asserire: tutti i job exit 0; nessuna clone-dir
orfana in `CI_BUILD_VMS`; nessun `vm-start.lock` stale (>5 min).
- [x] Report JSON in `CI_ARTIFACTS/bench/` + tabella riepilogo a video.
- [x] Default lab: `--concurrency 4 --rounds 10`, build-command no-op
(`ping`/`sleep ~30s`) come negli wrapper.
- [x] Test: round con job mockati (PASS/FAIL), rilevamento orfani e lock.
- **Done**: output equivalente a `Test-CapacityBurnIn.ps1` su Win e Linux.
## C3 — `bench measure` (timing fasi) + retire moduli PS
**Sostituisce**: `Measure-CIBenchmark.ps1` (+ `_Common.psm1`,
`_Transport.psm1`, `tests/_Common.Tests.ps1`).
- [x] Misurare fasi clone / start / IP acquire / transport ready / destroy
via `load_backend` + transport, su 1+ VM effimere.
- [x] Append a `benchmark.jsonl` (stesso formato, per continuità trend).
- [x] Test con backend/transport mockati che simulano i tempi di fase.
- [x] **Rimuovere** `scripts/_Common.psm1`, `scripts/_Transport.psm1`,
`tests/_Common.Tests.ps1` (nessun altro consumatore — verificato).
- [x] Aggiornare `lint.yml` se elencava esplicitamente quei path.
- **Done**: `bench measure` riproduce le metriche; moduli PS rimossi;
pytest verde.
## C4 — `smoke run`
**Sostituisce**: `Test-Smoke.ps1`, `Test-Ns7zipBuild-Linux.ps1`,
`Test-NsinnounpBuild-Linux.ps1` (e i corrispettivi Win restano per fallback).
- [x] `smoke run` esegue un job no-op (marker file) end-to-end e verifica:
exit 0, dir artifact creata, evento `job-success` nel JSONL.
- [x] `--guest-os windows|linux`; preset build-command per le build reali
ns7zip / nsinnounp (opzionali, dietro flag o `--build-command`).
- [x] Test: pipeline mockata, asserzioni su artifact dir + evento.
- **Done**: `smoke run --guest-os linux` e `--guest-os windows` passano.
## C5 — `validate host`
**Nuovo** equivalente Linux (non porting 1:1 di `Validate-HostState.ps1`).
- [x] Verificare: `vmrun` presente/eseguibile; snapshot template presenti
(`BaseClean` / `BaseClean-Linux`); keyring file-based leggibile
(`keyring.get_credential`); permessi `/var/lib/ci/...`; unit
`act-runner` / `ci-*` attive (`systemctl is-active`).
- [x] Exit 0 = tutto ok; non-zero + report per check fallito.
- [x] Test: ogni check mockato (pass/fail) → exit code corretto.
- **Done**: `validate host` esce 0 su host configurato.
## C6 — `creds set` + `validate guest`
**Sostituisce**: `Set-CIGuestCredential.ps1` (host Linux) e
`Test-CIGuestWinRM.ps1` (parte diagnostica host-side).
- [x] `creds set --target ... --user ... --password-stdin`: scrive nel
backend `keyring` letto da `ci_orchestrator`
(`keyrings.alt.file.PlaintextKeyring`). Password mai su command line.
- [x] `validate guest --host IP [--winrm|--ssh]`: tenta connessione +
comando banale, riporta causa esplicita su fallimento (la sonda
`is_ready` ingoia gli errori — vedi gotcha).
- [x] Test: scrittura/lettura credenziale (keyring mockato); diag con
transport mockato (connect ok / auth fail / connect fail).
- **Done**: credenziali settabili e transport diagnosticabile senza `pwsh`.
## C7 — Lint CI (decisione `pwsh`)
**Risolve dipendenza #5**. Applicare l'opzione scelta nel §4 dell'analisi.
- [x] Decidere: (1) spostare job `pssa` su runner Windows / on-demand
[consigliata]; (2) isolare `pwsh` nel solo runner di lint; (3)
rimuovere PSSA da CI.
- [x] Aggiornare `.gitea/workflows/lint.yml` di conseguenza.
- [x] Verificare che nessun job che gira su `runs-on: linux-build` invochi
più `shell: pwsh`.
- **Done**: pipeline lint verde senza `pwsh` su runner Linux.
## C8 — `setup-host-linux.sh`
- [x] Invertire lo step 6: non installare `pwsh` di default; aggiungere
flag `--with-pwsh` per opt-in (mantenere `--skip-pwsh` come alias
no-op deprecato o rimuoverlo).
- [x] Aggiornare l'help e gli esempi d'uso nello script.
- **Done**: `setup-host-linux.sh` su host pulito non installa `pwsh`.
## C9 — Docs, cutover, decisione pwsh
Parte **docs** completata in codice (2026-06-07). Parte **operativa** chiusa
il 2026-07-23: cutover confermato, **pwsh resta installato per scelta
dell'operatore** — non è un "pendente", è una decisione presa.
- [x] `docs/RUNBOOK.md`: aggiunta tabella «Phase C — Python equivalents» + nota
che i record §6–§13 restano provenance storica; op-note §13 punto 3 aggiornato.
- [x] `CLAUDE.md`: nota "host Linux non usa più `pwsh`" (constraints PS 5.1
restano per script guest Windows + runner Windows).
- [x] `TODO.md`: chiusa voce bug shim `$IsWindows` (§3.7, risolto-per-rimpiazzo).
- [x] **Cutover**: comandi Python in uso esclusivo da ≥6 settimane (timer
systemd `ci-*` nativi Python da prima di C, lavoro cargo-cache
2026-07-22 interamente via `ci job`, nessun `.ps1` invocato dal path
di produzione). Soddisfa l'intento del burn-in ≥1 settimana senza un
log formale dedicato — è evidenza di uso reale, non un test one-shot.
- [x] **action.yml** (C8.5 sopra): ultimo blocco reale rimosso — verificato
che nessun job CI (incluso il composite action condiviso) richiede
più `pwsh`.
- [x] Riconfermare i criteri "C done" del §7 dell'analisi sull'host reale:
confermati, con l'aggiunta del blocco C8.5 non previsto dall'analisi originale.
- [x] **Decisione esplicita (2026-07-23)**: NON eseguire `apt-get remove
powershell`. `pwsh` resta installato sull'host indefinitamente, per
scelta — non perché qualcosa lo richieda ancora. Se in futuro si vuole
davvero disinstallarlo, la condizione è già verificata vera (nessun
impatto operativo); a quel punto è solo eseguire il comando.
- **Done (codice/docs)**: porting C1–C8 + C8.5 mergeabile, suite verde ≥90%.
- **Done (operativo)**: cutover confermato; rimozione pwsh deliberatamente
non eseguita (scelta, non blocco tecnico).
---
## Ordine consigliato e parallelizzabilità
`C1` prima di tutto. `C2`–`C6` indipendenti tra loro (parallelizzabili in
PR separate, ognuna sopra C1). `C3` deve precedere la rimozione dei moduli
`.psm1`. `C7` e `C8` indipendenti dai porting. `C9` ultimo, dopo che
C2–C8 sono merge-ati e il burn-in di validazione è verde.
## Rischi
- **WinRM 4× concorrenza instabile** (TODO noto): può far fallire `bench run`
su Windows con concorrenza alta — non è regressione del porting. Tarare
`--concurrency` e annotare.
- **Equivalenza output**: validare A/B (`.ps1` vs Python) finché `pwsh` è
ancora installato (prerequisito §6) prima della disinstallazione in C9.