66 [string ]$TestFilter , # Filter by test name (e.g., 'FIREBIRD_USER_can_create_user'). Used only in the 'Test' task.
77
88 [ValidateSet (' master' , ' v5.0-release' , ' v4.0' )]
9- [string ]$Branch , # Snapshot branch. Used only in the 'Build-Snapshot' task .
9+ [string ]$Branch , # Snapshot branch. Used by 'Build-Snapshot' / 'Publish-Snapshot-Manifests' .
1010
1111 [string ]$Registry # Image registry/owner prefix. Defaults to 'firebirdsql' (Docker Hub).
1212 # Override for forks: e.g. 'ghcr.io/myusername'
@@ -576,12 +576,34 @@ task Publish-Manifests FilteredAssets, {
576576 }
577577}
578578
579- # Synopsis: Build a snapshot image from a Firebird pre-release branch.
580- task Build-Snapshot LoadAssets , {
579+ # Helper: produces { snapshotTag, major, defaultDistro } for a given snapshot branch.
580+ function Get-SnapshotMeta ( $Branch ) {
581581 if (-not $Branch ) {
582- throw " The -Branch parameter is required for Build-Snapshot. Use: Invoke-Build Build-Snapshot -Branch master"
582+ throw " The -Branch parameter is required. Use: -Branch master|v5.0-release|v4.0"
583+ }
584+ $snapshotTag = switch ($Branch ) {
585+ ' master' { ' 6-snapshot' }
586+ ' v5.0-release' { ' 5-snapshot' }
587+ ' v4.0' { ' 4-snapshot' }
588+ default { throw " Unknown snapshot branch: $Branch " }
589+ }
590+ $major = switch ($Branch ) {
591+ ' master' { ' 6' }
592+ ' v5.0-release' { ' 5' }
593+ ' v4.0' { ' 4' }
594+ }
595+ [pscustomobject ]@ {
596+ SnapshotTag = $snapshotTag
597+ Major = $major
598+ DefaultDistro = $script :assetsData.config.defaultDistro
583599 }
600+ }
584601
602+ # Synopsis: Build a snapshot image and push it by digest to the registry.
603+ # Saves the digest to generated/digests-snapshot-{arch}.json so a later
604+ # Publish-Snapshot-Manifests run can assemble the multi-arch manifest.
605+ # Caller must be logged into the registry before invoking this task.
606+ task Build-Snapshot LoadAssets, {
585607 # PSFirebird is required for this task
586608 if (-not (Get-Module PSFirebird - ListAvailable)) {
587609 Install-Module PSFirebird - MinimumVersion ' 1.0.0' - Force - Scope CurrentUser
@@ -591,7 +613,10 @@ task Build-Snapshot LoadAssets, {
591613 $PSStyle.OutputRendering = ' PlainText'
592614 $imagePrefix = $script :imagePrefix
593615 $imageName = ' firebird'
594- $defaultDistro = $script :assetsData.config.defaultDistro
616+ $meta = Get-SnapshotMeta $Branch
617+ $snapshotTag = $meta.SnapshotTag
618+ $major = $meta.Major
619+ $defaultDistro = $meta.DefaultDistro
595620
596621 # Detect host architecture
597622 $hostArch = if ($IsLinux ) { (dpkg -- print- architecture 2> $null ) ?? ' amd64' } else { ' amd64' }
@@ -602,20 +627,6 @@ task Build-Snapshot LoadAssets, {
602627
603628 Write-Build Cyan " Found: $ ( $snapshot.FileName ) (uploaded: $ ( $snapshot.UploadedAt ) )"
604629
605- # Determine version tag from branch
606- $snapshotTag = switch ($Branch ) {
607- ' master' { ' 6-snapshot' }
608- ' v5.0-release' { ' 5-snapshot' }
609- ' v4.0' { ' 4-snapshot' }
610- }
611-
612- # Determine major version for Dockerfile template
613- $major = switch ($Branch ) {
614- ' master' { ' 6' }
615- ' v5.0-release' { ' 5' }
616- ' v4.0' { ' 4' }
617- }
618-
619630 # Prepare snapshot Dockerfile
620631 $snapshotFolder = Join-Path $outputFolder " snapshot-$Branch " $defaultDistro
621632 New-Item - ItemType Directory $snapshotFolder - Force > $null
@@ -645,24 +656,71 @@ task Build-Snapshot LoadAssets, {
645656 Write-GeneratedFile - Content $dockerfile - Destination " $snapshotFolder /Dockerfile"
646657 Copy-Item ' ./src/entrypoint.sh' $snapshotFolder
647658
648- # Tag with both the bare alias (e.g. `6-snapshot`) and the base-qualified form
649- # (e.g. `6-snapshot-trixie`) so users can tell which distro the snapshot was built on.
650- $snapshotTagWithDistro = " $snapshotTag -$defaultDistro "
651-
652- # Build
659+ # Build and push by digest. Final tags (e.g. `6-snapshot`, `6-snapshot-trixie`)
660+ # are assembled from per-arch digests by Publish-Snapshot-Manifests.
661+ $metadataFile = Join-Path ([System.IO.Path ]::GetTempPath()) " metadata-snapshot-$Branch .json"
653662 $buildArgs = @ (
654- ' buildx' , ' build' , ' --load '
655- ' --tag ' , " $imagePrefix /${ imageName} : $snapshotTag "
656- ' --tag ' , " $imagePrefix / ${imageName} : $snapshotTagWithDistro "
663+ ' buildx' , ' build'
664+ ' --output ' , " type=image,name= $imagePrefix /$imageName ,push-by-digest=true,name-canonical=true,push=true "
665+ ' --metadata-file ' , $metadataFile
657666 ' --label' , ' org.opencontainers.image.description=Firebird Database (snapshot)'
658667 ' --label' , " org.opencontainers.image.version=$snapshotTag "
659668 ' --progress=plain'
660669 $snapshotFolder
661670 )
662- Write-Build Cyan " ----- [snapshot / $Branch / $defaultDistro / $hostArch ] -----"
671+ Write-Build Cyan " ----- [snapshot / $Branch / $defaultDistro / $hostArch → push-by-digest ] -----"
663672 exec { & docker $buildArgs * > & 1 }
664673
665- Write-Build Green " Snapshot image built: $imagePrefix /${imageName} :$snapshotTag (also tagged $snapshotTagWithDistro )"
674+ $metadata = Get-Content $metadataFile - Raw | ConvertFrom-Json
675+ $digest = $metadata .' containerimage.digest'
676+
677+ # Save digest for later manifest assembly
678+ $digestFile = Join-Path $outputFolder " digests-snapshot-$hostArch .json"
679+ New-Item - ItemType Directory (Split-Path $digestFile ) - Force > $null
680+ @ { $snapshotTag = $digest } | ConvertTo-Json | Out-File $digestFile - Encoding UTF8
681+
682+ Write-Build Green " Snapshot $snapshotTag pushed by digest: $digest "
683+ Write-Build Green " Digest saved to $digestFile "
684+ }
685+
686+ # Synopsis: Assemble a multi-arch (or single-arch) manifest for a snapshot branch
687+ # using digests previously written by Build-Snapshot. Reads
688+ # generated/digests-snapshot-amd64.json (required) and
689+ # generated/digests-snapshot-arm64.json (optional).
690+ task Publish-Snapshot - Manifests LoadAssets, {
691+ $imagePrefix = $script :imagePrefix
692+ $imageName = ' firebird'
693+ $meta = Get-SnapshotMeta $Branch
694+ $snapshotTag = $meta.SnapshotTag
695+ $defaultDistro = $meta.DefaultDistro
696+ $snapshotTagWithDistro = " $snapshotTag -$defaultDistro "
697+
698+ $amd64File = Join-Path $outputFolder ' digests-snapshot-amd64.json'
699+ $arm64File = Join-Path $outputFolder ' digests-snapshot-arm64.json'
700+
701+ if (-not (Test-Path $amd64File )) {
702+ throw " Required digest file not found: $amd64File . Run Build-Snapshot on amd64 first."
703+ }
704+ $amd64Digest = (Get-Content $amd64File - Raw | ConvertFrom-Json ).$snapshotTag
705+ if (-not $amd64Digest ) {
706+ throw " No digest for '$snapshotTag ' in $amd64File ."
707+ }
708+
709+ $sources = @ (" $imagePrefix /${imageName} @$amd64Digest " )
710+ if (Test-Path $arm64File ) {
711+ $arm64Digest = (Get-Content $arm64File - Raw | ConvertFrom-Json ).$snapshotTag
712+ if ($arm64Digest ) {
713+ $sources += " $imagePrefix /${imageName} @$arm64Digest "
714+ }
715+ }
716+
717+ foreach ($tag in @ ($snapshotTag , $snapshotTagWithDistro )) {
718+ Write-Build Cyan " $tag → manifest ($ ( $sources.Count ) arch)"
719+ $tagArgs = @ (' buildx' , ' imagetools' , ' create' , ' --tag' , " $imagePrefix /${imageName} :$tag " ) + $sources
720+ exec { & docker $tagArgs * > & 1 }
721+ }
722+
723+ Write-Build Green " Snapshot manifests published: $snapshotTag , $snapshotTagWithDistro "
666724}
667725
668726# Synopsis: Default task.
0 commit comments