[CmdletBinding()] param( [string]$Remote = 'origin', [string]$BaseUrl, [string]$Owner, [string]$Repo, [string]$UserName, [string]$ApiToken, [switch]$InsecureSkipTlsVerify, [Parameter(Position = 0, ValueFromRemainingArguments = $true)] [string[]]$GitArgs ) $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 { param( [string]$RemoteName, [string]$RemoteUrl ) if ([string]::IsNullOrWhiteSpace($RemoteUrl)) { $RemoteUrl = Invoke-GitCapture -ArgumentList @('remote', 'get-url', $RemoteName) } $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)?$') { $scheme = 'https' $giteaHost = $Matches[1] $port = if ([string]::IsNullOrWhiteSpace($Matches[2])) { '' } else { ":$($Matches[2])" } return [pscustomobject]@{ BaseUrl = "${scheme}://$giteaHost$port" Owner = $Matches[3] Repo = $Matches[4] } } throw "Could not parse Gitea remote URL: $normalized" } function Resolve-ApiToken { param( [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 } } throw 'No Gitea token was provided. Pass -ApiToken or set GITEA_API_TOKEN/GITEA_TOKEN for this process; this helper deliberately does not call Git Credential Manager.' } function Get-ScopedEnvironment { param( [Parameter(Mandatory = $true)] [string[]]$Names ) $values = @{} foreach ($name in $Names) { $values[$name] = [Environment]::GetEnvironmentVariable($name, 'Process') } return $values } function Set-ScopedEnvironment { param( [Parameter(Mandatory = $true)] [hashtable]$Values ) foreach ($entry in $Values.GetEnumerator()) { [Environment]::SetEnvironmentVariable($entry.Key, $entry.Value, 'Process') } } function Write-GitOutput { param( [object[]]$Output ) foreach ($item in $Output) { $line = [string]$item if ($line -match '^\d{2}:\d{2}:\d{2}\.\d+\s+http\.c:\d+\s+') { continue } Write-Output $line } } if ($GitArgs.Count -gt 0 -and $GitArgs[0] -eq '--') { $GitArgs = @($GitArgs | Select-Object -Skip 1) } if ($GitArgs.Count -eq 0) { throw 'Pass the git subcommand, for example: .\scripts\invoke-gitea-git.ps1 ls-remote origin refs/heads/main' } $workspaceRoot = Split-Path -Parent $PSScriptRoot Push-Location -LiteralPath $workspaceRoot try { $context = Resolve-GiteaRepositoryContext -RemoteName $Remote if ([string]::IsNullOrWhiteSpace($BaseUrl)) { $BaseUrl = $context.BaseUrl } if ([string]::IsNullOrWhiteSpace($Owner)) { $Owner = $context.Owner } if ([string]::IsNullOrWhiteSpace($Repo)) { $Repo = $context.Repo } if ([string]::IsNullOrWhiteSpace($UserName)) { $UserName = $Owner } $resolvedToken = Resolve-ApiToken -ExplicitToken $ApiToken $basic = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("${UserName}:$resolvedToken")) $configArgs = @( '-c', 'credential.helper=', '-c', 'http.sslBackend=openssl', '-c', "http.extraHeader=Authorization: Basic $basic" ) if ($InsecureSkipTlsVerify) { $configArgs += @('-c', 'http.sslVerify=false') } $scopedEnvironmentValues = @{ GIT_TERMINAL_PROMPT = '0' GIT_TRACE = '0' GIT_TRACE2 = '0' GIT_TRACE2_EVENT = '0' GIT_TRACE2_PERF = '0' GIT_TRACE_PACKET = '0' GIT_TRACE_CURL = '0' GIT_CURL_VERBOSE = $null } $scopedNames = @($scopedEnvironmentValues.Keys) $previousEnvironment = Get-ScopedEnvironment -Names $scopedNames Set-ScopedEnvironment -Values $scopedEnvironmentValues try { $gitOutput = @(& git @configArgs @GitArgs 2>&1) $exitCode = $LASTEXITCODE } finally { Set-ScopedEnvironment -Values $previousEnvironment } Write-GitOutput -Output $gitOutput if ($exitCode -ne 0) { throw "git command failed with exit code $exitCode. The transient Authorization header was not printed or persisted." } } finally { Pop-Location }