Files
local-ci-cd-system/docs/CI-FLOW.md
T
Simone 8ca3e530c5 feat(low): sprint 4 Low items tutti 5 completati
codice:
- template/Validate-SetupState.ps1: docblock HTTP/Basic -> HTTPS/Basic, port 5986
- scripts/Validate-HostState.ps1 (nuovo): check ACL SSH key ci_linux, Credential Manager
  target BuildVMGuest, struttura dir F:\CI\, vmrun.exe raggiungibile

docs:
- docs/TEST-PLAN-v1.3-to-HEAD.md sezione 3.6: campi JSONL corretti (cloneSec/startSec/
  ipSec/winrmSec/destroySec/totalBootSec) per riflettere output reale di Measure-CIBenchmark.ps1
- docs/CI-FLOW.md tabella failure: 'partial artifacts' -> Get-GuestDiagnostics a diagnostics/
- docs/CHANGELOG.md (nuovo): log reverse-cronologico di tutti gli sprint completati
- plans/final-master-plan.md: tutti i Low marcati done
2026-05-13 10:26:08 +02:00

11 KiB
Raw Permalink Blame History

CI Pipeline Flow — Step by Step

Trigger to Artifact: Complete Pipeline Walk-Through


Step 0 — Prerequisites (one-time setup)

Before any CI job runs, the following must be in place:

Component State
Gitea server Running, accessible on LAN
act_runner Registered, running as Windows service on host
Template VM (Win) Provisioned, snapshot "BaseClean" taken, VM powered off
Template VM (Lin) Ubuntu 24.04 LTS, snapshot "BaseClean-Linux" taken, VM powered off (optional)
WinRM Enabled on Windows template VM (inherits to all clones)
SSH key F:\CI\keys\ci_linux (ed25519) present; public key in Linux template
vmrun.exe Present at C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe
F:\CI\BuildVMs\ Directory exists and writable
F:\CI\Artifacts\ Directory exists and writable

Step 1 — Developer Pushes Code

Developer → git push origin main
  • Git push lands on Gitea server
  • Gitea evaluates .gitea/workflows/build.yml in the repository
  • If the workflow trigger matches (e.g. on: push to main), Gitea enqueues a new Actions job
  • Job is tagged with the label defined in the workflow (runs-on: windows-build)

Step 2 — act_runner Picks Up the Job

act_runner (host) ─polling─► Gitea Actions API
                  ◄─job data─
  • act_runner polls the Gitea API approximately every 510 seconds
  • Detects a pending job matching its labels (windows-build)
  • Downloads the workflow YAML and job parameters
  • If capacity slots are available, starts job execution immediately
  • If all slots are busy, job waits in Gitea queue until a slot frees

Step 3 — act_runner Executes Workflow Steps

The workflow YAML defines steps that run as PowerShell commands on the host. The first substantive step calls Invoke-CIJob.ps1:

- name: Run CI Job
  shell: pwsh
  run: |
    & 'N:\Code\Workspace\Local-CI-CD-System\scripts\Invoke-CIJob.ps1' `
      -JobId               '${{ github.run_id }}' `
      -RepoUrl             'ssh://gitea-ci/Simone/<repo>.git' `
      -Branch              '${{ github.ref_name }}' `
      -Commit              '${{ github.sha }}' `
      -TemplatePath        $env:GITEA_CI_TEMPLATE_PATH `
      -Submodules `
      -BuildCommand        'python build_plugin.py --final --dist-dir dist' `
      -GuestArtifactSource 'dist'
    if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

Il parametro -VMIPAddress non è più necessario — l'IP viene rilevato automaticamente tramite vmrun getGuestIPAddress dopo l'avvio della VM.


Step 4 — Invoke-CIJob.ps1: Clone VM

New-BuildVM.ps1
  vmrun.exe -T ws clone <template.vmx> <clone.vmx> linked -snapshot "BaseClean"
  • Generates unique clone name: Clone_{JobId}_{yyyyMMdd_HHmmss}
  • Creates clone directory under F:\CI\BuildVMs\
  • Linked clone creation takes ~515 seconds
  • The template snapshot "BaseClean" is not modified
  • Returns the full path to the new .vmx file

