Files
local-ci-cd-system/docs/CI-FLOW.md
T
Simone 6ba8cca70a docs: fix stale references across all documentation
- ARCHITECTURE.md: fix WinRM subnet (192.168.1179), VM box shows VS 2026/Python 3.13/unzip+python build instead of .NET SDK 8/git clone/dotnet build
- BEST-PRACTICES.md: fix VMnet11/192.168.11  VMnet8 NAT/192.168.79
- CI-FLOW.md: Step 3 workflow YAML updated to actual Invoke-CIJob.ps1 params (Submodules, BuildCommand, GuestArtifactSource); note that -VMIPAddress is auto-detected
- OPTIMIZATION.md: BaseClean tier updated to VS BuildTools 2026, .NET SDK 10.0.203, Python 3.13.3
- gitea/workflow-example.yml: remove BUILD_VM_IP (auto-detected), replace -VMIPAddress/-Configuration with -Submodules/-BuildCommand/-GuestArtifactSource
2026-05-08 23:36:57 +02:00

263 lines
9.6 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.
# 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 | Provisioned, snapshot "BaseClean" taken, VM powered off |
| WinRM | Enabled on template VM (inherits to all clones) |
| 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`:
```yaml
- 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):
```
Phase 1: vmrun getState → must return "running"
Phase 2: Test-Connection (ICMP ping) → must succeed
Phase 3: Test-WSMan → WinRM listener must respond
```
- 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
-Credential (from Windows Credential Manager)
-BuildCommand 'python build_plugin.py --final --dist-dir dist'
-GuestArtifactSource 'dist'
```
Sequence inside the PSSession:
```
1. New-PSSession → open WinRM session to VM
2. 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 — non si fa git clone nella VM)
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>
-Credential (same as above)
-GuestArtifactPath C:\CI\output\artifacts.zip
-HostArtifactDir F:\CI\Artifacts\{JobId}\
```
- Apre PSSession e copia `C:\CI\output\artifacts.zip` dall'host
- Valida che il file esista e sia non-vuoto
- Il zip contiene la struttura `dist/` con tutti gli artifact di build
---
### 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` collects partial artifacts (if any), 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** |