#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)"