dd238121b3
Sistema CI locale basato su VMware Workstation + Gitea Actions + act_runner. Testato e2e con nsis-plugin-nsinnounp (MSBuild + Python, 4 configurazioni parallele). - scripts/: Invoke-CIJob, Invoke-RemoteBuild, New/Remove-BuildVM, Wait-VMReady, Get-BuildArtifacts - runner/: act_runner config (windows-build label, capacity 4) - gitea/workflows/: build-nsis.yml (template per progetti MSBuild/Python) - template/: script di provisioning template VM (VS BuildTools 2026, .NET SDK 10, Python 3.13) - docs/: ARCHITECTURE, CI-FLOW, OPTIMIZATION, BEST-PRACTICES, Setup-GiteaSSH Verificato: e2e-009 SUCCESS in 02:09, cleanup automatico VM confermato.
202 lines
7.9 KiB
PowerShell
202 lines
7.9 KiB
PowerShell
#Requires -RunAsAdministrator
|
|
#Requires -Version 5.1
|
|
<#
|
|
.SYNOPSIS
|
|
Downloads, registers, and installs act_runner as a Windows service.
|
|
|
|
.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)"
|