feat(sprint5): quality pass, smoke test workflow, Get-CIJobSummary

Task 5.1: Delete runner/Install-Runner.ps1 (superseded by Setup-Host.ps1).
Task 5.2: Replace Unicode/Discord emoji in Watch-DiskSpace.ps1, Watch-RunnerHealth.ps1,
          Test-E2E-Section3.3.ps1 with plain-text prefixes ([WARNING], [ALERT], [WARN]).
Task 5.3: docs/TEST-PLAN-v1.3-to-HEAD.md: ForEach-Object -Parallel replaced with Start-Job;
          -RepositoryUrl replaced with -RepoUrl (3 occurrences); PS7 syntax removed.
Task 5.4: scripts/Get-CIJobSummary.ps1 (new): scans JSONL logs in F:\CI\Logs, prints summary
          table per job, -JobId detail view, -Failed filter, -Last N.
Task 3.5: gitea/workflows/self-test.yml (new): workflow_dispatch, smoke-windows + smoke-linux.
          scripts/Test-Smoke.ps1 (new): invokes Invoke-CIJob.ps1 with marker-file build,
          asserts artifact dir and JSONL success event.
Task 5.6: docs/BEST-PRACTICES.md Section 10 added: SHA256 pinning policy, priority table,
          PS 5.1 implementation pattern, update guidance.
