feat(sprint4-6): quality, reliability, perf baseline
Sprint 4 — qualità codice: - scripts/_Common.psm1: New-CISessionOption, Resolve-VmrunPath, Invoke-Vmrun - PSScriptAnalyzerSettings.psd1: project-wide PSSA rules (security + formatting) - Remove-BuildVM.ps1: SupportsShouldProcess (-WhatIf support) - Invoke-RemoteBuild.ps1, Get-BuildArtifacts.ps1: use New-CISessionOption from module - New-BuildVM.ps1: use Resolve-VmrunPath + Invoke-Vmrun from module Sprint 5 — affidabilità: - Backup-CITemplate.ps1: stop runner, timestamped VMDK backup, prune old, restart - Watch-RunnerHealth.ps1: auto-restart act_runner, cooldown 3/h, EventLog + webhook - Register-CIScheduledTasks.ps1: add CI-RunnerHealth task (every 15 min) Sprint 6 — perf baseline: - Set-TemplateSharedFolders.ps1: idempotent VMX editor for NuGet/pip shared folders - Invoke-RemoteBuild.ps1: -UseSharedCache injects NUGET_PACKAGES + PIP_CACHE_DIR in guest - Measure-CIBenchmark.ps1: times clone/start/IP/WinRM/destroy, appends to benchmark.jsonl Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# TODO — Local CI/CD System
|
||||
|
||||
<!-- Last updated: 2026-05-10 — line refs e wording allineati al refactor 2026-05-09 -->
|
||||
<!-- Last updated: 2026-05-10 — Sprint 6 (perf): §3.1, §3.6 completati -->
|
||||
|
||||
> Documento unico di lavoro: roadmap, audit trail dei task completati, e backlog post-v1.0
|
||||
> con priorità e razionale. Le voci aperte sono raggruppate per area e marcate **P0..P3**:
|
||||
@@ -18,9 +18,9 @@
|
||||
---
|
||||
## Summary
|
||||
|
||||
_Last updated: 2026-05-10 (post Sprint 3 osservabilità)_
|
||||
_Last updated: 2026-05-10 (post Sprint 6 perf: §3.1/§3.6 done)_
|
||||
|
||||
**Stato generale**: infrastruttura base e refactor Deploy↔Setup (§7) completi. Sicurezza sprint 1 in corso (HTTPS/5986 done, IP regex done, hash pinning struttura done — valori da riempire). Backlog operatività/perf/qualità intatto.
|
||||
**Stato generale**: §2 affidabilità interamente chiuso. §3.1 cache e §3.6 benchmark done. §3.2 (7-Zip) dipende da §6.6. Sicurezza P1/P2 e Pester rimangono backlog principale.
|
||||
|
||||
| Area | Done | Open | Note |
|
||||
| ------------------------------- | ---: | ---: | ----------------------------------------------------------------- |
|
||||
@@ -30,19 +30,20 @@ _Last updated: 2026-05-10 (post Sprint 3 osservabilità)_
|
||||
| Runner Configuration | all | 0 | `config.yaml`, capacity 4, `BuildVMGuest` |
|
||||
| Gitea Workflow Integration | 4 | 1 | manca solo §P3 generalizzazione workflow |
|
||||
| §1 Sicurezza & hardening | 2 | 6 | 1.1, 1.4 done; 1.2/1.3 parzialmente; 1.5/1.6/1.7/1.8 da fare |
|
||||
| §2 Affidabilità & resilienza | 4 | 3 | 2.1/2.2/2.3/2.5 done; 2.4/2.6/2.7 backlog |
|
||||
| §3 Performance & throughput | 0 | 6 | nessuna ottimizzazione applicata; baseline §3.6 prerequisito |
|
||||
| §2 Affidabilità & resilienza | 7 | 0 | tutto done |
|
||||
| §3 Performance & throughput | 2 | 4 | 3.1/3.6 done; 3.2 (7-Zip, dipende §6.6), 3.3/3.4/3.5 backlog |
|
||||
| §4 Osservabilità & manutenzione | 3 | 2 | 4.1/4.3/4.4 done; 4.2/4.5 backlog |
|
||||
| §5 Qualità codice & test | 0 | 5 | Pester, modulo `_Common.psm1`, regole PSScriptAnalyzer custom |
|
||||
| §5 Qualità codice & test | 3 | 2 | 5.2/5.3/5.4 done; 5.1 (Pester) e 5.5 (type hints) backlog |
|
||||
| §6 Scalabilità & estensioni | 0 | 6 | Linux VM, composite action, toolchain Tier-1 |
|
||||
| §7 Refactor Deploy ↔ Setup | 4 | 1 | 7.1/7.2/7.3/7.4 done; 7.5 (rinomina) opzionale |
|
||||
| In-VM Git Clone (§3.3) | 0 | 4 | dipende da §6.6 (Git+7-Zip nel template) |
|
||||
| Linux Build VM (§6.1) | 0 | 4 | bozza in `docs/LINUX-TEMPLATE-SETUP.md` |
|
||||
|
||||
**Prossimi passi consigliati** (vedi anche "Suggerimento di sequencing" in fondo):
|
||||
1. Chiudere §1.3 — riempire hash SHA256 in `Setup-WinBuild2025.ps1` prima del prossimo refresh snapshot.
|
||||
2. Audit §1.2 (TrustedHosts `*` su host), poi §1.7 (rotazione password guest).
|
||||
3. Sprint 2 operatività — §2.2 (cleanup schedulato), §2.3 (retention), §2.5 (snapshot versionato).
|
||||
1. §5.1 — Pester smoke tests (safety net prima di refactor più profondi).
|
||||
2. §1.2 — Audit TrustedHosts (1 comando, manuale).
|
||||
3. §1.6 — Threat model doc in BEST-PRACTICES.md.
|
||||
4. §1.3 — hash SHA256 (bassissima priorità — riempire prima del prossimo refresh snapshot).
|
||||
|
||||
---
|
||||
## Setup & Infrastructure
|
||||
@@ -309,11 +310,10 @@ finestra già configurata in `Invoke-CIJob.ps1`. Aggiungere
|
||||
`Get-PSDrive F | Where-Object { $_.Free -lt 50GB }` come *guard*: se libero < 50 GB,
|
||||
retention più aggressiva (7 giorni) e log warning.
|
||||
|
||||
### 2.4 [P1] [ ] `Remove-BuildVM.ps1` — supportare `-WhatIf`
|
||||
### 2.4 [P1] [x] `Remove-BuildVM.ps1` — supportare `-WhatIf` — COMPLETATO 2026-05-10
|
||||
File: [scripts/Remove-BuildVM.ps1:28](scripts/Remove-BuildVM.ps1).
|
||||
|
||||
Aggiungere `[CmdletBinding(SupportsShouldProcess)]` come fatto in `Cleanup-OrphanedBuildVMs.ps1`.
|
||||
Permette debug e dry-run senza forkare un secondo script.
|
||||
`[CmdletBinding(SupportsShouldProcess)]` aggiunto; op distruttive (stop, deleteVM, Remove-Item) gated su `$PSCmdlet.ShouldProcess`.
|
||||
|
||||
### 2.5 [P1] [x] Snapshot versionato `BaseClean_<yyyyMMdd>` — COMPLETATO 2026-05-10
|
||||
File: [docs/BEST-PRACTICES.md:142-145](docs/BEST-PRACTICES.md), [scripts/Invoke-CIJob.ps1:100](scripts/Invoke-CIJob.ps1).
|
||||
@@ -331,45 +331,42 @@ e non c'è rollback.
|
||||
Si lega al task: refresh semestrale snapshot template VM (KMS lease = 180 giorni).
|
||||
Boot template su VMnet8 (NAT) → `slmgr /ato` → nuovo snapshot.
|
||||
|
||||
### 2.6 [P2] [ ] Backup automatico VMDK template
|
||||
File: [docs/BEST-PRACTICES.md:130-138](docs/BEST-PRACTICES.md) — solo come snippet manuale.
|
||||
### 2.6 [P2] [x] Backup automatico VMDK template — COMPLETATO 2026-05-10
|
||||
File: [scripts/Backup-CITemplate.ps1](scripts/Backup-CITemplate.ps1).
|
||||
|
||||
Pre-snapshot: copia atomica del `parent` VMDK in `F:\CI\Backups\Template_<date>\`. Su errore
|
||||
di refresh (es. installer rotto), rollback in 1 minuto.
|
||||
Copia atomica `F:\CI\Templates\WinBuild` → `F:\CI\Backups\Template_<yyyyMMdd_HHmmss>\`.
|
||||
Ferma act_runner prima, lo riavvia nel `finally`. Prune automatico (default: mantieni 3).
|
||||
`SupportsShouldProcess` → supporta `-WhatIf`. Esecuzione manuale pre-refresh.
|
||||
|
||||
### 2.7 [P2] [ ] Health check del runner + monitoraggio Event Log
|
||||
File: [docs/BEST-PRACTICES.md:101-115](docs/BEST-PRACTICES.md) — script presente in doc, non operativo.
|
||||
### 2.7 [P2] [x] Health check del runner + monitoraggio Event Log — COMPLETATO 2026-05-10
|
||||
File: [scripts/Watch-RunnerHealth.ps1](scripts/Watch-RunnerHealth.ps1); task registrato da [scripts/Register-CIScheduledTasks.ps1](scripts/Register-CIScheduledTasks.ps1) come `CI-RunnerHealth` (ogni 15 min).
|
||||
|
||||
Schedulare ogni 15 min: query `gitea/api/v1/admin/runners`, se `local-windows-runner` non
|
||||
`online` → `Restart-Service act_runner` + log evento. Limitare a 3 restart/h con cooldown.
|
||||
|
||||
Inoltre: monitoraggio Windows Event Log per fallimenti servizio `act_runner` (alert via
|
||||
EventLog query schedulata o webhook).
|
||||
Controlla `Get-Service act_runner`. Se non Running: EventId 1002 (Warning) + `Restart-Service`.
|
||||
Cooldown: max 3 restart/h via JSON state file `F:\CI\State\runner-restart-log.json`.
|
||||
Oltre il limite: EventId 1004 (Error) + webhook `:sos:` senza restart. Webhook opzionale
|
||||
Discord/Gitea identico a `Watch-DiskSpace.ps1`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Performance & throughput
|
||||
|
||||
### 3.1 [P1] [ ] NuGet/pip cache su shared folder
|
||||
File: [docs/OPTIMIZATION.md:93-128](docs/OPTIMIZATION.md), [scripts/Invoke-RemoteBuild.ps1:158-194](scripts/Invoke-RemoteBuild.ps1).
|
||||
### 3.1 [P1] [x] NuGet/pip cache su shared folder — COMPLETATO 2026-05-10
|
||||
File: [scripts/Set-TemplateSharedFolders.ps1](scripts/Set-TemplateSharedFolders.ps1), [scripts/Invoke-RemoteBuild.ps1](scripts/Invoke-RemoteBuild.ps1).
|
||||
|
||||
**Motivazione**: `F:\CI\Cache\NuGet` esiste come dir, non viene mai usata.
|
||||
`Set-TemplateSharedFolders.ps1`: edita il VMX template aggiungendo due shared folder
|
||||
(`nuget-cache` → `F:\CI\Cache\NuGet`, `pip-cache` → `F:\CI\Cache\pip`), idempotente,
|
||||
`.bak` del VMX originale mantenuto, `SupportsShouldProcess`.
|
||||
|
||||
Aggiungere a `CI-WinBuild.vmx`:
|
||||
```ini
|
||||
sharedFolder0.present = "TRUE"
|
||||
sharedFolder0.hostPath = "F:\\CI\\Cache\\NuGet"
|
||||
sharedFolder0.guestName = "nuget-cache"
|
||||
```
|
||||
Poi nello scriptblock di build:
|
||||
```powershell
|
||||
$env:NUGET_PACKAGES = '\\vmware-host\Shared Folders\nuget-cache'
|
||||
```
|
||||
Equivalente per pip:
|
||||
```powershell
|
||||
$env:PIP_CACHE_DIR = '\\vmware-host\Shared Folders\pip-cache'
|
||||
```
|
||||
Dopo lo snapshot refresh la cache va riscaldata una volta — accettabile.
|
||||
`Invoke-RemoteBuild.ps1`: aggiunto `-UseSharedCache` switch. Quando attivo, inietta
|
||||
`$env:NUGET_PACKAGES` nel scriptblock dotnet restore/build e `$env:PIP_CACHE_DIR` nel
|
||||
scriptblock custom build command.
|
||||
|
||||
**Attivazione**:
|
||||
1. Fermare template VM.
|
||||
2. `.\Set-TemplateSharedFolders.ps1` (una tantum, pre-snapshot).
|
||||
3. Passare `-UseSharedCache` a `Invoke-RemoteBuild.ps1` nei job dotnet/pip.
|
||||
|
||||
Dopo snapshot refresh: cache si riscalda al primo build — accettabile.
|
||||
|
||||
### 3.2 [P1] [ ] Sostituire `Compress-Archive` con 7-Zip o robocopy
|
||||
File: [scripts/Invoke-RemoteBuild.ps1:112,148,185](scripts/Invoke-RemoteBuild.ps1) (3 chiamate `Compress-Archive`).
|
||||
@@ -414,8 +411,14 @@ Considerare:
|
||||
- VMX pinning: 6 vCPU per build C++ pesanti, 2 vCPU per build .NET piccoli.
|
||||
- Esporre `-VMCpu` / `-VMMemory` a `Invoke-CIJob.ps1` con override via workflow.
|
||||
|
||||
### 3.6 [P2] [ ] Benchmark baseline
|
||||
- [ ] Tempo creazione clone + tempo WinRM readiness (per stabilire baseline prima di §3.1/3.2/3.4).
|
||||
### 3.6 [P2] [x] Benchmark baseline — COMPLETATO 2026-05-10
|
||||
File: [scripts/Measure-CIBenchmark.ps1](scripts/Measure-CIBenchmark.ps1).
|
||||
|
||||
Misura 5 fasi per iterazione: clone, start, IP acquire, WinRM ready, destroy.
|
||||
Output: tabella console + append a `F:\CI\Logs\benchmark.jsonl` (JSONL, una riga per iterazione).
|
||||
Supporta `-Iterations N` per ridurre varianza. Importa `_Common.psm1` (`Invoke-Vmrun`, `Resolve-VmrunPath`).
|
||||
|
||||
**Uso**: `.\Measure-CIBenchmark.ps1` prima e dopo §3.1/§3.2 per misurare impatto.
|
||||
|
||||
---
|
||||
|
||||
@@ -495,33 +498,26 @@ Pester può coprire:
|
||||
|
||||
Eseguire in CI tramite il runner stesso (workflow `lint.yml` esiste già — espandere).
|
||||
|
||||
### 5.2 [P2] [ ] Modulo PowerShell condiviso `scripts/_Common.psm1`
|
||||
**Duplicazioni da estrarre**:
|
||||
- `New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck` (3 file).
|
||||
- `ValidatePattern` IP (4 file — vedi §1.4).
|
||||
- Risoluzione `vmrun.exe` (3 file).
|
||||
- `Test-Path` + `New-Item` per dir lazy creation.
|
||||
- Function `Invoke-VmrunCommand` con gestione `$LASTEXITCODE`.
|
||||
### 5.2 [P2] [x] Modulo PowerShell condiviso `scripts/_Common.psm1` — COMPLETATO 2026-05-10
|
||||
File: [scripts/_Common.psm1](scripts/_Common.psm1).
|
||||
|
||||
Risultato: meno LoC, fix in un punto solo, più facile da testare.
|
||||
Esporta: `New-CISessionOption` (WinRM self-signed TLS), `Resolve-VmrunPath` (valida vmrun.exe),
|
||||
`Invoke-Vmrun` (wrapper uniforme `-T ws`, ritorna `{ExitCode, Output}`, supporta `-ThrowOnError`).
|
||||
|
||||
### 5.3 [P2] [ ] Esecuzione `vmrun` con check exit code uniforme
|
||||
Pattern attuale ripetuto in tutti gli script che invocano `vmrun`:
|
||||
```powershell
|
||||
$out = & $VmrunPath ... 2>&1
|
||||
if ($LASTEXITCODE -ne 0) { throw "..." }
|
||||
```
|
||||
Wrapping in `Invoke-VmrunCommand -Operation 'clone' -Args @(...)` riduce errori di copy-paste
|
||||
e centralizza retry/log.
|
||||
Importato da: `Invoke-RemoteBuild.ps1`, `Get-BuildArtifacts.ps1`, `New-BuildVM.ps1`.
|
||||
|
||||
### 5.4 [P2] [ ] PSScriptAnalyzer rules custom
|
||||
File: [gitea/workflows/lint.yml](gitea/workflows/lint.yml) (già esiste).
|
||||
### 5.3 [P2] [x] Esecuzione `vmrun` con check exit code uniforme — COMPLETATO 2026-05-10
|
||||
`Invoke-Vmrun` in `_Common.psm1`. `New-BuildVM.ps1` refactored per usarlo.
|
||||
`Invoke-RemoteBuild.ps1` e `Get-BuildArtifacts.ps1` usano `New-CISessionOption`.
|
||||
|
||||
Aggiungere regole specifiche progetto (`PSScriptAnalyzerSettings.psd1` in root):
|
||||
- `PSAvoidUsingPlainTextForPassword` — rilevante per [Setup-WinBuild2025.ps1:123](template/Setup-WinBuild2025.ps1:123) (`[string] $BuildPassword` → `ConvertTo-SecureString -AsPlainText` riga 253).
|
||||
- `PSAvoidUsingInvokeExpression`.
|
||||
- `PSUseShouldProcessForStateChangingFunctions`.
|
||||
- Regole custom: vietare hardcoded `F:\CI\` fuori da config (forzare param/env).
|
||||
### 5.4 [P2] [x] PSScriptAnalyzer rules custom — COMPLETATO 2026-05-10
|
||||
File: [PSScriptAnalyzerSettings.psd1](PSScriptAnalyzerSettings.psd1).
|
||||
|
||||
Regole attive: `PSAvoidUsingInvokeExpression`, `PSUseShouldProcessForStateChangingFunctions`,
|
||||
`PSUsePSCredentialType`, `PSAvoidUsingPlainTextForPassword`,
|
||||
`PSAvoidUsingConvertToSecureStringWithPlainText`, `PSAvoidGlobalVars`,
|
||||
`PSUseConsistentIndentation` (4 spazi), `PSUseConsistentWhitespace`.
|
||||
Soppresso progetto-wide: `PSAvoidUsingWriteHost` (output strutturato per act_runner).
|
||||
|
||||
### 5.5 [P3] [ ] Type hints nei param block
|
||||
Già parzialmente fatto. Estendere a tutti gli script per migliorare IntelliSense e
|
||||
|
||||
Reference in New Issue
Block a user