§4.1 — Structured JSONL log (Invoke-CIJob.ps1)
Each job now emits a parallel invoke-ci.jsonl alongside the transcript.
Write-JobEvent appends one JSON line per phase transition (ts, jobId,
phase, status, data). Events emitted at: job.start, phase1.clone-repo
start/success, phase2-3b.vm-start start/success, phase4.wait-ready
start/success, phase5.build start/success, phase6.artifacts start/success,
job.success/failure (with elapsedSec and error string).
Silent no-op if $jsonLog is null (log dir setup failed). Errors in
Write-JobEvent are swallowed — logging never breaks the build.
Enables post-hoc per-phase duration analysis with jq or ConvertFrom-Json.
§4.3 — Disk space alert (scripts/Watch-DiskSpace.ps1)
Checks drive free space every 15 min (scheduled by Register-CIScheduledTasks).
Below MinFreeGB (default 50 GB): writes Warning to Windows Application Event Log
(source CI-DiskAlert, EventId 1001) and exits 1 so Task Scheduler flags the run.
Optional -WebhookUrl for Discord/Gitea webhook notification.
Register-CIScheduledTasks.ps1 updated with Task 3: CI-DiskSpaceAlert (every 15 min).
§4.4 — Incident runbook (docs/RUNBOOK.md)
Four scenarios with symptom / triage commands / fix / escalation:
1. Runner offline in Gitea UI
2. All builds fail in Phase 2 (clone/start/IP)
3. Builds are slow (per-phase JSONL analysis, disk/CPU/NAT checks)
4. Template VMX corrupt after host crash (lock removal + backup restore)
Quick-reference table at the end.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Local CI/CD System
Sistema CI/CD self-hosted su Windows per build isolati in VM efimere VMware.
Stato: production-ready — e2e verificato (e2e-009 SUCCESS)
Panoramica
Il runner act_runner riceve i job da Gitea Actions.
Per ogni job, lo script Invoke-CIJob.ps1 orchestra l'intero ciclo:
Gitea push/tag
│
▼
act_runner (Windows service, label: windows-build)
│
▼
Invoke-CIJob.ps1
│
├─ 1. git clone repo su host (con submoduli)
├─ 2. Linked clone da snapshot BaseClean
├─ 3. Avvio VM headless
├─ 4. Attesa WinRM ready
├─ 5. Zip transfer → build via WinRM → raccolta artifacts
├─ 6. Copia artifacts in F:\CI\Artifacts\<jobid>\
└─ finally: stop + rimozione VM clone
Ogni build gira in una VM Windows Server 2025 usa e getta, ripristinata dallo snapshot BaseClean ad ogni run.
Requisiti Host
| Componente | Versione / Dettaglio |
|---|---|
| OS | Windows 11 |
| CPU/RAM | i9-10900X, 64 GB RAM |
| VMware Workstation Pro | installato, vmrun.exe disponibile |
| PowerShell | 5.1 |
| act_runner | v1.0.2 — F:\CI\act_runner\act_runner.exe |
| Gitea | self-hosted http://10.10.20.11:3100 / https://gitea.emulab.it |
Template VM (snapshot BaseClean)
| Componente | Versione |
|---|---|
| OS | Windows Server 2025 |
| VMX | F:\CI\Templates\WinBuild\CI-WinBuild.vmx |
| VS Build Tools | 2026 (MSBuild 18.5.4 / toolset v145) |
| .NET SDK | 10.0.203 |
| Python | 3.13.3 |
| Rete | VMnet8 NAT — 192.168.79.0/24 |
| WinRM | HTTPS/5986, Basic auth, self-signed cert (SkipCACheck — lab-only) |
Struttura repository
├── Setup-Host.ps1 # Bootstrap host: dirs F:\CI\, credenziali, act_runner service
│
├── scripts/
│ ├── Invoke-CIJob.ps1 # Orchestratore principale
│ ├── New-BuildVM.ps1 # Linked clone da template
│ ├── Wait-VMReady.ps1 # Polling WinRM readiness
│ ├── Invoke-RemoteBuild.ps1 # Zip transfer + esecuzione build in VM
│ ├── Get-BuildArtifacts.ps1 # Copia artifacts dall'host
│ └── Remove-BuildVM.ps1 # Stop + rimozione VM clone
│
├── template/
│ ├── Prepare-WinBuild2025.ps1 # Provisioning automatico template VM (HOST-side)
│ └── Setup-WinBuild2025.ps1 # Installazione toolchain nella VM (GUEST-side)
│
├── gitea/
│ ├── workflows/
│ │ └── build-nsis.yml # Workflow live per nsis-plugin-nsinnounp
│ └── workflow-example.yml # Template generico adattabile
│
├── runner/
│ └── config.yaml # Configurazione act_runner (no secrets)
│
├── docs/
│ ├── ARCHITECTURE.md # Diagramma sistema e componenti
│ ├── CI-FLOW.md # Flusso dettagliato passo-passo
│ ├── OPTIMIZATION.md # Layout disco, snapshot, cache, tuning
│ ├── BEST-PRACTICES.md # Sicurezza, WinRM, credenziali
│ └── Setup-GiteaSSH.md # Configurazione SSH alias per Gitea
│
├── PLAN.md # Stato implementazione e decisioni tecniche
└── TODO.md # Task completati e roadmap futura
Setup rapido
1. Template VM
# Dalla directory template/, dopo aver installato Windows Server 2025 nella VM
# e annotato il suo IP DHCP su VMnet8:
.\Prepare-WinBuild2025.ps1 -VMIPAddress 192.168.79.x -SkipWindowsUpdate
Poi spegni la VM e prendi lo snapshot con nome esatto BaseClean.
2. Credenziali guest
# PowerShell elevato — una volta sola sull'host
Import-Module CredentialManager
New-StoredCredential -Target "BuildVMGuest" -UserName "ci_build" `
-Password "<your-build-password>" -Persist LocalMachine
3. act_runner
# Registra il runner con Gitea (interattivo, usa il registration token da Gitea Admin)
F:\CI\act_runner\act_runner.exe register
# Installa come servizio Windows
nssm install act_runner "F:\CI\act_runner\act_runner.exe" daemon
nssm start act_runner
Imposta GITEA_CI_TEMPLATE_PATH nelle variabili d'ambiente del servizio:
F:\CI\Templates\WinBuild\CI-WinBuild.vmx
4. SSH per Gitea
Vedi docs/Setup-GiteaSSH.md per configurare l'alias gitea-ci
(SSH port 2222, necessario per git clone ssh://gitea-ci/... durante i build).
Uso — build manuale (test)
& 'N:\Code\Workspace\Local-CI-CD-System\scripts\Invoke-CIJob.ps1' `
-JobId 'test-001' `
-RepoUrl 'ssh://gitea-ci/Simone/nsis-plugin-nsinnounp.git' `
-Branch 'main' `
-Commit '' `
-TemplatePath 'F:\CI\Templates\WinBuild\CI-WinBuild.vmx' `
-Submodules `
-BuildCommand 'python build_plugin.py --final --dist-dir dist' `
-GuestArtifactSource 'dist' `
-GuestCredentialTarget 'BuildVMGuest'
Artifacts raccolti in: F:\CI\Artifacts\test-001\artifacts.zip
Workflow Gitea
Il file gitea/workflows/build-nsis.yml è il workflow
attivo per Simone/nsis-plugin-nsinnounp. Si attiva su push di tag v* o manualmente.
Per adattarlo ad altri repository, copia gitea/workflow-example.yml
e aggiorna -RepoUrl, -BuildCommand e -GuestArtifactSource.
Documentazione
| File | Contenuto |
|---|---|
| docs/ARCHITECTURE.md | Diagramma componenti e flusso dati |
| docs/CI-FLOW.md | Descrizione dettagliata di ogni fase del pipeline |
| docs/OPTIMIZATION.md | Layout NVMe, snapshot strategy, cache, tuning WinRM |
| docs/BEST-PRACTICES.md | Sicurezza WinRM, gestione credenziali, isolamento |
| docs/Setup-GiteaSSH.md | Configurazione SSH alias gitea-ci |
Note di sicurezza
WinRM usa HTTPS/5986 con certificato self-signed e Basic auth.
-SkipCACheck/-SkipCNCheck sono accettabili in lab isolato (il cert non è di una CA trusted).
Per ambienti condivisi o di produzione, usare un certificato CA valida e rimuovere -SkipCACheck.
Vedi docs/BEST-PRACTICES.md.