diff --git a/compose/config/config.py b/compose/config/config.py index 94c5ab95a..55c717f42 100644 --- a/compose/config/config.py +++ b/compose/config/config.py @@ -275,15 +275,19 @@ class ServiceLoader(object): self.service_dict['environment'] = env def validate_and_construct_extends(self): + extends = self.service_dict['extends'] + if not isinstance(extends, dict): + extends = {'service': extends} + validate_extends_file_path( self.service_name, - self.service_dict['extends'], + extends, self.filename ) self.extended_config_path = self.get_extended_config_path( - self.service_dict['extends'] + extends ) - self.extended_service_name = self.service_dict['extends']['service'] + self.extended_service_name = extends['service'] full_extended_config = pre_process_config( load_yaml(self.extended_config_path) diff --git a/compose/config/fields_schema.json b/compose/config/fields_schema.json index 6fce299cb..07b17cb22 100644 --- a/compose/config/fields_schema.json +++ b/compose/config/fields_schema.json @@ -57,14 +57,21 @@ }, "extends": { - "type": "object", + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", - "properties": { - "service": {"type": "string"}, - "file": {"type": "string"} - }, - "required": ["service"], - "additionalProperties": false + "properties": { + "service": {"type": "string"}, + "file": {"type": "string"} + }, + "required": ["service"], + "additionalProperties": false + } + ] }, "extra_hosts": {"$ref": "#/definitions/list_or_dict"}, diff --git a/tests/fixtures/extends/verbose-and-shorthand.yml b/tests/fixtures/extends/verbose-and-shorthand.yml new file mode 100644 index 000000000..d38163027 --- /dev/null +++ b/tests/fixtures/extends/verbose-and-shorthand.yml @@ -0,0 +1,15 @@ +base: + image: busybox + environment: + - "BAR=1" + +verbose: + extends: + service: base + environment: + - "FOO=1" + +shorthand: + extends: base + environment: + - "FOO=2" diff --git a/tests/unit/config/config_test.py b/tests/unit/config/config_test.py index 2dfa764df..2c3c5a3a1 100644 --- a/tests/unit/config/config_test.py +++ b/tests/unit/config/config_test.py @@ -1115,6 +1115,26 @@ class ExtendsTest(unittest.TestCase): dicts = load_from_filename('tests/fixtures/extends/valid-common-config.yml') self.assertEqual(dicts[0]['environment'], {'FOO': '1'}) + def test_extended_service_with_verbose_and_shorthand_way(self): + services = load_from_filename('tests/fixtures/extends/verbose-and-shorthand.yml') + self.assertEqual(service_sort(services), service_sort([ + { + 'name': 'base', + 'image': 'busybox', + 'environment': {'BAR': '1'}, + }, + { + 'name': 'verbose', + 'image': 'busybox', + 'environment': {'BAR': '1', 'FOO': '1'}, + }, + { + 'name': 'shorthand', + 'image': 'busybox', + 'environment': {'BAR': '1', 'FOO': '2'}, + }, + ])) + @pytest.mark.xfail(IS_WINDOWS_PLATFORM, reason='paths use slash') class ExpandPathTest(unittest.TestCase):