diff --git a/compose/project.py b/compose/project.py index 92c352050..8fab09e54 100644 --- a/compose/project.py +++ b/compose/project.py @@ -29,6 +29,7 @@ from .service import ContainerNetworkMode from .service import ContainerPidMode from .service import ConvergenceStrategy from .service import NetworkMode +from .service import parse_repository_tag from .service import PidMode from .service import Service from .service import ServiceNetworkMode @@ -592,8 +593,15 @@ class Project(object): service.pull(ignore_pull_failures, silent=silent) def push(self, service_names=None, ignore_push_failures=False): + unique_images = set() for service in self.get_services(service_names, include_deps=False): - service.push(ignore_push_failures) + # Considering and as the same + repo, tag, sep = parse_repository_tag(service.image_name) + service_image_name = sep.join((repo, tag)) if tag else sep.join((repo, 'latest')) + + if service_image_name not in unique_images: + service.push(ignore_push_failures) + unique_images.add(service_image_name) def _labeled_containers(self, stopped=False, one_off=OneOffFilter.exclude): ctnrs = list(filter(None, [ diff --git a/tests/integration/project_test.py b/tests/integration/project_test.py index 57f3b7074..203b7bb3d 100644 --- a/tests/integration/project_test.py +++ b/tests/integration/project_test.py @@ -1995,3 +1995,21 @@ class ProjectTest(DockerClientTestCase): net_data = self.client.inspect_network(full_net_name) assert net_data assert net_data['Labels'][LABEL_PROJECT] == '-dashtest' + + def test_avoid_multiple_push(self): + service_config_latest = {'image': 'busybox:latest', 'build': '.'} + service_config_default = {'image': 'busybox', 'build': '.'} + service_config_sha = { + 'image': 'busybox@sha256:38a203e1986cf79639cfb9b2e1d6e773de84002feea2d4eb006b52004ee8502d', + 'build': '.' + } + svc1 = self.create_service('busy1', **service_config_latest) + svc1_1 = self.create_service('busy11', **service_config_latest) + svc2 = self.create_service('busy2', **service_config_default) + svc2_1 = self.create_service('busy21', **service_config_default) + svc3 = self.create_service('busy3', **service_config_sha) + svc3_1 = self.create_service('busy31', **service_config_sha) + project = Project('composetest', [svc1, svc1_1, svc2, svc2_1, svc3, svc3_1], self.client) + with mock.patch('compose.service.Service.push') as fake_push: + project.push(ignore_push_failures=True) + assert fake_push.call_count == 2