forked from Crockan/MercuryToolbox
chore(release): prepare public source release
This commit is contained in:
@@ -0,0 +1,319 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$InstanceUrl,
|
||||
[string]$Owner,
|
||||
[string]$Repo,
|
||||
[string]$RunnerName,
|
||||
[string]$RunnerRoot,
|
||||
[string]$ApiToken,
|
||||
[switch]$SkipInstall,
|
||||
[switch]$SkipStartupRegistration
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
Set-StrictMode -Version Latest
|
||||
|
||||
function Invoke-GitCapture {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string[]]$ArgumentList
|
||||
)
|
||||
|
||||
$output = & git @ArgumentList 2>&1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "git $($ArgumentList -join ' ') failed: $($output -join "`n")"
|
||||
}
|
||||
|
||||
return (($output | ForEach-Object { [string]$_ }) -join "`n").Trim()
|
||||
}
|
||||
|
||||
function Resolve-GiteaRepositoryContext {
|
||||
$remoteUrl = Invoke-GitCapture -ArgumentList @('remote', 'get-url', 'origin')
|
||||
$normalized = $remoteUrl.Trim()
|
||||
|
||||
if ($normalized -match '^(https?://[^/]+)/([^/]+)/([^/]+?)(?:\.git)?$') {
|
||||
return [pscustomobject]@{
|
||||
BaseUrl = $Matches[1]
|
||||
Owner = $Matches[2]
|
||||
Repo = $Matches[3]
|
||||
}
|
||||
}
|
||||
|
||||
if ($normalized -match '^ssh://git@([^/:]+)(?::(\d+))?/([^/]+)/([^/]+?)(?:\.git)?$') {
|
||||
$giteaHost = $Matches[1]
|
||||
$port = if ([string]::IsNullOrWhiteSpace($Matches[2])) { '' } else { ":$($Matches[2])" }
|
||||
return [pscustomobject]@{
|
||||
BaseUrl = "https://$giteaHost$port"
|
||||
Owner = $Matches[3]
|
||||
Repo = $Matches[4]
|
||||
}
|
||||
}
|
||||
|
||||
throw "Could not parse Gitea origin remote URL: $normalized"
|
||||
}
|
||||
|
||||
function Resolve-ApiToken {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$BaseUrl,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$RepoOwner,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$RepoName,
|
||||
[string]$ExplicitToken
|
||||
)
|
||||
|
||||
if (-not [string]::IsNullOrWhiteSpace($ExplicitToken)) {
|
||||
return $ExplicitToken
|
||||
}
|
||||
|
||||
foreach ($name in @('GITEA_API_TOKEN', 'GITEA_TOKEN', 'GITHUB_TOKEN')) {
|
||||
$value = [Environment]::GetEnvironmentVariable($name)
|
||||
if (-not [string]::IsNullOrWhiteSpace($value)) {
|
||||
return $value
|
||||
}
|
||||
}
|
||||
|
||||
$uri = [Uri]$BaseUrl
|
||||
$lines = @(
|
||||
'protocol=https'
|
||||
"host=$($uri.Authority)"
|
||||
"path=$RepoOwner/$RepoName.git"
|
||||
''
|
||||
) | git credential fill
|
||||
$passwordLine = $lines | Where-Object { $_ -like 'password=*' } | Select-Object -First 1
|
||||
if ($null -eq $passwordLine) {
|
||||
throw 'Could not resolve a Gitea API token from the current environment or git credential manager.'
|
||||
}
|
||||
|
||||
return $passwordLine.Substring(9)
|
||||
}
|
||||
|
||||
function Invoke-GiteaApi {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Method,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Uri,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Token
|
||||
)
|
||||
|
||||
$headers = @{
|
||||
Authorization = "token $Token"
|
||||
}
|
||||
|
||||
try {
|
||||
return Invoke-RestMethod -Method $Method -Uri $Uri -Headers $headers -ErrorAction Stop
|
||||
}
|
||||
catch {
|
||||
$response = $_.Exception.Response
|
||||
if ($null -eq $response) {
|
||||
throw
|
||||
}
|
||||
$statusCode = [int]$response.StatusCode
|
||||
$payload = ''
|
||||
if ($response -is [System.Net.Http.HttpResponseMessage]) {
|
||||
if ($null -ne $_.ErrorDetails -and -not [string]::IsNullOrWhiteSpace($_.ErrorDetails.Message)) {
|
||||
$payload = $_.ErrorDetails.Message
|
||||
}
|
||||
elseif ($null -ne $response.Content) {
|
||||
try {
|
||||
$payload = $response.Content.ReadAsStringAsync().GetAwaiter().GetResult()
|
||||
}
|
||||
catch {
|
||||
$payload = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ($response.PSObject.Methods.Name -contains 'GetResponseStream') {
|
||||
$stream = $response.GetResponseStream()
|
||||
if ($null -ne $stream) {
|
||||
$reader = [System.IO.StreamReader]::new($stream)
|
||||
try {
|
||||
$payload = $reader.ReadToEnd()
|
||||
}
|
||||
finally {
|
||||
$reader.Dispose()
|
||||
$stream.Dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
throw "Gitea API $Method $Uri failed with HTTP ${statusCode}: $payload"
|
||||
}
|
||||
}
|
||||
|
||||
function Resolve-RunnerExe {
|
||||
$command = Get-Command -Name 'gitea-runner.exe' -ErrorAction SilentlyContinue
|
||||
if ($null -ne $command) {
|
||||
return $command.Source
|
||||
}
|
||||
|
||||
$command = Get-Command -Name 'gitea-runner' -ErrorAction SilentlyContinue
|
||||
if ($null -ne $command) {
|
||||
return $command.Source
|
||||
}
|
||||
|
||||
$candidate = Join-Path $env:LOCALAPPDATA 'Microsoft\WinGet\Packages\Gitea.Runner_Microsoft.Winget.Source_8wekyb3d8bbwe\gitea-runner.exe'
|
||||
if (Test-Path -LiteralPath $candidate -PathType Leaf) {
|
||||
return $candidate
|
||||
}
|
||||
|
||||
if ($SkipInstall) {
|
||||
throw 'gitea-runner was not found and -SkipInstall was requested.'
|
||||
}
|
||||
|
||||
& winget install --id Gitea.Runner -e --accept-package-agreements --accept-source-agreements
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "winget install Gitea.Runner failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $candidate -PathType Leaf)) {
|
||||
throw "gitea-runner was installed but not found at expected path: $candidate"
|
||||
}
|
||||
|
||||
return $candidate
|
||||
}
|
||||
|
||||
$context = Resolve-GiteaRepositoryContext
|
||||
if ([string]::IsNullOrWhiteSpace($InstanceUrl)) {
|
||||
$InstanceUrl = $context.BaseUrl
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($Owner)) {
|
||||
$Owner = $context.Owner
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($Repo)) {
|
||||
$Repo = $context.Repo
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($RunnerName)) {
|
||||
$RunnerName = "$Repo-local-win"
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($RunnerRoot)) {
|
||||
$RunnerRoot = Join-Path $env:LOCALAPPDATA "GiteaRunner\$Repo"
|
||||
}
|
||||
|
||||
$runnerExe = Resolve-RunnerExe
|
||||
$ApiToken = Resolve-ApiToken -BaseUrl $InstanceUrl -RepoOwner $Owner -RepoName $Repo -ExplicitToken $ApiToken
|
||||
$registration = Invoke-GiteaApi -Method 'POST' -Uri "$InstanceUrl/api/v1/repos/$Owner/$Repo/actions/runners/registration-token" -Token $ApiToken
|
||||
$registrationToken = [string]$registration.token
|
||||
if ([string]::IsNullOrWhiteSpace($registrationToken)) {
|
||||
throw 'Gitea did not return a runner registration token.'
|
||||
}
|
||||
|
||||
$configPath = Join-Path $RunnerRoot 'config.yaml'
|
||||
$registrationPath = Join-Path $RunnerRoot '.runner'
|
||||
$logPath = Join-Path $RunnerRoot 'daemon.log'
|
||||
$startScriptPath = Join-Path $RunnerRoot 'start-runner.ps1'
|
||||
$startupFolder = [Environment]::GetFolderPath('Startup')
|
||||
$startupCmdPath = Join-Path $startupFolder "$Repo-gitea-runner.cmd"
|
||||
$workdirParent = Join-Path $RunnerRoot 'workdir'
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $RunnerRoot, $workdirParent | Out-Null
|
||||
|
||||
$fullPath = [string]::Join(';', (@(
|
||||
[Environment]::GetEnvironmentVariable('Path', 'User'),
|
||||
[Environment]::GetEnvironmentVariable('Path', 'Machine')
|
||||
) | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }))
|
||||
$cargoHome = if ($env:CARGO_HOME) { $env:CARGO_HOME } else { Join-Path $HOME '.cargo' }
|
||||
$rustupHome = if ($env:RUSTUP_HOME) { $env:RUSTUP_HOME } else { Join-Path $HOME '.rustup' }
|
||||
$repoHostLabel = "${Repo}:host"
|
||||
|
||||
$config = @"
|
||||
log:
|
||||
level: info
|
||||
|
||||
runner:
|
||||
file: .runner
|
||||
capacity: 1
|
||||
envs:
|
||||
PATH: $fullPath
|
||||
CARGO_HOME: $cargoHome
|
||||
RUSTUP_HOME: $rustupHome
|
||||
CARGO_INCREMENTAL: '0'
|
||||
env_file: .env
|
||||
timeout: 3h
|
||||
shutdown_timeout: 30s
|
||||
insecure: false
|
||||
fetch_timeout: 5s
|
||||
fetch_interval: 2s
|
||||
fetch_interval_max: 5s
|
||||
workdir_cleanup_age: 24h
|
||||
idle_cleanup_interval: 10m
|
||||
labels:
|
||||
- 'windows-amd64:host'
|
||||
- 'windows:host'
|
||||
- '$repoHostLabel'
|
||||
allocate_pty: false
|
||||
|
||||
cache:
|
||||
enabled: true
|
||||
dir: ''
|
||||
host: ''
|
||||
port: 0
|
||||
external_server: ''
|
||||
external_secret: ''
|
||||
offline_mode: false
|
||||
|
||||
container:
|
||||
network: ''
|
||||
privileged: false
|
||||
options:
|
||||
workdir_parent:
|
||||
valid_volumes: []
|
||||
docker_host: ''
|
||||
force_pull: true
|
||||
force_rebuild: false
|
||||
require_docker: false
|
||||
docker_timeout: 0s
|
||||
bind_workdir: false
|
||||
|
||||
host:
|
||||
workdir_parent: '$($workdirParent -replace '\\', '/')'
|
||||
|
||||
metrics:
|
||||
enabled: false
|
||||
addr: '127.0.0.1:9101'
|
||||
"@
|
||||
Set-Content -LiteralPath $configPath -Value $config -Encoding utf8NoBOM
|
||||
|
||||
if (-not (Test-Path -LiteralPath $registrationPath)) {
|
||||
Push-Location -LiteralPath $RunnerRoot
|
||||
try {
|
||||
& $runnerExe register --no-interactive --config $configPath --instance $InstanceUrl --token $registrationToken --name $RunnerName
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "gitea-runner register failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
}
|
||||
|
||||
$startScript = @"
|
||||
`$ErrorActionPreference = 'Stop'
|
||||
Set-Location '$RunnerRoot'
|
||||
& '$runnerExe' daemon --config '$configPath' *>> '$logPath'
|
||||
"@
|
||||
Set-Content -LiteralPath $startScriptPath -Value $startScript -Encoding utf8NoBOM
|
||||
|
||||
if (-not $SkipStartupRegistration) {
|
||||
$startupCmd = @"
|
||||
@echo off
|
||||
powershell -NoProfile -WindowStyle Hidden -File "$startScriptPath"
|
||||
"@
|
||||
Set-Content -LiteralPath $startupCmdPath -Value $startupCmd -Encoding ascii
|
||||
}
|
||||
|
||||
$existing = Get-CimInstance Win32_Process | Where-Object { $_.Name -eq 'gitea-runner.exe' -and $_.CommandLine -like "*$configPath*" }
|
||||
if ($null -eq $existing) {
|
||||
Start-Process -FilePath $runnerExe -ArgumentList @('daemon', '--config', $configPath) -WorkingDirectory $RunnerRoot -WindowStyle Hidden | Out-Null
|
||||
Start-Sleep -Seconds 3
|
||||
}
|
||||
|
||||
$runners = Invoke-GiteaApi -Method 'GET' -Uri "$InstanceUrl/api/v1/repos/$Owner/$Repo/actions/runners" -Token $ApiToken
|
||||
$matched = @($runners.runners | Where-Object { $_.name -eq $RunnerName })
|
||||
if ($matched.Count -eq 0) {
|
||||
throw "Runner $RunnerName was not visible in the repository runner list after setup."
|
||||
}
|
||||
|
||||
$matched | ConvertTo-Json -Depth 6
|
||||
Reference in New Issue
Block a user