Private/Invoke-GEGit.ps1
|
function Invoke-GEGit { <# .SYNOPSIS Run a Git command and return its exit code and output as separate stdout and stderr arrays. .DESCRIPTION Invoke-GEGit is the engine's single point of contact with Git. It captures stdout and stderr separately so that warnings (for example, LF/CRLF notices) do not poison parsed output. By default it throws when Git exits non-zero; -AllowFailure suppresses that and returns the result for the caller to inspect. Pass -LogPath to append a per-step record (command, exit code, stdout, stderr) to a diagnostic log file. .PARAMETER ArgumentList The Git command and its arguments, as a string array. .PARAMETER WorkingDirectory Where to run the command. Defaults to the current location. .PARAMETER AllowFailure Return the result instead of throwing when the exit code is non-zero. .PARAMETER LogPath Optional path to a diagnostic log file. When set, every call appends a step record. .EXAMPLE $r = Invoke-GEGit -ArgumentList @('rev-parse', '--show-toplevel') .EXAMPLE $r = Invoke-GEGit -ArgumentList @('push') -WorkingDirectory $root -LogPath $session.Path .NOTES Internal. Public commands route every Git call through this helper. Steps: 1. Change to the working directory, run the Git command capturing combined output, then restore the previous location. 2. Separate the combined output into stdout lines and stderr lines (ErrorRecord objects are stderr). 3. Sanitize each argument before logging to strip any embedded credentials. 4. If a log path was provided, append a step record with the command, exit code, stdout, and stderr. 5. If the exit code is non-zero and -AllowFailure was not set, throw with the sanitized command and output. 6. Return a result object with the exit code, stdout array, and stderr array. .LINK Save-Work #> [CmdletBinding()] param( [Parameter(Mandatory)] [string[]]$ArgumentList, [string]$WorkingDirectory = (Get-Location).Path, [switch]$AllowFailure, [string]$LogPath = '' ) $previousLocation = Get-Location try { Set-Location -LiteralPath $WorkingDirectory $previousActionPreference = $ErrorActionPreference $ErrorActionPreference = 'Continue' $merged = & git @ArgumentList 2>&1 $exitCode = $LASTEXITCODE $ErrorActionPreference = $previousActionPreference } finally { $ErrorActionPreference = 'Stop' Set-Location -LiteralPath $previousLocation } $stdoutLines = New-Object System.Collections.Generic.List[string] $stderrLines = New-Object System.Collections.Generic.List[string] foreach ($entry in @($merged)) { if ($null -eq $entry) { continue } if ($entry -is [System.Management.Automation.ErrorRecord]) { $stderrLines.Add($entry.ToString()) } else { $stdoutLines.Add($entry.ToString()) } } # F-06: an arg to Invoke-GEGit can be a remote URL with embedded # credentials (e.g. `remote set-url origin https://x:tok@host/...`). # Sanitise each arg before it lands in the log step header or the # thrown error message. Format-GESafeUrl is a no-op on args that are # not URL-shaped, so this is safe to apply unconditionally. $safeArgs = @($ArgumentList | ForEach-Object { Format-GESafeUrl -Url $_ }) if (-not [string]::IsNullOrWhiteSpace($LogPath)) { $stepText = 'git ' + ($safeArgs -join ' ') $logLines = New-Object System.Collections.Generic.List[string] foreach ($line in $stdoutLines) { $logLines.Add($line) } foreach ($line in $stderrLines) { $logLines.Add('[stderr] ' + $line) } Add-GELogStep -Path $LogPath -Step $stepText -ExitCode $exitCode -Output $logLines } if (($exitCode -ne 0) -and (-not $AllowFailure)) { $combined = New-Object System.Collections.Generic.List[string] foreach ($line in $stdoutLines) { $combined.Add($line) } foreach ($line in $stderrLines) { $combined.Add($line) } throw ("git " + ($safeArgs -join ' ') + " exited with code $exitCode" + [Environment]::NewLine + ($combined -join [Environment]::NewLine)) } [PSCustomObject]@{ ExitCode = $exitCode Output = @($stdoutLines) Stderr = @($stderrLines) } } |