From c866760105327c38905e214b41c173faea0b2632 Mon Sep 17 00:00:00 2001 From: GraceSolutions Date: Tue, 2 Jun 2026 15:49:51 -0400 Subject: [PATCH] Ignore local scripts/ directory (not part of the module) --- .gitignore | 3 + scripts/Install-GiteaRunner.ps1 | 426 -------------------------------- 2 files changed, 3 insertions(+), 426 deletions(-) delete mode 100644 scripts/Install-GiteaRunner.ps1 diff --git a/.gitignore b/.gitignore index 8968d26..707e68d 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,6 @@ Thumbs.db TestResults/ *.trx *.coverage + +## Local helper scripts (not part of the module) +scripts/ diff --git a/scripts/Install-GiteaRunner.ps1 b/scripts/Install-GiteaRunner.ps1 deleted file mode 100644 index 0f234ee..0000000 --- a/scripts/Install-GiteaRunner.ps1 +++ /dev/null @@ -1,426 +0,0 @@ -#Requires -Version 7.0 -<# -.SYNOPSIS - Downloads the Gitea act_runner binary, installs it as a system daemon, and registers it. - -.DESCRIPTION - Cross-platform installer for the Gitea Actions runner. Idempotent: re-running upgrades - in place, skips work when the requested version already matches, and reuses an existing - registration unless -Force is supplied. - - Resolution order for InstanceUrl and RegistrationToken when not passed explicitly: - Process scope env vars -> User scope env vars -> Machine scope env vars - Explicit candidate variable names tried in order: - InstanceUrl: GITEA_INSTANCE_URL, GITEA_URL, - CLOUDINIT_GITEA_INSTANCE_URL, CLOUDINIT_GITEA_URL - RegistrationToken: GITEA_RUNNER_REGISTRATION_TOKEN, GITEA_RUNNER_TOKEN, - GITEA_REGISTRATION_TOKEN, - CLOUDINIT_GITEA_RUNNER_REGISTRATION_TOKEN, - CLOUDINIT_GITEA_RUNNER_TOKEN, - CLOUDINIT_GITEA_REGISTRATION_TOKEN - -.PARAMETER InstanceUrl - Base URL of the Gitea instance (e.g. https://prod.git.gracesolution.info). - -.PARAMETER RegistrationToken - Runner registration token. Treated as secret; never logged. - -.PARAMETER RunnerName - Name presented to Gitea. Defaults to the machine hostname. - -.PARAMETER Labels - Optional comma-separated runner labels (e.g. linux-amd64,docker). When omitted, - no --labels argument is passed to act_runner register and the runner is - registered with whatever labels are configured server-side or in config.yaml. - -.PARAMETER Version - Specific release tag (e.g. v1.0.7) or 'latest'. Defaults to latest. - -.PARAMETER InstallRoot - Override directory. Defaults are /opt/gitea/runner on Linux, - /usr/local/gitea/runner on macOS, and %ProgramData%\Gitea\Runner on Windows. - -.PARAMETER BinaryName - Renamed binary on disk. Defaults to act_runner (act_runner.exe on Windows). - -.PARAMETER ServiceName - System service identifier (used as the systemd unit name, launchd label suffix, - and Windows service name). Must not contain spaces or characters illegal in - a unit/service identifier. Defaults to 'gitea-runner'. - -.PARAMETER ServiceDisplayName - Friendly human-readable name shown in systemctl status, Windows Services MMC, - and similar UIs. Defaults to 'Gitea Runner'. - -.PARAMETER Force - Re-download binary and re-register the runner even when already present. - -.EXAMPLE - pwsh -File Install-GiteaRunner.ps1 -InstanceUrl https://prod.git.gracesolution.info - -.EXAMPLE - Remote one-liner using env vars for InstanceUrl / RegistrationToken: - $env:GITEA_INSTANCE_URL = 'https://prod.git.gracesolution.info' - $env:GITEA_RUNNER_REGISTRATION_TOKEN = '' - irm 'https://prod.git.gracesolution.info/gsadmin/Gitea-Bootstrap/raw/branch/main/scripts/Install-GiteaRunner.ps1' | iex -#> -[CmdletBinding()] -param( - [string] $InstanceUrl, - [string] $RegistrationToken, - [string] $RunnerName = [System.Net.Dns]::GetHostName(), - [string] $Labels, - [string] $Version = 'latest', - [string] $InstallRoot, - [string] $BinaryName, - [string] $ServiceName = 'gitea-runner', - [string] $ServiceDisplayName = 'Gitea Runner', - [switch] $Force -) - -$ErrorActionPreference = 'Stop' -$ProgressPreference = 'SilentlyContinue' - -if ($PSVersionTable.PSVersion.Major -lt 7) { - throw "Install-GiteaRunner requires PowerShell 7 or later. Detected: $($PSVersionTable.PSVersion)." -} - -$script:Utf8NoBom = New-Object System.Text.UTF8Encoding($false) - -function Write-Stage { - param([string] $Message) - $stamp = [DateTimeOffset]::UtcNow.UtcDateTime.ToString('yyyy-MM-ddTHH:mm:ss.fffffffZ') - Write-Host "[$stamp] - [Install-GiteaRunner] - $Message" -} - -function Resolve-FromEnvVarNames { - param( - [Parameter(Mandatory)][string[]] $Names, - [string] $DisplayName - ) - - $scopes = @('Process', 'User', 'Machine') - foreach ($name in $Names) { - foreach ($scope in $scopes) { - try { $value = [System.Environment]::GetEnvironmentVariable($name, [System.EnvironmentVariableTarget]::$scope) } - catch { continue } - - if (-not [string]::IsNullOrWhiteSpace($value)) { - Write-Stage "Resolved $DisplayName from $scope env var '$name'." - return [string] $value - } - } - } - return $null -} - -function Get-PlatformDescriptor { - $arch = [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture.ToString().ToLowerInvariant() - switch ($arch) { - 'x64' { $assetArch = 'amd64' } - 'arm64' { $assetArch = 'arm64' } - 'arm' { $assetArch = 'arm-7' } - default { throw "Unsupported architecture: $arch" } - } - - if ($IsWindows) { return @{ Os = 'windows'; Arch = $assetArch; Suffix = '.exe' } } - if ($IsMacOS) { return @{ Os = 'darwin'; Arch = $assetArch; Suffix = '' } } - if ($IsLinux) { return @{ Os = 'linux'; Arch = $assetArch; Suffix = '' } } - throw 'Unable to determine host operating system.' -} - -function Get-DefaultInstallRoot { - if ($IsWindows) { return (Join-Path $env:ProgramData 'Gitea' 'Runner') } - if ($IsMacOS) { return '/usr/local/gitea/runner' } - return '/opt/gitea/runner' -} - -function Assert-Elevated { - if ($IsWindows) { - $principal = New-Object Security.Principal.WindowsPrincipal ([Security.Principal.WindowsIdentity]::GetCurrent()) - if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { - throw 'This script must be run from an elevated PowerShell session (Administrator).' - } - } else { - $uid = & id -u - if ($uid -ne '0') { throw 'This script must be run as root (use sudo).' } - } -} - -function Resolve-ReleaseTag { - param([string] $Requested) - if ($Requested -and $Requested -ne 'latest') { return ($Requested.TrimStart('v')) } - - Write-Stage 'Querying Gitea for latest runner release.' - $proxyUri = [System.Net.WebRequest]::GetSystemWebProxy().GetProxy([Uri] 'https://gitea.com') - $invokeArgs = @{ - Uri = 'https://gitea.com/api/v1/repos/gitea/act_runner/releases/latest' - UseBasicParsing = $true - UseDefaultCredentials = $true - } - if ($proxyUri -and $proxyUri.AbsoluteUri -ne 'https://gitea.com/') { - $invokeArgs.Proxy = $proxyUri.AbsoluteUri - $invokeArgs.ProxyUseDefaultCredentials = $true - } - $release = Invoke-RestMethod @invokeArgs - if (-not $release.tag_name) { throw 'Failed to resolve latest act_runner release tag.' } - return ($release.tag_name.TrimStart('v')) -} - - -function Get-InstalledBinaryVersion { - param([string] $BinaryPath) - if (-not (Test-Path -LiteralPath $BinaryPath)) { return $null } - try { - $raw = & $BinaryPath --version 2>$null - if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($raw)) { return $null } - $match = [regex]::Match($raw, '(\d+\.\d+\.\d+(?:[\-\.][0-9A-Za-z\.\-]+)?)') - if ($match.Success) { return $match.Groups[1].Value } - } catch { } - return $null -} - -function Save-BinaryViaWebClient { - param( - [Parameter(Mandatory)][string] $Uri, - [Parameter(Mandatory)][string] $Destination - ) - Write-Stage "Downloading $Uri" - $client = New-Object System.Net.WebClient - try { - $client.Headers['User-Agent'] = 'Install-GiteaRunner' - $client.UseDefaultCredentials = $true - $proxy = [System.Net.WebRequest]::GetSystemWebProxy() - $proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials - $client.Proxy = $proxy - $client.DownloadFile($Uri, $Destination) - } finally { - $client.Dispose() - } -} - -function Add-ToMachinePath { - param([Parameter(Mandatory)][string] $Directory) - if ($IsWindows) { - $current = [System.Environment]::GetEnvironmentVariable('Path', 'Machine') - $parts = @() - if ($current) { $parts = $current.Split(';', [System.StringSplitOptions]::RemoveEmptyEntries) } - if ($parts -notcontains $Directory) { - $updated = ($parts + $Directory) -join ';' - [System.Environment]::SetEnvironmentVariable('Path', $updated, 'Machine') - Write-Stage "Added $Directory to Machine PATH." - } - if (-not ($env:Path -split ';' -contains $Directory)) { $env:Path = "$env:Path;$Directory" } - return - } - - $profilePath = '/etc/profile.d/gitea-runner.sh' - $line = "export PATH=`"$Directory`":`$PATH" - $existing = if ([System.IO.File]::Exists($profilePath)) { [System.IO.File]::ReadAllText($profilePath) } else { '' } - if ($existing -notmatch [regex]::Escape($Directory)) { - [System.IO.File]::WriteAllText($profilePath, $line, $script:Utf8NoBom) - & chmod 0644 $profilePath | Out-Null - Write-Stage "Wrote $profilePath for system-wide PATH." - } - if (($env:PATH -split ':') -notcontains $Directory) { $env:PATH = "$Directory`:$env:PATH" } -} - -function Register-Runner { - param( - [Parameter(Mandatory)][string] $BinaryPath, - [Parameter(Mandatory)][string] $WorkingDirectory, - [Parameter(Mandatory)][string] $InstanceUrl, - [Parameter(Mandatory)][string] $Token, - [Parameter(Mandatory)][string] $RunnerName, - [string] $Labels, - [switch] $Force - ) - - $configPath = Join-Path $WorkingDirectory 'config.yaml' - if ((-not [System.IO.File]::Exists($configPath)) -or $Force) { - Write-Stage 'Generating config.yaml.' - Push-Location $WorkingDirectory - try { - $configContent = (& $BinaryPath generate-config) | Out-String - [System.IO.File]::WriteAllText($configPath, $configContent, $script:Utf8NoBom) - } finally { Pop-Location } - } - - $runnerStateFile = Join-Path $WorkingDirectory '.runner' - if ((Test-Path -LiteralPath $runnerStateFile) -and -not $Force) { - Write-Stage 'Runner already registered (.runner present); skipping registration.' - return - } - - $labelDescription = if ([string]::IsNullOrWhiteSpace($Labels)) { '(no labels specified; using server/config defaults)' } else { "with labels '$Labels'" } - Write-Stage "Registering runner '$RunnerName' $labelDescription." - - Push-Location $WorkingDirectory - try { - $registerArgs = @('register', '--no-interactive', '--instance', $InstanceUrl, - '--token', $Token, '--name', $RunnerName, '--config', $configPath) - if (-not [string]::IsNullOrWhiteSpace($Labels)) { $registerArgs += @('--labels', $Labels) } - & $BinaryPath @registerArgs - if ($LASTEXITCODE -ne 0) { throw "act_runner register exited with code $LASTEXITCODE." } - } finally { Pop-Location } -} - -function Install-SystemdUnit { - param( - [Parameter(Mandatory)][string] $ServiceName, - [Parameter(Mandatory)][string] $ServiceDisplayName, - [Parameter(Mandatory)][string] $BinaryPath, - [Parameter(Mandatory)][string] $WorkingDirectory - ) - $unitPath = "/etc/systemd/system/$ServiceName.service" - $configPath = Join-Path $WorkingDirectory 'config.yaml' - $unit = @" -[Unit] -Description=$ServiceDisplayName -After=network-online.target -Wants=network-online.target - -[Service] -Type=simple -WorkingDirectory=$WorkingDirectory -ExecStart=$BinaryPath daemon --config $configPath -Restart=always -RestartSec=5 -User=root - -[Install] -WantedBy=multi-user.target -"@ - [System.IO.File]::WriteAllText($unitPath, $unit, $script:Utf8NoBom) - & systemctl daemon-reload | Out-Null - & systemctl enable $ServiceName | Out-Null - & systemctl restart $ServiceName | Out-Null - Write-Stage "Systemd unit $unitPath installed and started." -} - -function Install-LaunchdPlist { - param( - [Parameter(Mandatory)][string] $ServiceName, - [Parameter(Mandatory)][string] $ServiceDisplayName, - [Parameter(Mandatory)][string] $BinaryPath, - [Parameter(Mandatory)][string] $WorkingDirectory - ) - $label = "com.gitea.$ServiceName" - $plistPath = "/Library/LaunchDaemons/$label.plist" - $configPath = Join-Path $WorkingDirectory 'config.yaml' - $plist = @" - - - - - Label$label - ProgramArguments - - $BinaryPath - daemon - --config - $configPath - - WorkingDirectory$WorkingDirectory - RunAtLoad - KeepAlive - - -"@ - [System.IO.File]::WriteAllText($plistPath, $plist, $script:Utf8NoBom) - & chmod 0644 $plistPath | Out-Null - & launchctl unload $plistPath 2>$null | Out-Null - & launchctl load -w $plistPath | Out-Null - Write-Stage "Launchd plist $plistPath installed and loaded." -} - -function Install-WindowsService { - param( - [Parameter(Mandatory)][string] $ServiceName, - [Parameter(Mandatory)][string] $ServiceDisplayName, - [Parameter(Mandatory)][string] $BinaryPath, - [Parameter(Mandatory)][string] $WorkingDirectory - ) - $configPath = Join-Path $WorkingDirectory 'config.yaml' - $binPath = "`"$BinaryPath`" daemon --config `"$configPath`"" - $existing = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue - if ($existing) { - Write-Stage "Service $ServiceName exists; updating binary path and restarting." - & sc.exe config $ServiceName binPath= $binPath DisplayName= $ServiceDisplayName | Out-Null - if ($existing.Status -eq 'Running') { Stop-Service -Name $ServiceName -Force } - } else { - Write-Stage "Creating Windows service $ServiceName." - & sc.exe create $ServiceName binPath= $binPath start= auto DisplayName= $ServiceDisplayName | Out-Null - if ($LASTEXITCODE -ne 0) { throw "sc.exe create failed with exit code $LASTEXITCODE." } - } - Start-Service -Name $ServiceName - Write-Stage "Service $ServiceName started." -} - - -# --- Main ---------------------------------------------------------------- - -Assert-Elevated - -if ([string]::IsNullOrWhiteSpace($ServiceName) -or ($ServiceName -match '\s')) { - throw "ServiceName must be a non-empty identifier with no whitespace (got: '$ServiceName'). Use -ServiceDisplayName for the friendly label." -} -if ([string]::IsNullOrWhiteSpace($ServiceDisplayName)) { $ServiceDisplayName = $ServiceName } - -if ([string]::IsNullOrWhiteSpace($InstanceUrl)) { - $InstanceUrl = Resolve-FromEnvVarNames -DisplayName 'InstanceUrl' -Names @( - 'GITEA_INSTANCE_URL', - 'GITEA_URL', - 'CLOUDINIT_GITEA_INSTANCE_URL', - 'CLOUDINIT_GITEA_URL' - ) -} -if ([string]::IsNullOrWhiteSpace($RegistrationToken)) { - $RegistrationToken = Resolve-FromEnvVarNames -DisplayName 'RegistrationToken' -Names @( - 'GITEA_RUNNER_REGISTRATION_TOKEN', - 'GITEA_RUNNER_TOKEN', - 'GITEA_REGISTRATION_TOKEN', - 'CLOUDINIT_GITEA_RUNNER_REGISTRATION_TOKEN', - 'CLOUDINIT_GITEA_RUNNER_TOKEN', - 'CLOUDINIT_GITEA_REGISTRATION_TOKEN' - ) -} - -if ([string]::IsNullOrWhiteSpace($InstanceUrl)) { throw 'InstanceUrl not provided and no matching env var found.' } -if ([string]::IsNullOrWhiteSpace($RegistrationToken)) { throw 'RegistrationToken not provided and no matching env var found.' } - -$platform = Get-PlatformDescriptor -if (-not $InstallRoot) { $InstallRoot = Get-DefaultInstallRoot } -if (-not $BinaryName) { $BinaryName = if ($IsWindows) { 'act_runner.exe' } else { 'act_runner' } } - -$resolvedVersion = Resolve-ReleaseTag -Requested $Version -$assetName = "gitea-runner-$resolvedVersion-$($platform.Os)-$($platform.Arch)$($platform.Suffix)" -$downloadUri = "https://gitea.com/gitea/runner/releases/download/v$resolvedVersion/$assetName" - -if (-not (Test-Path -LiteralPath $InstallRoot)) { - Write-Stage "Creating install root $InstallRoot." - New-Item -ItemType Directory -Path $InstallRoot -Force | Out-Null -} - -$binaryPath = Join-Path $InstallRoot $BinaryName -$installedVersion = Get-InstalledBinaryVersion -BinaryPath $binaryPath - -if ($installedVersion -eq $resolvedVersion -and -not $Force) { - Write-Stage "act_runner $installedVersion already installed; skipping download." -} else { - if ($installedVersion) { Write-Stage "Upgrading act_runner $installedVersion -> $resolvedVersion." } - Save-BinaryViaWebClient -Uri $downloadUri -Destination $binaryPath - if (-not $IsWindows) { & chmod 0755 $binaryPath | Out-Null } -} - -Add-ToMachinePath -Directory $InstallRoot - -Register-Runner -BinaryPath $binaryPath -WorkingDirectory $InstallRoot ` - -InstanceUrl $InstanceUrl -Token $RegistrationToken ` - -RunnerName $RunnerName -Labels $Labels -Force:$Force - -if ($IsLinux) { Install-SystemdUnit -ServiceName $ServiceName -ServiceDisplayName $ServiceDisplayName -BinaryPath $binaryPath -WorkingDirectory $InstallRoot } -elseif ($IsMacOS) { Install-LaunchdPlist -ServiceName $ServiceName -ServiceDisplayName $ServiceDisplayName -BinaryPath $binaryPath -WorkingDirectory $InstallRoot } -elseif ($IsWindows) { Install-WindowsService -ServiceName $ServiceName -ServiceDisplayName $ServiceDisplayName -BinaryPath $binaryPath -WorkingDirectory $InstallRoot } - -Write-Stage "Gitea runner installation complete (version $resolvedVersion, service $ServiceName / '$ServiceDisplayName')." \ No newline at end of file