Modules/businessdev.ALbuild.Containers/Public/Invoke-BcDocker.ps1
|
function Invoke-BcDocker { <# .SYNOPSIS Runs a Docker CLI command for ALbuild (the central Docker entry point). .DESCRIPTION Every Docker interaction in ALbuild goes through this function so behaviour is consistent: the Docker CLI is located (and a clear error raised if it is missing), the command is run via Invoke-ALbuildProcess (reliable output capture, optional retry/back-off), registry authentication failures on 'pull' are turned into actionable errors, and output is logged through Write-ALbuildLog. This is ALbuild's equivalent of BcContainerHelper's DockerDo, written from scratch on top of the shared process helper. .PARAMETER Arguments The Docker command and its arguments, e.g. @('ps','--all','--format','{{.Names}}'). .PARAMETER DockerExecutable The Docker executable to use. Default 'docker'. Allows full paths or alternatives (e.g. 'docker.exe', 'podman') and makes the function testable against a stand-in. .PARAMETER WorkingDirectory Working directory for the Docker process. .PARAMETER SuccessExitCodes Exit codes treated as success. Default: 0. .PARAMETER RetryCount Additional attempts on failure (use for transient operations such as 'pull'). Default 0. .PARAMETER RetryDelaySeconds Delay between attempts. Default 5. .PARAMETER PassThru Return the result object even on failure instead of throwing. .PARAMETER Quiet Do not echo Docker stdout through Write-ALbuildLog. .EXAMPLE Invoke-BcDocker -Arguments @('version','--format','{{.Server.Version}}') .EXAMPLE Invoke-BcDocker -Arguments @('pull', $imageName) -RetryCount 5 -RetryDelaySeconds 15 .OUTPUTS PSCustomObject with ExitCode, StdOut, StdErr, Success, Attempts. #> [CmdletBinding()] param( [Parameter(Mandatory, Position = 0)] [ValidateNotNullOrEmpty()] [string[]] $Arguments, [string] $DockerExecutable = 'docker', [string] $WorkingDirectory, [int[]] $SuccessExitCodes = @(0), [ValidateRange(0, [int]::MaxValue)] [int] $RetryCount = 0, [ValidateRange(0, [int]::MaxValue)] [int] $RetryDelaySeconds = 5, [switch] $PassThru, [switch] $Quiet, # Echo the process output live (chunk-streamed) instead of only after it completes - used for # long-running container operations so progress is visible. [switch] $StreamOutput ) $command = Get-Command -Name $DockerExecutable -CommandType Application -ErrorAction SilentlyContinue | Select-Object -First 1 if (-not $command) { throw "The Docker CLI ('$DockerExecutable') was not found on PATH. Business Central containers require Docker on a Windows host. Install Docker, or run containerless operations instead." } $procArgs = @{ FilePath = $command.Source Arguments = $Arguments SuccessExitCodes = $SuccessExitCodes RetryCount = $RetryCount RetryDelaySeconds = $RetryDelaySeconds PassThru = $true } if ($WorkingDirectory) { $procArgs['WorkingDirectory'] = $WorkingDirectory } if ($StreamOutput) { $procArgs['StreamOutput'] = $true } $result = Invoke-ALbuildProcess @procArgs if (-not $Quiet -and -not [string]::IsNullOrWhiteSpace($result.StdOut)) { Write-ALbuildLog $result.StdOut.TrimEnd() } if (-not $result.Success) { $combined = "$($result.StdOut)`n$($result.StdErr)" if ($combined -match '(?im)please login|unauthorized|denied|authentication required') { $registry = ($Arguments | Where-Object { $_ -match '/' } | Select-Object -First 1) if ($registry) { $registry = $registry.Split('/')[0] } throw "Docker registry authentication is required$(if ($registry) { " for '$registry'" }). Log in with 'docker login' (for Microsoft insider/private images, obtain credentials via the Microsoft ReadyToGo / Collaborate program) and retry." } if (-not $PassThru) { $detail = if ([string]::IsNullOrWhiteSpace($result.StdErr)) { $result.StdOut } else { $result.StdErr } throw "Docker command 'docker $($Arguments -join ' ')' failed with exit code $($result.ExitCode).$(if ([string]::IsNullOrWhiteSpace($detail)) { '' } else { [Environment]::NewLine + $detail.Trim() })" } } return $result } |