param( [switch]$Push, [string]$EnvFile = ".devcontainer/.env", [string]$Dockerfile = ".devcontainer/Dockerfile" ) $ErrorActionPreference = "Stop" if (!(Test-Path $EnvFile)) { throw "Env file not found: $EnvFile" } $vars = @{} Get-Content $EnvFile | ForEach-Object { $line = $_.Trim() if ($line -and -not $line.StartsWith("#")) { $pair = $line -split "=", 2 if ($pair.Count -eq 2) { $vars[$pair[0].Trim()] = $pair[1].Trim() } } } $required = @("PYTHON_BASE", "DEVCONTAINER_IMAGE_PUSH_REPO", "DEVCONTAINER_IMAGE_REV") foreach ($key in $required) { if (-not $vars.ContainsKey($key) -or [string]::IsNullOrWhiteSpace($vars[$key])) { throw "Missing required key '$key' in $EnvFile" } } $pythonBase = $vars["PYTHON_BASE"] $pushRepo = $vars["DEVCONTAINER_IMAGE_PUSH_REPO"] $rev = $vars["DEVCONTAINER_IMAGE_REV"] $versionTag = "${pushRepo}:${pythonBase}-${rev}-devcontainer" $channelTag = "${pushRepo}:${pythonBase}-devcontainer" $registry = ($pushRepo -split "/", 2)[0] function Invoke-DockerPushWithLoginFallback { param( [Parameter(Mandatory = $true)] [string]$Tag, [Parameter(Mandatory = $true)] [string]$Registry ) Write-Host "Pushing $Tag" docker push $Tag if ($LASTEXITCODE -eq 0) { return } Write-Warning "docker push failed for $Tag. Trying docker login to $Registry and retrying once." docker login $Registry if ($LASTEXITCODE -ne 0) { throw "docker login failed for $Registry" } docker push $Tag if ($LASTEXITCODE -ne 0) { throw "docker push failed for $Tag after login fallback" } } Write-Host "Building $versionTag" docker build -f $Dockerfile --build-arg "PYTHON_VERSION=$pythonBase" -t $versionTag -t $channelTag . if ($LASTEXITCODE -ne 0) { throw "docker build failed" } if ($Push) { Invoke-DockerPushWithLoginFallback -Tag $versionTag -Registry $registry Invoke-DockerPushWithLoginFallback -Tag $channelTag -Registry $registry }