Step 5 — Start VM

vmrun.exe -T ws start <clone.vmx> nogui
  • Starts the cloned VM in headless (no GUI) mode
  • VM boots from the "BaseClean" state: clean OS, build tools installed, WinRM enabled
  • Boot takes ~2040 seconds

Step 6 — Wait for VM Readiness

Wait-VMReady.ps1 -VMPath <clone.vmx> -IPAddress <dynamic-NAT-ip> -TimeoutSeconds 300

IP is discovered dynamically via vmrun getGuestIPAddress (VMnet8 NAT, subnet 192.168.79.0/24). No hardcoded IPs — each clone gets a DHCP-assigned address from VMware NAT.

Three-phase readiness check (retried every 5 seconds, up to 300s timeout). Transport is selected automatically from the VMX guestOS field (-Transport WinRM for Windows, -Transport SSH for Linux):

Phase 1: vmrun getState → must return "running"

Windows (-Transport WinRM, default):
  Phase 2: Test-Connection (ICMP ping) → must succeed
  Phase 3: Test-WSMan → WinRM listener must respond

Linux (-Transport SSH):
  Phase 2: Test-NetConnection -Port 22 → must succeed
  Phase 3: ssh -o ConnectTimeout=5 ... "echo ready" → must return "ready"
  • Total wait is typically 3090 seconds after vmrun start
  • If timeout exceeded, VM is destroyed and job fails with a clear error message
  • On success, IP and credentials are ready for PSSession

Step 7 — Remote Build Execution

Invoke-RemoteBuild.ps1
  -IPAddress   <dynamic-NAT-ip>           # from vmrun getGuestIPAddress
  -GuestOS     Windows|Linux              # auto-detected from VMX guestOS field

  # Windows path (default):
  -Credential  (from Windows Credential Manager)
  -BuildCommand 'python build_plugin.py --final --dist-dir dist'
  -GuestArtifactSource 'dist'

  # Linux path (-GuestOS Linux):
  -SshKeyPath  F:\CI\keys\ci_linux
  -SshUser     ci_build
  -CloneUrl / -CloneBranch   # always in-VM git clone for Linux
  -BuildCommand 'make all'

Sequence inside the PSSession:

