diff --git a/docker/api/build.py b/docker/api/build.py index 5c34c47b..f30be416 100644 --- a/docker/api/build.py +++ b/docker/api/build.py @@ -18,7 +18,7 @@ class BuildApiMixin(object): custom_context=False, encoding=None, pull=False, forcerm=False, dockerfile=None, container_limits=None, decode=False, buildargs=None, gzip=False, shmsize=None, - labels=None, cache_from=None): + labels=None, cache_from=None, target=None): """ Similar to the ``docker build`` command. Either ``path`` or ``fileobj`` needs to be set. ``path`` can be a local path (to a directory @@ -94,6 +94,8 @@ class BuildApiMixin(object): labels (dict): A dictionary of labels to set on the image. cache_from (list): A list of images used for build cache resolution. + target (str): Name of the build-stage to build in a multi-stage + Dockerfile. Returns: A generator for the build output. @@ -198,6 +200,14 @@ class BuildApiMixin(object): 'cache_from was only introduced in API version 1.25' ) + if target: + if utils.version_gte(self._version, '1.29'): + params.update({'target': target}) + else: + raise errors.InvalidVersion( + 'target was only introduced in API version 1.29' + ) + if context is not None: headers = {'Content-Type': 'application/tar'} if encoding: diff --git a/docker/models/images.py b/docker/models/images.py index 52a44b27..a9ed65ee 100644 --- a/docker/models/images.py +++ b/docker/models/images.py @@ -151,6 +151,8 @@ class ImageCollection(Collection): decoded into dicts on the fly. Default ``False``. cache_from (list): A list of images used for build cache resolution. + target (str): Name of the build-stage to build in a multi-stage + Dockerfile. Returns: (:py:class:`Image`): The built image. diff --git a/tests/integration/api_build_test.py b/tests/integration/api_build_test.py index fe5d994d..623b6609 100644 --- a/tests/integration/api_build_test.py +++ b/tests/integration/api_build_test.py @@ -189,6 +189,28 @@ class BuildTest(BaseAPIIntegrationTest): counter += 1 assert counter == 0 + @requires_api_version('1.29') + def test_build_container_with_target(self): + script = io.BytesIO('\n'.join([ + 'FROM busybox as first', + 'RUN mkdir -p /tmp/test', + 'RUN touch /tmp/silence.tar.gz', + 'FROM alpine:latest', + 'WORKDIR /root/' + 'COPY --from=first /tmp/silence.tar.gz .', + 'ONBUILD RUN echo "This should not be in the final image"' + ]).encode('ascii')) + + stream = self.client.build( + fileobj=script, target='first', tag='build1' + ) + self.tmp_imgs.append('build1') + for chunk in stream: + pass + + info = self.client.inspect_image('build1') + self.assertEqual(info['Config']['OnBuild'], []) + def test_build_stderr_data(self): control_chars = ['\x1b[91m', '\x1b[0m'] snippet = 'Ancient Temple (Mystic Oriental Dream ~ Ancient Temple)'