Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion python_on_whales/components/buildx/imagetools/cli_wrapper.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import json
from pathlib import Path
from typing import List, Optional, Union
from typing import Dict, List, Optional, Union

from python_on_whales.client_config import DockerCLICaller
from python_on_whales.utils import run
Expand All @@ -20,6 +20,7 @@ def create(
sources: List[str] = [],
tags: List[str] = [],
append: bool = False,
annotations: Dict[str, str] = {},
files: List[Union[str, Path]] = [],
dry_run: bool = False,
builder: Optional[str] = None,
Expand All @@ -36,6 +37,7 @@ def create(
Parameters:
sources: The sources manifest to create, change
append: Append to existing manifest
annotations: Add annotations to the image as a dict of key-value pairs
dry_run: Show final image instead of pushing
files: Read source descriptor from file
builder: The builder to use.
Expand All @@ -52,10 +54,16 @@ def create(
raise TypeError(
"The argument 'files' of the function docker.buildx.imagetools.create() must be a list of strings."
)
if not isinstance(annotations, dict):
raise TypeError(
"The argument 'annotations' of the function docker.buildx.imagetools.create() must be a dict."
)

full_cmd = self.docker_cmd + ["buildx", "imagetools", "create"]
for tag in tags:
full_cmd.add_simple_arg("--tag", tag)
for key, value in annotations.items():
full_cmd.add_simple_arg("--annotation", f"{key}={value}")
for file in files:
full_cmd.add_simple_arg("--file", file)
full_cmd.add_simple_arg("--builder", builder)
Expand Down
1 change: 1 addition & 0 deletions python_on_whales/components/buildx/imagetools/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ class Manifest(pydantic.BaseModel):
layers: Optional[List[ManifestLayer]] = None
manifests: Optional[List[ImageVariantManifest]] = None
config: Optional[ManifestConfig] = None
annotations: Optional[dict] = None
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import pytest

from python_on_whales import docker
from python_on_whales.utils import PROJECT_ROOT

Expand Down Expand Up @@ -68,3 +70,32 @@ def test_imagetools_append(docker_registry):
docker.buildx.imagetools.create([base_image_busybox], tags=[new_image])
docker.buildx.imagetools.create([base_image_alpine], tags=[new_image], append=True)
docker.pull(new_image)


def test_imagetools_create_annotations_type_validation():
with pytest.raises(TypeError) as err:
docker.buildx.imagetools.create(
["python:3.13.0"], annotations="not-a-dict", dry_run=True
)
assert "must be a dict" in str(err.value)


def test_imagetools_create_with_annotations_command_construction():
annotations = {
"index:org.opencontainers.image.source": "https://github.com/user/repo",
"index:org.opencontainers.image.description": "Test image",
}

manifest = docker.buildx.imagetools.create(
sources=["python:3.13.0"],
tags=["myrepo/myimage:latest"],
annotations=annotations,
dry_run=True,
)

assert len(manifest.annotations) == 2
assert (
manifest.annotations["org.opencontainers.image.source"]
== "https://github.com/user/repo"
)
assert manifest.annotations["org.opencontainers.image.description"] == "Test image"