1. New-PSSession  →  open WinRM session to VM
2a. (default) Compress-Archive (host) → copy zip to C:\CI\build.zip (guest) → Expand-Archive to C:\CI\build\
    (source code è già clonato sull'host in Phase 1 — nessun git clone nella VM)
2b. (opt-in, `-UseGitClone`, §3.3 DONE 2026-05-10)
    git clone direttamente in VM tramite `ssh://gitea-ci/...` (richiede Git+7-Zip in template, §6.6 Tier-1)
    Vantaggio: skip host-zip-transfer, -25.7% durata pipeline (e2e PASS). Verifica SHA commit post-clone.
3. Invoke-Expression "$BuildCommand" in C:\CI\build\
     Esempio: python build_plugin.py --final --dist-dir dist
       a. Build 4 configurazioni MSBuild in parallelo (x86-unicode, x64-unicode, cli-x86, cli-x64)
       b. Raccoglie artifact in C:\CI\build\dist\
       c. Cleanup build dir (--final)
4. Compress-Archive C:\CI\build\$GuestArtifactSource C:\CI\output\artifacts.zip
5. Cattura exit code; se non-zero il job fallisce con errore chiaro
6. Remove-PSSession
  • Output standard e stderr dalla build sono streamati all'host e catturati da act_runner per i log Gitea Actions
  • Se la build fallisce (exit code ≠ 0), il controllo passa al blocco finally

Step 8 — Collect Artifacts

Get-BuildArtifacts.ps1
  -IPAddress       <dynamic-NAT-ip>
  -GuestOS         Windows|Linux         # auto-detected from Invoke-CIJob

  # Windows path (default):
  -Credential      (from Windows Credential Manager)
  -GuestArtifactPath  C:\CI\output\artifacts.zip

  # Linux path (-GuestOS Linux):
  -SshKeyPath      F:\CI\keys\ci_linux
  -GuestArtifactPath  /opt/ci/output

  -HostArtifactDir    F:\CI\Artifacts\{JobId}\
  • Windows: apre PSSession e copia C:\CI\output\artifacts.zip tramite WinRM
  • Linux: scp -r ci_build@<ip>:/opt/ci/output/. <HostArtifactDir> tramite _Transport.psm1
  • In entrambi i casi valida che almeno un file sia stato trasferito

Step 9 — Destroy VM

Remove-BuildVM.ps1 -VMPath <clone.vmx>

Sequence:

1. vmrun stop <clone.vmx> soft      (graceful shutdown attempt)
2. Wait 5 seconds
3. vmrun getState → if still "running":
   vmrun stop <clone.vmx> hard     (force off)
4. vmrun deleteVM <clone.vmx>       (removes VMX + VMDK delta files)
5. Remove-Item <clone dir> -Recurse (removes any leftover files)
  • VM is gone from disk within ~510 seconds
  • No state, no temp files, no credentials remain in the clone
  • Template VM and "BaseClean" snapshot are unaffected

Note: This step runs in a finally block inside Invoke-CIJob.ps1, so it executes even if Steps 68 failed. A build VM is never left running.


Step 10 — Report Status & Upload Artifacts

act_runner ─► Gitea Actions API  (job status: success / failure)
act_runner ─► Gitea artifact store  (uploads F:\CI\Artifacts\{JobId}\*)
  • act_runner reads the exit code from Invoke-CIJob.ps1
  • Reports success or failure to Gitea
  • Uploads artifacts using actions/upload-artifact step in the workflow YAML
  • Build log (stdout from all steps) is stored in Gitea Actions UI
  • Commit/PR status badge is updated

Parallel Build Flow

When multiple pushes happen concurrently (or multiple PRs are open):

act_runner (capacity: 4)
  ├── Job #1 ──► Clone_Job_001 (192.168.79.x) → build → destroy
  ├── Job #2 ──► Clone_Job_002 (192.168.79.x) → build → destroy
  ├── Job #3 ──► Clone_Job_003 (192.168.79.x) → build → destroy
  └── Job #4 ──► Clone_Job_004 (192.168.79.x) → build → destroy
                   (Job #5 waits in Gitea queue)

Note: each clone gets a dynamic IP from VMware NAT DHCP (192.168.79.0/24). IP is discovered automatically via vmrun getGuestIPAddress — no static assignment required.

  • Each job creates its own independently named clone
  • Clones share the parent "BaseClean" snapshot (read-only CoW)
  • No filesystem or process overlap between concurrent builds
  • act_runner enforces the capacity limit

Failure Scenarios

Failure Point Behavior
VM clone fails Invoke-CIJob.ps1 throws; no VM to destroy; job fails immediately
VM never reaches ready state (timeout) Wait-VMReady.ps1 throws; finally destroys the (running) VM
Build fails inside VM Invoke-RemoteBuild.ps1 throws; finally runs Get-GuestDiagnostics (best-effort, to F:\CI\Artifacts\<jobId>\diagnostics\), destroys VM
Artifact collection fails Job marked failed; VM is still destroyed in finally
Host machine loses power mid-job act_runner resumes on reboot, marks in-flight job as failed; orphan VMs must be cleaned up manually (see TODO.md)

Timing Summary (typical build)

Phase Typical Duration
Gitea → act_runner poll 510 s
Linked clone creation 515 s
VM boot 2040 s
WinRM readiness 1030 s (after boot)
git clone (from local Gitea) 210 s
dotnet restore + build project-dependent
Artifact collection 210 s
VM destruction 510 s
Overhead total ~60120 s