Files
local-ci-cd-system/README.md
T
Simone 97ec820ebb ci: rename build-nsInnoUnp.yml -> build-ns7zip.yml; update doc refs
Workflow now targets Simone/nsis-plugin-ns7zip. Renamed the file and
the workflow `name:`, and updated all references in active docs
(plans/archived and docs/archived left as frozen history).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 20:12:25 +02:00

428 lines
21 KiB
Markdown
Raw Permalink 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.
# Local CI/CD System
Sistema CI/CD self-hosted su Windows per build isolati in VM efimere VMware.
**Stato**: production-ready — build Windows e Linux verificati e2e; burn-in concorrente a 4 job PASS; §3.3 in-VM git clone attivabile via `-UseGitClone`
---
## Panoramica
Il runner [act_runner](https://gitea.com/gitea/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 (label: windows-build | linux-build)
Invoke-CIJob.ps1
├─ 1. git clone repo su host (con submoduli)
├─ 2. Linked clone da snapshot BaseClean / BaseClean-Linux
├─ 3. Avvio VM headless
├─ 4. Attesa readiness (WinRM/5986 per Windows, SSH/22 per Linux)
├─ 5. Source transfer + build (WinRM per Windows, SSH/SCP per Linux)
├─ 6. Copia artifacts in F:\CI\Artifacts\<jobid>\
└─ finally: stop + rimozione VM clone
```
Ogni build gira in una VM **usa e getta** ripristinata dallo snapshot: Windows Server 2025/2022 (WinRM) o Ubuntu 24.04 (SSH).
---
## 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
### Windows (snapshot `BaseClean`)
| Componente | Versione |
| -------------- | ------------------------------------------------------------------------------ |
| OS | Windows Server 2025 |
| VMX | `F:\CI\Templates\WinBuild2025\WinBuild2025.vmx` (env `GITEA_CI_TEMPLATE_PATH`) |
| 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) |
Variante **Windows Server 2022**: `*WinBuild2022.ps1` + VMX `F:\CI\Templates\WinBuild2022\WinBuild2022.vmx`.
### Linux (snapshot `BaseClean-Linux`)
| Componente | Versione |
| ------------ | ---------------------------------------------------------------------------------------- |
| OS | Ubuntu 24.04 LTS (cloud image) |
| VMX | `F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx` (env `GITEA_CI_LINUX_TEMPLATE_PATH`) |
| Toolchain | GCC, G++, Clang, CMake, Ninja, Python 3, Git, 7-Zip |
| Rete | VMnet8 NAT — `192.168.79.0/24` |
| SSH | porta 22, utente `ci_build`, chiave `F:\CI\keys\ci_linux` |
| Runner label | `linux-build:host` |
---
## Struttura repository
```
├── Setup-Host.ps1 # Bootstrap host: dirs F:\CI\, credenziali, act_runner service
├── PSScriptAnalyzerSettings.psd1 # Regole linting condivise (§5.4)
├── scripts/
│ ├── _Common.psm1 # Shared module (vmrun wrapper, diagnostics)
│ ├── _Transport.psm1 # SSH/SCP helpers per guest Linux (Invoke-SshCommand, Copy-SshItem)
│ ├── Invoke-CIJob.ps1 # Orchestratore principale (Windows WinRM + Linux SSH, -UseGitClone)
│ ├── New-BuildVM.ps1 # Linked clone da template
│ ├── Wait-VMReady.ps1 # Polling readiness (WinRM/5986 o SSH/22)
│ ├── Invoke-RemoteBuild.ps1 # Build remoto (WinRM per Windows, SSH/SCP per Linux)
│ ├── Get-BuildArtifacts.ps1 # Raccolta artifacts (WinRM o SCP)
│ ├── Remove-BuildVM.ps1 # Stop + rimozione VM clone (-WhatIf)
│ ├── Cleanup-OrphanedBuildVMs.ps1 # Cleanup VM orfane (§2.2)
│ ├── Invoke-RetentionPolicy.ps1 # Retention artifact + log (§2.3)
│ ├── Watch-DiskSpace.ps1 # Alert spazio libero F: (§4.3)
│ ├── Watch-RunnerHealth.ps1 # Health check runner (§2.7)
│ ├── Backup-CITemplate.ps1 # Backup VMDK template (§2.6)
│ ├── Set-TemplateSharedFolders.ps1 # Cache NuGet/pip via shared folders (§3.1)
│ ├── Measure-CIBenchmark.ps1 # Benchmark fasi pipeline (§3.6)
│ ├── Register-CIScheduledTasks.ps1 # Task Scheduler bootstrap
│ ├── Test-CapacityBurnIn.ps1 # Burn-in concorrente N job × R round
│ ├── Start-BurnInTest-Linux.ps1 # Wrapper burn-in specifico per LinuxBuild2404
│ └── Get-CIJobSummary.ps1 # Report sintetico ultima esecuzione job
├── template/
│ ├── autounattend.template.xml # Template XML per installazione Windows unattended
│ ├── Deploy-WinBuild2025.ps1 # Deploy VM + install Windows 2025 unattended (HOST)
│ ├── Prepare-WinBuild2025.ps1 # Provisioning toolchain 2025 via WinRM (HOST-side)
│ ├── Install-CIToolchain-WinBuild2025.ps1 # Toolchain CI 2025 nella VM (GUEST-side)
│ ├── Deploy-WinBuild2022.ps1 # Deploy VM + install Windows 2022 unattended (HOST)
│ ├── Prepare-WinBuild2022.ps1 # Provisioning toolchain 2022 via WinRM (HOST-side)
│ ├── Install-CIToolchain-WinBuild2022.ps1 # Toolchain CI 2022 nella VM (GUEST-side)
│ ├── Deploy-LinuxBuild2404.ps1 # Deploy cloud image Ubuntu 24.04 su VMware (HOST)
│ ├── Prepare-LinuxBuild2404.ps1# Provisioning toolchain Linux via SSH + snapshot (HOST-side)
│ ├── Install-CIToolchain-Linux2404.sh # Toolchain CI Ubuntu 24.04 nel guest (GUEST-side)
│ ├── Validate-DeployState.ps1 # Validazione stato post-Deploy (2025, 2022, Linux)
│ └── Validate-SetupState.ps1 # Validazione stato post-Setup (pre-snapshot)
├── tests/ # Pester v5 unit tests (§5.1)
├── gitea/
│ ├── actions/
│ │ └── local-ci-build/action.yml # Composite action riusabile (wrap Invoke-CIJob.ps1)
│ ├── workflows/
│ │ ├── build-ns7zip.yml # Workflow matrix Windows+Linux per nsis-plugin-ns7zip
│ │ └── lint.yml # PSScriptAnalyzer su push/PR (§5.4)
│ └── workflow-example.yml # Template generico adattabile
├── runner/
│ ├── config.yaml # Configurazione act_runner (no secrets)
│ └── Install-Runner.ps1
├── docs/
│ ├── ARCHITECTURE.md # Diagramma sistema e componenti
│ ├── CI-FLOW.md # Flusso dettagliato passo-passo
│ ├── HOST-SETUP.md # Bootstrap macchina host
│ ├── WINDOWS-TEMPLATE-SETUP.md # Provisioning template Windows
│ ├── LINUX-TEMPLATE-SETUP.md # Bozza template Linux (§6.1, non implementato)
│ ├── OPTIMIZATION.md # Layout disco, snapshot, cache, tuning
│ ├── BEST-PRACTICES.md # Sicurezza, WinRM, credenziali, threat model
│ ├── RUNBOOK.md # Triage incident comuni (§4.4)
│ ├── TEST-PLAN-v1.3-to-HEAD.md # Test plan completo features post-v1.3
│ ├── Setup-GiteaSSH.md # Configurazione SSH alias per Gitea
│ └── archived/ # Doc storici / sign-off
└── TODO.md # Roadmap, audit trail task completati, backlog
```
---
## Python orchestrator (Phase A — in progress)
A new Python 3.11+ rewrite of the orchestrator lives under `src/ci_orchestrator/`.
Phase A (see [implementation-plan-A-B](plans/implementation-plan-A-B.md)) is on
branch `feature/python-rewrite-and-linux-migration`. As of A5 the Python CLI is the
production entry point invoked by `gitea/actions/local-ci-build/action.yml`;
the PowerShell scripts in `scripts/` are 3-line shims that forward to the
Python sub-commands listed below.
### Setup
```powershell
# Production venv on the runner host (one-time + on every code deploy).
# NON-editable: act_runner runs as LocalSystem and cannot resolve an
# editable .pth into the dev tree or a transient RunnerWork dir
# (-> "No module named ci_orchestrator"). Re-run `pip install .` after
# each code change. No CI workflow may install into this venv.
python -m venv F:\CI\python\venv
F:\CI\python\venv\Scripts\python.exe -m pip install --upgrade pip
F:\CI\python\venv\Scripts\python.exe -m pip install .
# Local dev venv (NOT committed; see .gitignore) — editable is fine here
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -e ".[dev]"
```
Configuration: copy [config.example.toml](config.example.toml) to
`F:\CI\config.toml` (or set `$env:CI_CONFIG`). Environment variables
(`CI_ROOT`, `CI_TEMPLATES`, `CI_BUILD_VMS`, `CI_ARTIFACTS`, `CI_KEYS`)
override the file. Dependency manifest and tool config (ruff, mypy,
pytest, coverage) live in [pyproject.toml](pyproject.toml).
### CLI sub-commands
```powershell
# Discover commands
python -m ci_orchestrator --help
# Wait for a VM to become reachable (WinRM 5986 or SSH 22 — auto-detected)
python -m ci_orchestrator wait-ready `
--vmx F:\CI\BuildVMs\smoke\smoke.vmx --guest-os windows --timeout 300
# Linked-clone lifecycle
python -m ci_orchestrator vm new `
--template-path F:\CI\Templates\WinBuild2025\WinBuild2025.vmx `
--snapshot-name BaseClean `
--clone-base-dir F:\CI\BuildVMs `
--job-id smoke-001
python -m ci_orchestrator vm remove --vmx F:\CI\BuildVMs\Clone_smoke-001_*\Clone_smoke-001_*.vmx
python -m ci_orchestrator vm cleanup --max-age-hours 12
# Build + artifact collection
python -m ci_orchestrator build run `
--vmx F:\CI\BuildVMs\Clone_smoke-001_*\*.vmx `
--script .\build.ps1 --workdir C:\build --guest-os windows
python -m ci_orchestrator artifacts collect `
--vmx F:\CI\BuildVMs\Clone_smoke-001_*\*.vmx `
--remote-path C:\build\dist --local-dir F:\CI\Artifacts\smoke-001
# Monitoring (driven by Task Scheduler / systemd timers in B5)
python -m ci_orchestrator monitor disk --min-free-gb 50 --drive-letter F
python -m ci_orchestrator monitor runner --state-dir F:\CI\act_runner
# Reporting
python -m ci_orchestrator report job --job-id smoke-001
# End-to-end orchestrator (replaces Invoke-CIJob.ps1)
python -m ci_orchestrator job `
--job-id smoke-001 `
--repo-url ssh://gitea-ci/Simone/nsis-plugin-ns7zip.git `
--branch main `
--template-path F:\CI\Templates\WinBuild2025\WinBuild2025.vmx `
--build-command "python build_plugin.py --final --dist-dir dist" `
--guest-artifact-source dist
```
The PowerShell wrappers (`scripts\Invoke-CIJob.ps1`,
`scripts\New-BuildVM.ps1`, `scripts\Wait-VMReady.ps1`,
`scripts\Remove-BuildVM.ps1`, `scripts\Cleanup-OrphanedBuildVMs.ps1`,
`scripts\Invoke-RemoteBuild.ps1`, `scripts\Get-BuildArtifacts.ps1`,
`scripts\Watch-DiskSpace.ps1`, `scripts\Watch-RunnerHealth.ps1`,
`scripts\Get-CIJobSummary.ps1`) are kept as 3-line shims for Task
Scheduler and external callers — they translate PascalCase parameters
to the Python kebab-case CLI and propagate the exit code.
### Local validation gates
```powershell
.\.venv\Scripts\python.exe -m ruff check src tests\python
.\.venv\Scripts\python.exe -m mypy --strict src
.\.venv\Scripts\python.exe -m pytest tests\python -q --cov=ci_orchestrator --cov-fail-under=90
```
Coverage gate is **90%**. Regression tests for the
`AGENTS.md` "Errori frequenti da evitare" #9#12 live in
[tests/python/test_agents_errors.py](tests/python/test_agents_errors.py)
and must stay green.
---
## Setup rapido
### 1a. Template VM Windows
**Opzione A — Deploy automatico** (crea VM + installa Windows unattended da ISO):
```powershell
cd N:\Code\Workspace\Local-CI-CD-System\template
# Windows Server 2025 (corrente):
.\Deploy-WinBuild2025.ps1 -ISOPath F:\CI\ISO\WinSrv2025.iso `
-VMPath F:\CI\Templates\WinBuild2025\WinBuild2025.vmx
# Windows Server 2022 (alternativa):
.\Deploy-WinBuild2022.ps1 -ISOPath F:\CI\ISO\WinSrv2022.iso `
-VMPath F:\CI\Templates\WinBuild2022\WinBuild2022.vmx
```
**Opzione B — installazione manuale**: installa Windows nella VM, abilita WinRM
(`winrm quickconfig -q` + `Enable-PSRemoting -Force`), annota l'IP VMnet8.
**Provisioning toolchain** (dopo A o B, dalla directory `template/`):
```powershell
# Windows Server 2025:
.\Prepare-WinBuild2025.ps1 -VMIPAddress 192.168.79.x -StoreCredential
# Windows Server 2022:
.\Prepare-WinBuild2022.ps1 -VMIPAddress 192.168.79.x -StoreCredential
```
Poi spegni la VM e prendi lo snapshot con nome esatto **`BaseClean`**.
### 1b. Template VM Linux
```powershell
cd N:\Code\Workspace\Local-CI-CD-System\template
# Deploy cloud image Ubuntu 24.04 (scarica ISO/cloud img, crea VM):
.\Deploy-LinuxBuild2404.ps1 -VMPath F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx
```
**Provisioning toolchain** (SSH — la VM deve essere avviata e raggiungibile):
```powershell
.\Prepare-LinuxBuild2404.ps1 -VMIPAddress 192.168.79.x `
-VMXPath F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx `
-TakeSnapshot
```
`-TakeSnapshot` esegue automaticamente: reset machine-id → shutdown → snapshot **`BaseClean-Linux`**.
Dettagli: [docs/LINUX-TEMPLATE-SETUP.md](docs/LINUX-TEMPLATE-SETUP.md).
### 2. Credenziali guest
```powershell
# PowerShell elevato — una volta sola sull'host.
# Scrive nel vault SYSTEM (act_runner gira come LocalSystem; un
# New-StoredCredential dalla sessione utente NON sarebbe leggibile dal
# runner). Username host-qualificato col computer name del guest
# (bare 'ci_build' -> NTLM SEC_E_UNKNOWN_CREDENTIALS).
.\scripts\Set-CIGuestCredential.ps1 -UserName 'WINBUILD-2025\ci_build'
```
### 3. act_runner
```powershell
# 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 queste variabili d'ambiente nel servizio (`runner/config.yaml`):
| Variabile | Valore |
| ------------------------------ | --------------------------------------------------- |
| `GITEA_CI_TEMPLATE_PATH` | `F:\CI\Templates\WinBuild2025\WinBuild2025.vmx` |
| `GITEA_CI_LINUX_TEMPLATE_PATH` | `F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx` |
| `GITEA_CI_CLONE_BASE_DIR` | `F:\CI\BuildVMs` |
| `GITEA_CI_ARTIFACT_DIR` | `F:\CI\Artifacts` |
| `GITEA_CI_GUEST_CRED_TARGET` | `BuildVMGuest` |
| `GITEA_CI_SSH_KEY_PATH` | `F:\CI\keys\ci_linux` |
Labels runner: `windows-build:host` (job Windows) e `linux-build:host` (job Linux).
Dettagli completi: [docs/HOST-SETUP.md](docs/HOST-SETUP.md).
### 4. SSH per Gitea
Vedi [docs/Setup-GiteaSSH.md](docs/Setup-GiteaSSH.md) per configurare l'alias `gitea-ci`
(SSH port 2222, usato dai workflow live in `git clone ssh://gitea-ci/...`).
---
## Uso — build manuale (test)
**Windows guest:**
```powershell
& 'N:\Code\Workspace\Local-CI-CD-System\scripts\Invoke-CIJob.ps1' `
-JobId 'test-win-001' `
-RepoUrl 'ssh://gitea-ci/Simone/nsis-plugin-ns7zip.git' `
-Branch 'main' `
-TemplatePath 'F:\CI\Templates\WinBuild2025\WinBuild2025.vmx' `
-Submodules `
-BuildCommand 'python build_plugin.py --final --dist-dir dist' `
-GuestArtifactSource 'dist' `
-GuestCredentialTarget 'BuildVMGuest'
```
**Linux guest:**
```powershell
& 'N:\Code\Workspace\Local-CI-CD-System\scripts\Invoke-CIJob.ps1' `
-JobId 'test-linux-001' `
-RepoUrl 'ssh://gitea-ci/Simone/nsis-plugin-ns7zip.git' `
-Branch 'main' `
-TemplatePath 'F:\CI\Templates\LinuxBuild2404\LinuxBuild2404.vmx' `
-SnapshotName 'BaseClean-Linux' `
-GuestOS 'Linux' `
-BuildCommand 'bash build.sh' `
-GuestArtifactSource '/opt/ci/output'
```
Artifacts raccolti in: `F:\CI\Artifacts\<jobid>\`.
Aggiungi `-UseGitClone` per clonare direttamente in VM (skip host-zip-transfer; richiede Git in template — già incluso nel toolchain).
Aggiungi `-SkipArtifact` per job che non producono output (es. lint, test puri).
---
## Workflow Gitea
Il file [gitea/workflows/build-ns7zip.yml](gitea/workflows/build-ns7zip.yml) è il workflow
attivo per `Simone/nsis-plugin-ns7zip`. Si attiva su push di tag `v*` o manualmente.
Usa una **strategy matrix** `[windows, linux]` che esegue in parallelo su entrambi i runner.
La composite action [gitea/actions/local-ci-build/action.yml](gitea/actions/local-ci-build/action.yml)
asconde tutta la logica Invoke-CIJob.ps1 e accetta questi input principali:
| Input | Descrizione |
| ----------------- | ------------------------------------------------ |
| `build-command` | Comando di build da eseguire nel guest |
| `guest-os` | `Windows` (default) o `Linux` |
| `artifact-source` | Path artifacts nel guest |
| `skip-artifact` | `true` per job senza output |
| `repo-url` | URL SSH del repository |
| `job-id-suffix` | Suffisso per disambiguare artifact dir in matrix |
Per adattare ad altri repository, copia [gitea/workflow-example.yml](gitea/workflow-example.yml)
e aggiorna `build-command`, `artifact-source`, `repo-url`.
---
## Documentazione
| File | Contenuto |
| ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Diagramma componenti e flusso dati |
| [docs/CI-FLOW.md](docs/CI-FLOW.md) | Descrizione dettagliata di ogni fase del pipeline |
| [docs/HOST-SETUP.md](docs/HOST-SETUP.md) | Bootstrap macchina host (Setup-Host.ps1) |
| [docs/WINDOWS-TEMPLATE-SETUP.md](docs/WINDOWS-TEMPLATE-SETUP.md) | Provisioning template Windows (Deploy + Prepare + Setup) |
| [docs/LINUX-TEMPLATE-SETUP.md](docs/LINUX-TEMPLATE-SETUP.md) | Template Ubuntu 24.04: Deploy-LinuxBuild2404, Prepare-LinuxBuild2404, snapshot BaseClean-Linux |
| [docs/OPTIMIZATION.md](docs/OPTIMIZATION.md) | Layout NVMe, snapshot strategy, cache, tuning |
| [docs/BEST-PRACTICES.md](docs/BEST-PRACTICES.md) | Sicurezza WinRM, threat model, credenziali |
| [docs/RUNBOOK.md](docs/RUNBOOK.md) | Triage incident comuni (runner offline, clone fail, ecc.) |
| [docs/TEST-PLAN-v1.3-to-HEAD.md](docs/TEST-PLAN-v1.3-to-HEAD.md) | Test plan completo features post-v1.3 |
| [docs/Setup-GiteaSSH.md](docs/Setup-GiteaSSH.md) | Configurazione SSH alias `gitea-ci` |
| [TODO.md](TODO.md) | Roadmap, audit trail task completati, backlog |
---
## 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](docs/BEST-PRACTICES.md).