Skip to content

Commit 276bdda

Browse files
committed
fix(docker): use --push to preserve manifest metadata
- Changed build() to support push parameter for direct registry push - Updated build_and_push() to use docker buildx build --push - Applies all tags in single buildx command to preserve manifest - Fixes architecture validation failure in CI (issue #170) When using --load + docker push, manifest metadata (architecture/os) is lost. Using --push directly preserves the proper manifest structure with architecture information that the validation step requires. This ensures docker buildx imagetools inspect can read the architecture from the pushed image manifest.
1 parent df7972f commit 276bdda

File tree

1 file changed

+41
-16
lines changed

1 file changed

+41
-16
lines changed

docker/scripts/docker.py

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -177,13 +177,22 @@ def generate_tags(
177177

178178
return tags
179179

180-
def build(self, tag: str, platform: Optional[str] = None, version: Optional[str] = None) -> bool:
180+
def build(
181+
self,
182+
tag: str,
183+
platform: Optional[str] = None,
184+
version: Optional[str] = None,
185+
push: bool = False,
186+
additional_tags: Optional[list[str]] = None,
187+
) -> bool:
181188
"""Build Docker image with the specified tag.
182189
183190
Args:
184191
tag: Image tag to build
185192
platform: Target platform (defaults to detected platform)
186193
version: Version to pass as build arg (will be set as BUILD_VERSION env var in container)
194+
push: If True, push directly to registry (preserves manifest metadata)
195+
additional_tags: Additional tags to apply during build (only used with push=True)
187196
"""
188197
# Use detected platform if not specified
189198
build_platform = platform or self.platform
@@ -205,6 +214,8 @@ def build(self, tag: str, platform: Optional[str] = None, version: Optional[str]
205214
print(f"INFO: Target platform: {build_platform}", file=sys.stderr)
206215
if version:
207216
print(f"INFO: Build version: {version}", file=sys.stderr)
217+
if push:
218+
print(f"INFO: Build mode: push directly to registry (preserves manifest)", file=sys.stderr)
208219

209220
os.chdir(self.project_root)
210221

@@ -215,13 +226,28 @@ def build(self, tag: str, platform: Optional[str] = None, version: Optional[str]
215226
if version:
216227
build_cmd.extend(["--build-arg", f"VERSION={version}"])
217228

218-
# Use --load to load the image into Docker (instead of just building to cache)
219-
build_cmd.extend(["--load", "--tag", tag, "."])
229+
# Add primary tag
230+
build_cmd.extend(["--tag", tag])
231+
232+
# Add additional tags if provided (only relevant for push mode)
233+
if additional_tags:
234+
for additional_tag in additional_tags:
235+
build_cmd.extend(["--tag", additional_tag])
236+
237+
# Use --push for registry builds (preserves manifest metadata)
238+
# Use --load for local builds (loads into local Docker daemon)
239+
if push:
240+
build_cmd.extend(["--push", "."])
241+
else:
242+
build_cmd.extend(["--load", "."])
220243

221244
result = self._run_command(build_cmd, check=False)
222245

223246
if result.returncode == 0:
224247
print(f"INFO: Successfully built: {tag}", file=sys.stderr)
248+
if additional_tags:
249+
for additional_tag in additional_tags:
250+
print(f"INFO: Successfully tagged: {additional_tag}", file=sys.stderr)
225251
return True
226252
else:
227253
print(f"ERROR: Failed to build image", file=sys.stderr)
@@ -269,6 +295,10 @@ def build_and_push(self, version: str, include_latest: bool = True, arch_specifi
269295
270296
Supports architecture-specific builds. Builds for the current platform by default.
271297
Use arch_specific=True to include architecture suffix in tags (e.g., v1.0.0-arm64).
298+
299+
Uses docker buildx build --push to build and push in a single step, which preserves
300+
the proper manifest with architecture metadata. This is required for the validation
301+
step to detect the image architecture.
272302
"""
273303
if not self._check_docker():
274304
return False
@@ -289,23 +319,18 @@ def build_and_push(self, version: str, include_latest: bool = True, arch_specifi
289319
print(f"INFO: Generated {len(tags)} image tags:", file=sys.stderr)
290320
for ref in tags:
291321
print(f"INFO: - {ref.uri}", file=sys.stderr)
322+
print("", file=sys.stderr)
292323

293-
# Build with first tag, passing version as build arg
324+
# Build and push with all tags in a single buildx command
325+
# This preserves the proper manifest with architecture metadata
294326
primary_tag = tags[0].uri
295-
if not self.build(primary_tag, version=version):
296-
return False
297-
298-
# Tag with additional tags
299-
for ref in tags[1:]:
300-
if not self.tag(primary_tag, ref.uri):
301-
return False
327+
additional_tags = [ref.uri for ref in tags[1:]]
302328

303-
# Push all tags
304-
for ref in tags:
305-
if not self.push(ref.uri):
306-
return False
329+
if not self.build(primary_tag, version=version, push=True, additional_tags=additional_tags):
330+
return False
307331

308-
print(f"INFO: Docker push completed successfully", file=sys.stderr)
332+
print("", file=sys.stderr)
333+
print(f"INFO: Docker build and push completed successfully", file=sys.stderr)
309334
print(f"INFO: Pushed {len(tags)} tags to registry: {self.registry}", file=sys.stderr)
310335

311336
# Output the primary image URI for capture by CI

0 commit comments

Comments
 (0)