Docker-Images/build-and-push.ps1

111 lines
3.7 KiB
PowerShell

#Requires -Version 5.1
<#
.SYNOPSIS
Build and push a CI image to the Harbor registry using podman.
.EXAMPLE
.\build-and-push.ps1 -Image ci/java-builder
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Image,
[Parameter(Mandatory = $false)]
[string]$Version
)
$ErrorActionPreference = 'Stop'
# --- Load .env ---
$envFile = Join-Path $PSScriptRoot '.env'
if (-not (Test-Path $envFile)) { throw ".env not found at $envFile" }
Get-Content $envFile | ForEach-Object {
if ($_ -match '^\s*([^#=\s]+)\s*=\s*(.*?)\s*$') {
$value = $matches[2].TrimEnd("`r")
if ($value.StartsWith('"') -and $value.EndsWith('"')) { $value = $value.Substring(1, $value.Length - 2) }
elseif ($value.StartsWith("'") -and $value.EndsWith("'")) { $value = $value.Substring(1, $value.Length - 2) }
[Environment]::SetEnvironmentVariable($matches[1], $value)
}
}
foreach ($v in 'REGISTRY', 'REGISTRY_USER', 'REGISTRY_PASS') {
if (-not (Get-Item "env:$v" -ErrorAction SilentlyContinue).Value) {
throw "$v not set in .env"
}
}
# --- Resolve paths ---
# $Image is the path to the image directory relative to the repo root, and
# also the image name pushed to the registry (e.g. "ci/java-builder").
$regHost = $env:REGISTRY -replace '^https?://', '' -replace '/$', ''
$imageName = ($Image -replace '\\', '/').Trim('/')
$imageDir = Join-Path $PSScriptRoot ($imageName -replace '/', [IO.Path]::DirectorySeparatorChar)
if (-not (Test-Path $imageDir)) { throw "Image directory not found: $imageDir" }
$repo = "$regHost/kollect-tools/$imageName"
$date = Get-Date -Format 'yyyyMMdd'
# --- Resolve version ---
# If -Version isn't given, parse the Dockerfile: find the variable referenced
# in the FROM line and read its ARG default (e.g. JAVA_VERSION=25 -> "25").
if (-not $Version) {
$dockerfile = Join-Path $imageDir 'Dockerfile'
$content = Get-Content $dockerfile -Raw
if ($content -match '(?m)^\s*FROM\s+\S*?\$\{(\w+)\}') {
$varName = $matches[1]
if ($content -match "(?m)^\s*ARG\s+$varName\s*=\s*`"?([^`"\s]+)`"?") {
$Version = $matches[1]
}
}
if (-not $Version) {
throw "Could not auto-detect version from $dockerfile. Pass -Version explicitly."
}
Write-Host "=> Auto-detected version: $Version (from $varName)"
}
$tags = @('latest', $Version, $date)
# --- Login ---
# Use .NET Process so stdin gets the raw password with no trailing newline
# (PowerShell's native pipe appends CRLF, which breaks --password-stdin).
Write-Host "=> Logging in to $regHost"
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = 'podman'
$psi.Arguments = "login $regHost --username `"$($env:REGISTRY_USER)`" --password-stdin"
$psi.RedirectStandardInput = $true
$psi.UseShellExecute = $false
$proc = [System.Diagnostics.Process]::Start($psi)
$proc.StandardInput.Write($env:REGISTRY_PASS)
$proc.StandardInput.Close()
$proc.WaitForExit()
if ($proc.ExitCode -ne 0) { throw "podman login failed (exit $($proc.ExitCode))" }
# --- Build ---
Write-Host "=> Building ${repo}:latest"
$buildArgs = @('build', '-t', "${repo}:latest")
if ($env:NVD_API_KEY) {
$buildArgs += @('--build-arg', "NVD_API_KEY=$env:NVD_API_KEY")
}
$buildArgs += $imageDir
& podman @buildArgs
if ($LASTEXITCODE -ne 0) { throw "podman build failed" }
# --- Tag ---
foreach ($tag in $Version, $date) {
Write-Host "=> Tagging ${repo}:$tag"
podman tag "${repo}:latest" "${repo}:$tag"
if ($LASTEXITCODE -ne 0) { throw "podman tag failed for $tag" }
}
# --- Push ---
foreach ($tag in $tags) {
Write-Host "=> Pushing ${repo}:$tag"
podman push "${repo}:$tag"
if ($LASTEXITCODE -ne 0) { throw "podman push failed for $tag" }
}
Write-Host "Done. Pushed $($tags.Count) tags to $repo"