nice-to-have: implement all 6 tier items
- Get-CIJobSummary.ps1: already present with full implementation (marked done) - Get-BuildArtifacts.ps1: add -JobId/-Commit params; Write-ArtifactManifest writes manifest.json (name, size, sha256, commit, jobId) after both Linux and Windows artifact collection branches - Invoke-CIJob.ps1: add -GuestCPU/-GuestMemoryMB params; insert post-clone VMX override block (numvcpus/memsize rewrite) before vmrun start; pass -JobId/-Commit to Get-BuildArtifacts calls - Watch-RunnerHealth.ps1: add -GiteaUrl/-GiteaCredentialTarget params; optional GET /api/v1/admin/runners check in Running branch warns if 0 online runners - Install-CIToolchain-WinBuild2025.ps1: fill SHA256 hashes for Python 3.13.3, 7-Zip 26.01, Node.js 22.14.0, dotnet-install.ps1 - Measure-CIBenchmark.ps1: add deltaKB field (linked-clone disk footprint in KB) measured post-clone; added to result object and summary Format-Table
This commit is contained in:
@@ -65,7 +65,13 @@ param(
|
||||
|
||||
# Persistent known_hosts file for SSH calls (CI jobs).
|
||||
# Empty string (default) = permissive mode (StrictHostKeyChecking=no, UserKnownHostsFile=NUL).
|
||||
[string] $SshKnownHostsFile = ''
|
||||
[string] $SshKnownHostsFile = '',
|
||||
|
||||
# Optional job ID and commit SHA written into manifest.json.
|
||||
# When either is non-empty a manifest.json is written to $HostArtifactDir
|
||||
# listing all collected files with name, size, and SHA256.
|
||||
[string] $JobId = '',
|
||||
[string] $Commit = ''
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
@@ -73,6 +79,34 @@ $ErrorActionPreference = 'Stop'
|
||||
|
||||
Import-Module (Join-Path $PSScriptRoot '_Common.psm1') -Force
|
||||
|
||||
# ── Helper: write artifact manifest ─────────────────────────────────────────
|
||||
function Write-ArtifactManifest {
|
||||
param([string] $Dir, [string] $JobId, [string] $Commit)
|
||||
$files = @(Get-ChildItem -Path $Dir -Recurse -File -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.Name -ne 'manifest.json' })
|
||||
$fileEntries = foreach ($f in $files) {
|
||||
[pscustomobject]@{
|
||||
name = $f.FullName.Substring($Dir.TrimEnd('\', '/').Length).TrimStart('\', '/')
|
||||
size = $f.Length
|
||||
sha256 = (Get-FileHash $f.FullName -Algorithm SHA256).Hash.ToLower()
|
||||
}
|
||||
}
|
||||
$manifest = [ordered]@{
|
||||
ts = (Get-Date -Format 'o')
|
||||
jobId = $JobId
|
||||
commit = $Commit
|
||||
files = @($fileEntries)
|
||||
}
|
||||
$manifestPath = Join-Path $Dir 'manifest.json'
|
||||
try {
|
||||
$manifest | ConvertTo-Json -Depth 4 |
|
||||
Set-Content -Path $manifestPath -Encoding UTF8 -Force -ErrorAction Stop
|
||||
Write-Host "[Get-BuildArtifacts] Manifest written: $manifestPath ($($files.Count) file(s))"
|
||||
} catch {
|
||||
Write-Warning "[Get-BuildArtifacts] Could not write manifest.json: $_"
|
||||
}
|
||||
}
|
||||
|
||||
if ($GuestOS -eq 'Windows' -and $null -eq $Credential) {
|
||||
throw "Credential is required when GuestOS is Windows."
|
||||
}
|
||||
@@ -103,6 +137,9 @@ if ($GuestOS -eq 'Linux') {
|
||||
throw "[Get-BuildArtifacts] No files found in $HostArtifactDir after SCP transfer."
|
||||
}
|
||||
Write-Host "[Get-BuildArtifacts] $($transferred.Count) file(s) collected from Linux guest."
|
||||
if ($JobId -ne '' -or $Commit -ne '') {
|
||||
Write-ArtifactManifest -Dir $HostArtifactDir -JobId $JobId -Commit $Commit
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -180,6 +217,9 @@ try {
|
||||
$sizeKB = [math]::Round($fileItem.Length / 1KB, 1)
|
||||
|
||||
Write-Host "[Get-BuildArtifacts] Artifact collected: $hostDestPath ($sizeKB KB)"
|
||||
if ($JobId -ne '' -or $Commit -ne '') {
|
||||
Write-ArtifactManifest -Dir $HostArtifactDir -JobId $JobId -Commit $Commit
|
||||
}
|
||||
return $hostDestPath
|
||||
}
|
||||
finally {
|
||||
|
||||
@@ -159,7 +159,17 @@ param(
|
||||
|
||||
# Optional webhook URL (Discord/Gitea). When set, a background job fires a
|
||||
# [WARNING] once the job has been running for 90 minutes.
|
||||
[string] $WebhookUrl = ''
|
||||
[string] $WebhookUrl = '',
|
||||
|
||||
# Optional per-job VMX CPU and RAM override (default 0 = use template value).
|
||||
# Applied to the linked clone after New-BuildVM.ps1, before vmrun start.
|
||||
# The template VMX is never modified.
|
||||
# Example: -GuestCPU 4 -GuestMemoryMB 8192
|
||||
[ValidateRange(0, 32)]
|
||||
[int] $GuestCPU = 0,
|
||||
|
||||
[ValidateRange(0, 131072)]
|
||||
[int] $GuestMemoryMB = 0
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
@@ -402,6 +412,28 @@ try {
|
||||
-JobId $JobId `
|
||||
-VmrunPath $VmrunPath
|
||||
|
||||
# ── Optional VMX CPU/RAM override (post-clone, pre-start) ─────────────
|
||||
if ($GuestCPU -gt 0 -or $GuestMemoryMB -gt 0) {
|
||||
Write-Host "[Invoke-CIJob] Applying VMX override: CPU=$GuestCPU, RAM=${GuestMemoryMB}MB"
|
||||
$vmxLines = Get-Content -LiteralPath $cloneVmxPath
|
||||
if ($GuestCPU -gt 0) {
|
||||
if ($vmxLines -imatch '^numvcpus\s*=') {
|
||||
$vmxLines = $vmxLines -replace '(?i)^numvcpus\s*=.*', "numvcpus = `"$GuestCPU`""
|
||||
} else {
|
||||
$vmxLines = $vmxLines + "numvcpus = `"$GuestCPU`""
|
||||
}
|
||||
}
|
||||
if ($GuestMemoryMB -gt 0) {
|
||||
if ($vmxLines -imatch '^memsize\s*=') {
|
||||
$vmxLines = $vmxLines -replace '(?i)^memsize\s*=.*', "memsize = `"$GuestMemoryMB`""
|
||||
} else {
|
||||
$vmxLines = $vmxLines + "memsize = `"$GuestMemoryMB`""
|
||||
}
|
||||
}
|
||||
Set-Content -LiteralPath $cloneVmxPath -Value $vmxLines -Encoding UTF8
|
||||
Write-Host "[Invoke-CIJob] VMX updated: $cloneVmxPath"
|
||||
}
|
||||
|
||||
# ── Phase 3: Start VM ─────────────────────────────────────────────
|
||||
Write-Host "`n[Phase 3/6] Starting VM..."
|
||||
$startResult = Invoke-VmrunBounded -VmrunPath $VmrunPath `
|
||||
@@ -546,6 +578,8 @@ try {
|
||||
-SshKnownHostsFile $SshKnownHostsFile `
|
||||
-GuestArtifactPath '/opt/ci/output' `
|
||||
-HostArtifactDir $jobArtifactDir `
|
||||
-JobId $JobId `
|
||||
-Commit $Commit `
|
||||
-IncludeLogs
|
||||
} else {
|
||||
& "$scriptDir\Get-BuildArtifacts.ps1" `
|
||||
@@ -553,6 +587,8 @@ try {
|
||||
-Credential $credential `
|
||||
-GuestArtifactPath 'C:\CI\output\artifacts.zip' `
|
||||
-HostArtifactDir $jobArtifactDir `
|
||||
-JobId $JobId `
|
||||
-Commit $Commit `
|
||||
-IncludeLogs
|
||||
}
|
||||
Write-JobEvent -Phase 'phase6.artifacts' -Status 'success' -Data @{ dir = $jobArtifactDir }
|
||||
|
||||
@@ -104,6 +104,7 @@ for ($i = 1; $i -le $Iterations; $i++) {
|
||||
ip = $null
|
||||
winrm = $null
|
||||
destroy = $null
|
||||
deltaKB = $null
|
||||
vmIP = $null
|
||||
error = $null
|
||||
}
|
||||
@@ -122,6 +123,16 @@ for ($i = 1; $i -le $Iterations; $i++) {
|
||||
$t.clone = [math]::Round($sw.Elapsed.TotalSeconds, 2)
|
||||
Write-Host "[bench] clone: $($t.clone)s"
|
||||
|
||||
# Measure linked-clone disk footprint
|
||||
try {
|
||||
$cloneSizeBytes = (Get-ChildItem -Path $cloneDir -Recurse -File -ErrorAction Stop |
|
||||
Measure-Object -Property Length -Sum).Sum
|
||||
$t.deltaKB = [math]::Round($cloneSizeBytes / 1KB, 0)
|
||||
Write-Host "[bench] clone size: $($t.deltaKB) KB"
|
||||
} catch {
|
||||
Write-Warning "[bench] Could not measure clone size: $_"
|
||||
}
|
||||
|
||||
# ── Phase: start ──────────────────────────────────────────────────────
|
||||
Write-Host "[bench] Starting VM..."
|
||||
$sw.Restart()
|
||||
@@ -191,6 +202,7 @@ for ($i = 1; $i -le $Iterations; $i++) {
|
||||
winrmSec = $t.winrm
|
||||
destroySec = $t.destroy
|
||||
totalBootSec = $totalBootSec
|
||||
deltaKB = $t.deltaKB
|
||||
vmIP = $t.vmIP
|
||||
error = $t.error
|
||||
}
|
||||
@@ -217,6 +229,7 @@ $results | Format-Table @(
|
||||
@{ L = 'WinRM(s)'; E = { $_.winrmSec } }
|
||||
@{ L = 'Destroy(s)'; E = { $_.destroySec } }
|
||||
@{ L = 'Boot total'; E = { $_.totalBootSec } }
|
||||
@{ L = 'Delta(KB)'; E = { $_.deltaKB } }
|
||||
@{ L = 'IP'; E = { $_.vmIP } }
|
||||
@{ L = 'Error'; E = { $_.error } }
|
||||
) -AutoSize
|
||||
|
||||
@@ -49,7 +49,17 @@ param(
|
||||
|
||||
[string] $StateDir = 'F:\CI\State',
|
||||
|
||||
[string] $WebhookUrl = ''
|
||||
[string] $WebhookUrl = '',
|
||||
|
||||
# Optional Gitea API runner-online verification.
|
||||
# When $GiteaUrl is non-empty and the act_runner service is Running, this script
|
||||
# queries GET $GiteaUrl/api/v1/admin/runners and warns if zero runners are online.
|
||||
# Requires an admin Personal Access Token stored in Windows Credential Manager
|
||||
# under $GiteaCredentialTarget (same module: CredentialManager).
|
||||
# Silently skipped if GiteaUrl is empty or the credential is unavailable.
|
||||
[string] $GiteaUrl = '',
|
||||
|
||||
[string] $GiteaCredentialTarget = ''
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
@@ -103,6 +113,40 @@ if (-not $svc) {
|
||||
|
||||
if ($svc.Status -eq 'Running') {
|
||||
Write-Host "[RunnerHealth] $ServiceName is Running — OK"
|
||||
|
||||
# ── Optional Gitea runner-online API check ────────────────────────────────
|
||||
if ($GiteaUrl -ne '') {
|
||||
$pat = $null
|
||||
if ($GiteaCredentialTarget -ne '') {
|
||||
try {
|
||||
$cred = Get-StoredCredential -Target $GiteaCredentialTarget -ErrorAction Stop
|
||||
$pat = $cred.GetNetworkCredential().Password
|
||||
} catch {
|
||||
Write-Warning "[RunnerHealth] Could not load Gitea PAT from '$GiteaCredentialTarget': $_"
|
||||
}
|
||||
}
|
||||
if ($pat) {
|
||||
try {
|
||||
$apiUrl = "$($GiteaUrl.TrimEnd('/'))/api/v1/admin/runners"
|
||||
$runners = Invoke-RestMethod -Uri $apiUrl `
|
||||
-Headers @{ Authorization = "token $pat" } `
|
||||
-Method Get -TimeoutSec 10 -ErrorAction Stop
|
||||
$online = @($runners | Where-Object { $_.online -eq $true })
|
||||
if ($online.Count -gt 0) {
|
||||
Write-Host "[RunnerHealth] Gitea API: $($online.Count) runner(s) online — OK"
|
||||
} else {
|
||||
$msg = "Gitea API ($apiUrl) reports 0 online runners. " +
|
||||
"$ServiceName service is Running — possible registration issue."
|
||||
Write-Warning "[RunnerHealth] $msg"
|
||||
Write-CIEvent -EventId 1005 -EntryType Warning -Message $msg
|
||||
Send-Webhook -Content "[WARNING] CI Runner Alert -- $msg"
|
||||
}
|
||||
} catch {
|
||||
Write-Warning "[RunnerHealth] Gitea API check failed: $_"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user