This commit is contained in:
Simone
2026-05-12 21:13:15 +02:00
parent 9de86ac289
commit c04a2f25aa
9 changed files with 447 additions and 222 deletions
-207
View File
@@ -1,207 +0,0 @@
#Requires -RunAsAdministrator
#Requires -Version 5.1
<#
.SYNOPSIS
Downloads, registers, and installs act_runner as a Windows service.
.NOTES
DEPRECATED — use Setup-Host.ps1 instead.
Setup-Host.ps1 handles the full host bootstrap including act_runner service
installation in a single idempotent script. Install-Runner.ps1 is kept for
reference but may drift from Setup-Host.ps1 over time.
.DESCRIPTION
1. Downloads the act_runner binary from the specified URL (or Gitea releases).
2. Registers the runner with the Gitea instance using a registration token.
3. Installs it as a Windows service that auto-starts with the system.
Prerequisites:
- Run as Administrator
- NSSM (Non-Sucking Service Manager) must be installed and in PATH,
OR use the built-in sc.exe method (creates a wrapper via PowerShell).
- The Gitea instance must be reachable from this host.
.PARAMETER GiteaURL
Base URL of your Gitea instance. Example: http://192.168.1.50:3000
.PARAMETER RegistrationToken
Runner registration token from Gitea:
Admin Panel → Settings → Actions → Runners → "Create Runner Token"
.PARAMETER InstallDir
Directory where act_runner will be installed.
Default: F:\CI\act_runner
.PARAMETER RunnerName
Display name for this runner in the Gitea UI.
Default: local-windows-runner
.PARAMETER ActRunnerVersion
Version tag to download. Default: latest (resolves via GitHub API).
Example: v0.2.11
.PARAMETER ServiceName
Windows service name. Default: act_runner
.EXAMPLE
.\Install-Runner.ps1 `
-GiteaURL "http://192.168.1.50:3000" `
-RegistrationToken "abc123xyz"
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string] $GiteaURL,
[Parameter(Mandatory)]
[string] $RegistrationToken,
[string] $InstallDir = 'F:\CI\act_runner',
[string] $RunnerName = 'local-windows-runner',
[string] $ActRunnerVersion = 'latest',
[string] $ServiceName = 'act_runner'
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
# ── Resolve download URL ──────────────────────────────────────────────────────
if ($ActRunnerVersion -eq 'latest') {
Write-Host "[Install-Runner] Resolving latest act_runner version from Gitea releases..."
try {
$releaseInfo = Invoke-RestMethod -Uri 'https://dl.gitea.com/act_runner/version.json' -UseBasicParsing
$ActRunnerVersion = $releaseInfo.latest
}
catch {
Write-Warning "Could not resolve latest version automatically. Set -ActRunnerVersion explicitly."
Write-Warning "Find releases at: https://gitea.com/gitea/act_runner/releases"
throw
}
}
$downloadUrl = "https://dl.gitea.com/act_runner/${ActRunnerVersion}/act_runner-${ActRunnerVersion}-windows-amd64.exe"
$binaryPath = Join-Path $InstallDir 'act_runner.exe'
$configPath = Join-Path $InstallDir 'config.yaml'
Write-Host "[Install-Runner] Version : $ActRunnerVersion"
Write-Host "[Install-Runner] Install dir: $InstallDir"
Write-Host "[Install-Runner] Service : $ServiceName"
# ── Create install directory ──────────────────────────────────────────────────
if (-not (Test-Path $InstallDir)) {
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
Write-Host "[Install-Runner] Created directory: $InstallDir"
}
# ── Download act_runner binary ────────────────────────────────────────────────
if (Test-Path $binaryPath) {
Write-Host "[Install-Runner] act_runner.exe already exists — skipping download."
Write-Host " Delete $binaryPath to force re-download."
}
else {
Write-Host "[Install-Runner] Downloading from: $downloadUrl"
Invoke-WebRequest -Uri $downloadUrl -OutFile $binaryPath -UseBasicParsing
Write-Host "[Install-Runner] Downloaded: $binaryPath"
}
# ── Copy config.yaml if not already present ───────────────────────────────────
$repoConfigPath = Join-Path $PSScriptRoot 'config.yaml'
if (-not (Test-Path $configPath)) {
if (Test-Path $repoConfigPath) {
Copy-Item $repoConfigPath $configPath
Write-Host "[Install-Runner] Copied config.yaml from repo to $configPath"
Write-Host " Review and update paths in $configPath before proceeding."
}
else {
Write-Warning "[Install-Runner] config.yaml not found at $repoConfigPath"
Write-Warning " Generating default config and registering without custom config."
# Generate default config
Push-Location $InstallDir
& $binaryPath generate-config | Out-File $configPath -Encoding UTF8
Pop-Location
}
}
else {
Write-Host "[Install-Runner] Using existing config.yaml: $configPath"
}
# ── Register runner with Gitea ────────────────────────────────────────────────
$stateFile = Join-Path $InstallDir '.runner'
if (Test-Path $stateFile) {
Write-Host "[Install-Runner] Runner already registered (.runner state file exists)."
Write-Host " Delete $stateFile to re-register."
}
else {
Write-Host "[Install-Runner] Registering runner with Gitea at $GiteaURL..."
Push-Location $InstallDir
try {
& $binaryPath register `
--no-interactive `
--instance $GiteaURL `
--token $RegistrationToken `
--name $RunnerName `
--labels 'windows-build:host,dotnet:host,msbuild:host' `
--config $configPath
if ($LASTEXITCODE -ne 0) {
throw "act_runner register exited with code $LASTEXITCODE"
}
}
finally {
Pop-Location
}
Write-Host "[Install-Runner] Runner registered successfully."
}
# ── Install as Windows service ────────────────────────────────────────────────
$existingService = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
if ($existingService) {
Write-Host "[Install-Runner] Service '$ServiceName' already exists."
Write-Host " Stopping and updating..."
Stop-Service -Name $ServiceName -Force -ErrorAction SilentlyContinue
}
# Build service command (act_runner daemon with explicit config)
$serviceCmd = "`"$binaryPath`" daemon --config `"$configPath`""
if ($existingService) {
# Update existing service binary path
sc.exe config $ServiceName binpath= $serviceCmd | Out-Null
}
else {
# Create new service
New-Service `
-Name $ServiceName `
-BinaryPathName $serviceCmd `
-DisplayName 'Gitea act_runner (CI/CD)' `
-Description 'Gitea Actions runner for ephemeral VMware build VMs' `
-StartupType Automatic | Out-Null
Write-Host "[Install-Runner] Service created: $ServiceName"
}
# Configure service recovery: restart on failure
sc.exe failure $ServiceName reset= 86400 actions= restart/5000/restart/10000/restart/30000 | Out-Null
# Start the service
Start-Service -Name $ServiceName
Write-Host "[Install-Runner] Service '$ServiceName' started."
# ── Verify ────────────────────────────────────────────────────────────────────
Start-Sleep -Seconds 3
$svc = Get-Service -Name $ServiceName
if ($svc.Status -eq 'Running') {
Write-Host "[Install-Runner] act_runner is running as a Windows service."
Write-Host "[Install-Runner] Check Gitea Admin → Settings → Actions → Runners to confirm it appears Online."
}
else {
Write-Warning "[Install-Runner] Service status: $($svc.Status). Check Windows Event Log for errors."
}
Write-Host ""
Write-Host "Installation complete."
Write-Host " Binary : $binaryPath"
Write-Host " Config : $configPath"
Write-Host " Service : $ServiceName (startup: Automatic)"