diff --git a/compose/config/config.py b/compose/config/config.py index 6cfce5da4..97c427b91 100644 --- a/compose/config/config.py +++ b/compose/config/config.py @@ -4,7 +4,6 @@ from __future__ import unicode_literals import functools import logging import ntpath -import operator import os import string import sys @@ -749,13 +748,10 @@ def merge_service_dicts(base, override, version): md.merge_field(field, merge_path_mappings) for field in [ - 'depends_on', - 'expose', - 'external_links', - 'ports', - 'volumes_from', + 'ports', 'cap_add', 'cap_drop', 'expose', 'external_links', + 'security_opt', 'volumes_from', 'depends_on', ]: - md.merge_field(field, operator.add, default=[]) + md.merge_field(field, merge_unique_items_lists, default=[]) for field in ['dns', 'dns_search', 'env_file', 'tmpfs']: md.merge_field(field, merge_list_or_string) @@ -771,6 +767,10 @@ def merge_service_dicts(base, override, version): return dict(md) +def merge_unique_items_lists(base, override): + return sorted(set().union(base, override)) + + def merge_build(output, base, override): def to_dict(service): build_config = service.get('build', {}) diff --git a/tests/integration/project_test.py b/tests/integration/project_test.py index 7ef492a56..6e82e931f 100644 --- a/tests/integration/project_test.py +++ b/tests/integration/project_test.py @@ -834,6 +834,42 @@ class ProjectTest(DockerClientTestCase): self.assertTrue(log_config) self.assertEqual(log_config.get('Type'), 'none') + @v2_only() + def test_project_up_port_mappings_with_multiple_files(self): + base_file = config.ConfigFile( + 'base.yml', + { + 'version': V2_0, + 'services': { + 'simple': { + 'image': 'busybox:latest', + 'command': 'top', + 'ports': ['1234:1234'] + }, + }, + + }) + override_file = config.ConfigFile( + 'override.yml', + { + 'version': V2_0, + 'services': { + 'simple': { + 'ports': ['1234:1234'] + } + } + + }) + details = config.ConfigDetails('.', [base_file, override_file]) + + config_data = config.load(details) + project = Project.from_config( + name='composetest', config_data=config_data, client=self.client + ) + project.up() + containers = project.containers() + self.assertEqual(len(containers), 1) + @v2_only() def test_initialize_volumes(self): vol_name = '{0:x}'.format(random.getrandbits(32)) diff --git a/tests/unit/config/config_test.py b/tests/unit/config/config_test.py index ccb3bcfe1..24ece4994 100644 --- a/tests/unit/config/config_test.py +++ b/tests/unit/config/config_test.py @@ -1912,6 +1912,14 @@ class MergePortsTest(unittest.TestCase, MergeListsTest): base_config = ['10:8000', '9000'] override_config = ['20:8000'] + def test_duplicate_port_mappings(self): + service_dict = config.merge_service_dicts( + {self.config_name: self.base_config}, + {self.config_name: self.base_config}, + DEFAULT_VERSION + ) + assert set(service_dict[self.config_name]) == set(self.base_config) + class MergeNetworksTest(unittest.TestCase, MergeListsTest): config_name = 'networks'