This commit is contained in:
Khushiyant 2025-06-30 13:26:41 +02:00 committed by GitHub
commit 1a8f65bcdd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 69 additions and 1 deletions

View File

@ -3,6 +3,7 @@ import os
from .. import auth, errors, utils
from ..constants import DEFAULT_DATA_CHUNK_SIZE
from ..types.image import Platform
log = logging.getLogger(__name__)
@ -434,7 +435,7 @@ class ImageApiMixin:
return self._result(response)
def push(self, repository, tag=None, stream=False, auth_config=None,
decode=False):
decode=False, platform=None):
"""
Push an image or a repository to the registry. Similar to the ``docker
push`` command.
@ -448,6 +449,7 @@ class ImageApiMixin:
``username`` and ``password`` keys to be valid.
decode (bool): Decode the JSON data from the server into dicts.
Only applies with ``stream=True``
platform (str): JSON-encoded OCI platform to select the platform-variant to push. If not provided, all available variants will attempt to be pushed.
Returns:
(generator or str): The output from the server.
@ -488,6 +490,13 @@ class ImageApiMixin:
log.debug('Sending supplied auth config')
headers['X-Registry-Auth'] = auth.encode_header(auth_config)
if platform is not None:
if utils.version_lt(self._version, '1.46'):
raise errors.InvalidVersion(
'platform was only introduced in API version 1.46'
)
params['platform'] = Platform
response = self._post_json(
u, None, headers=headers, stream=stream, params=params
)

35
docker/types/image.py Normal file
View File

@ -0,0 +1,35 @@
from .base import DictType
class Platform(DictType):
def __init__(self, **kwargs):
architecture = kwargs.get('architecture', kwargs.get('Architecture'))
os = kwargs.get('os', kwargs.get('OS'))
if architecture is None and os is None:
raise ValueError("At least one of 'architecture' or 'os' must be provided")
super().__init__({
'Architecture': architecture,
'OS': os,
'OSVersion': kwargs.get('os_version', kwargs.get('OSVersion')),
'OSFeatures': kwargs.get('os_features', kwargs.get('OSFeatures')),
'Variant': kwargs.get('variant', kwargs.get('Variant'))
})
@property
def architecture(self):
return self['Architecture']
@property
def os(self):
return self['OS']
@architecture.setter
def architecture(self, value):
self['Architecture'] = value
@os.setter
def os(self, value):
self['OS'] = value

View File

@ -5,6 +5,7 @@ import pytest
import docker
from docker import auth
from ..helpers import requires_api_version
from . import fake_api
from .api_test import (
DEFAULT_TIMEOUT_SECONDS,
@ -271,6 +272,28 @@ class ImageTest(BaseAPIClientTest):
timeout=DEFAULT_TIMEOUT_SECONDS
)
@requires_api_version('1.46')
def test_push_image_with_platform(self):
with mock.patch('docker.auth.resolve_authconfig',
fake_resolve_authconfig):
self.client.push(
fake_api.FAKE_IMAGE_NAME,
platform=fake_api.FAKE_PLATFORM
)
fake_request.assert_called_with(
'POST',
f"{url_prefix}images/test_image/push",
params={
'tag': None,
'platform': fake_api.FAKE_PLATFORM
},
data='{}',
headers={'Content-Type': 'application/json'},
stream=False,
timeout=DEFAULT_TIMEOUT_SECONDS
)
def test_push_image_stream(self):
with mock.patch('docker.auth.resolve_authconfig',
fake_resolve_authconfig):

View File

@ -21,6 +21,7 @@ FAKE_SECRET_ID = 'epdyrw4tsi03xy3deu8g8ly6o'
FAKE_SECRET_NAME = 'super_secret'
FAKE_CONFIG_ID = 'sekvs771242jfdjnvfuds8232'
FAKE_CONFIG_NAME = 'super_config'
FAKE_PLATFORM = "{'os': 'linux','architecture': 'arm','variant': 'v5'}"
# Each method is prefixed with HTTP method (get, post...)
# for clarity and readability