feat(a2): port leaf PS scripts to ci_orchestrator CLI

Implements Phase A2 of plans/implementation-plan-A-B.md:

- commands/wait.py    -> wait-ready (replaces Wait-VMReady.ps1)

- commands/vm.py      -> vm remove + vm cleanup (replaces Remove-BuildVM.ps1, Cleanup-OrphanedBuildVMs.ps1); cleanup accepts injected VmBackend (Phase C ESXi hook preserved)

- commands/monitor.py -> monitor disk + monitor runner (replaces Watch-DiskSpace.ps1, Watch-RunnerHealth.ps1)

- commands/report.py  -> report job (replaces Get-CIJobSummary.ps1)

Each PS script reduced to a 3-line shim that delegates to the Python CLI and preserves \0.

Tests: 69 pytest cases across new test_commands_*.py modules; ruff clean, mypy --strict clean, coverage 74.5% (>=70 gate).
This commit is contained in:
2026-05-14 17:01:15 +02:00
parent 10da8f4e81
commit 80f6661ad5
17 changed files with 2074 additions and 881 deletions
+16 -89
View File
@@ -1,96 +1,23 @@
#Requires -Version 5.1
<#
.SYNOPSIS
Checks CI host drive free space and alerts via Windows Event Log (and optionally a webhook).
.DESCRIPTION
Intended to run as a scheduled task every 15 minutes (registered by
Register-CIScheduledTasks.ps1). If the monitored drive is below MinFreeGB,
writes a Warning entry to the Windows Application Event Log under source
'CI-DiskAlert' (Event ID 1001) and exits with code 1 so Task Scheduler
marks the task as failed (visible in Task Scheduler history).
If WebhookUrl is provided, also POSTs a JSON payload to that URL
(compatible with Discord and Gitea webhooks — content field only).
A full drive silently causes vmrun clone to fail with cryptic errors
(not enough disk space for linked clone delta files). Alert early.
.PARAMETER MinFreeGB
Alert threshold in GB. Default: 50
.PARAMETER DriveLetter
Single letter (no colon) of the drive to monitor. Default: F
.PARAMETER WebhookUrl
Optional Discord/Gitea webhook URL. If empty, only Event Log is written.
.EXAMPLE
# Manual check
.\Watch-DiskSpace.ps1 -MinFreeGB 50
# With Discord webhook
.\Watch-DiskSpace.ps1 -WebhookUrl "https://discord.com/api/webhooks/..."
#>
[CmdletBinding()]
param(
[ValidateRange(1, 2000)]
[int] $MinFreeGB = 50,
[ValidatePattern('^[A-Za-z]$')]
[string] $DriveLetter = 'F',
[string] $WebhookUrl = ''
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Continue'
$ErrorActionPreference = 'Stop'
$drive = Get-PSDrive -Name $DriveLetter -ErrorAction SilentlyContinue
if (-not $drive) {
Write-Warning "[DiskSpace] Drive ${DriveLetter}: not found."
exit 2
}
$freeGB = [math]::Round($drive.Free / 1GB, 1)
$totalGB = [math]::Round(($drive.Free + $drive.Used) / 1GB, 1)
$pctFree = [math]::Round($freeGB / $totalGB * 100, 0)
if ($freeGB -ge $MinFreeGB) {
Write-Host "[DiskSpace] Drive ${DriveLetter}: ${freeGB} GB free / ${totalGB} GB (${pctFree}%) — OK (threshold: ${MinFreeGB} GB)"
exit 0
}
# ── Alert ─────────────────────────────────────────────────────────────────────
$msg = "CI host drive ${DriveLetter}: free space ${freeGB} GB (${pctFree}%) is below " +
"the ${MinFreeGB} GB threshold. vmrun linked clones may fail silently. " +
"Run Invoke-RetentionPolicy.ps1 or free disk space manually."
Write-Warning "[DiskSpace] $msg"
# Windows Event Log
$logSource = 'CI-DiskSpaceAlert'
try {
if (-not [System.Diagnostics.EventLog]::SourceExists($logSource)) {
New-EventLog -LogName Application -Source $logSource -ErrorAction Stop
# Shim: delegates to the Python ci_orchestrator CLI.
# Original PS implementation moved to git history; see plans/A2-closeout.md.
$pyArgs = @()
foreach ($a in $args) {
if ($a -is [string] -and $a.Length -gt 1 -and $a.StartsWith('-') -and -not $a.StartsWith('--')) {
$name = $a.Substring(1)
$kebab = [Regex]::Replace($name, '(?<=[a-z0-9])([A-Z])', '-$1')
$kebab = [Regex]::Replace($kebab, '([A-Z]+)([A-Z][a-z])', '$1-$2')
$pyArgs += '--' + $kebab.ToLower()
}
Write-EventLog -LogName Application -Source $logSource `
-EventId 1001 -EntryType Warning -Message $msg
Write-Host "[DiskSpace] Event Log entry written (Application/$logSource, EventId 1001)."
} catch {
Write-Warning "[DiskSpace] Could not write Event Log: $_"
}
# Optional webhook (Discord / Gitea)
if ($WebhookUrl) {
$body = @{ content = "[WARNING] CI Disk Alert -- $msg" } | ConvertTo-Json -Compress
try {
$null = Invoke-RestMethod -Uri $WebhookUrl -Method Post `
-Body $body -ContentType 'application/json' -TimeoutSec 10
Write-Host "[DiskSpace] Webhook notified: $WebhookUrl"
} catch {
Write-Warning "[DiskSpace] Webhook POST failed: $_"
else {
$pyArgs += $a
}
}
exit 1 # non-zero → Task Scheduler marks run as failed (visible in history/Event Viewer)
$venvPython = $env:CI_VENV_PYTHON
if (-not $venvPython) { $venvPython = 'F:\CI\python\venv\Scripts\python.exe' }
& $venvPython -m ci_orchestrator monitor disk @pyArgs
exit $LASTEXITCODE