From c7ffbf97c8827025a5d7567cf076a83894eb256a Mon Sep 17 00:00:00 2001
From: Karol Duleba <mr.fuxi@gmail.com>
Date: Thu, 24 Sep 2015 22:49:38 +0100
Subject: [PATCH] Extend oneOf error handling. Issue #1989

Signed-off-by: Karol Duleba <mr.fuxi@gmail.com>
---
 compose/config/validation.py     | 18 +++++++++++++++++-
 tests/unit/config/config_test.py | 12 +++++++++---
 2 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/compose/config/validation.py b/compose/config/validation.py
index 959465e98..33b660268 100644
--- a/compose/config/validation.py
+++ b/compose/config/validation.py
@@ -4,6 +4,7 @@ import os
 import sys
 from functools import wraps
 
+import six
 from docker.utils.ports import split_port
 from jsonschema import Draft4Validator
 from jsonschema import FormatChecker
@@ -162,10 +163,25 @@ def process_errors(errors, service_name=None):
         Inspecting the context value of a ValidationError gives us information about
         which sub schema failed and which kind of error it is.
         """
+
+        required = [context for context in error.context if context.validator == 'required']
+        if required:
+            return required[0].message
+
+        additionalProperties = [context for context in error.context if context.validator == 'additionalProperties']
+        if additionalProperties:
+            invalid_config_key = _parse_key_from_error_msg(additionalProperties[0])
+            return "contains unsupported option: '{}'".format(invalid_config_key)
+
         constraint = [context for context in error.context if len(context.path) > 0]
         if constraint:
             valid_types = _parse_valid_types_from_validator(constraint[0].validator_value)
-            msg = "contains {}, which is an invalid type, it should be {}".format(
+            invalid_config_key = "".join(
+                "'{}' ".format(fragment) for fragment in constraint[0].path
+                if isinstance(fragment, six.string_types)
+            )
+            msg = "{}contains {}, which is an invalid type, it should be {}".format(
+                invalid_config_key,
                 constraint[0].instance,
                 valid_types
             )
diff --git a/tests/unit/config/config_test.py b/tests/unit/config/config_test.py
index 2c3c5a3a1..7b31038f5 100644
--- a/tests/unit/config/config_test.py
+++ b/tests/unit/config/config_test.py
@@ -335,7 +335,7 @@ class ConfigTest(unittest.TestCase):
         self.assertTrue(expected_warning_msg in mock_logging.warn.call_args[0][0])
 
     def test_config_invalid_environment_dict_key_raises_validation_error(self):
-        expected_error_msg = "Service 'web' configuration key 'environment' contains an invalid type"
+        expected_error_msg = "Service 'web' configuration key 'environment' contains unsupported option: '---'"
 
         with self.assertRaisesRegexp(ConfigurationError, expected_error_msg):
             config.load(
@@ -957,7 +957,10 @@ class ExtendsTest(unittest.TestCase):
             )
 
     def test_extends_validation_invalid_key(self):
-        expected_error_msg = "Unsupported config option for 'web' service: 'rogue_key'"
+        expected_error_msg = (
+            "Service 'web' configuration key 'extends' "
+            "contains unsupported option: 'rogue_key'"
+        )
         with self.assertRaisesRegexp(ConfigurationError, expected_error_msg):
             config.load(
                 build_config_details(
@@ -977,7 +980,10 @@ class ExtendsTest(unittest.TestCase):
             )
 
     def test_extends_validation_sub_property_key(self):
-        expected_error_msg = "Service 'web' configuration key 'extends' 'file' contains an invalid type"
+        expected_error_msg = (
+            "Service 'web' configuration key 'extends' 'file' contains 1, "
+            "which is an invalid type, it should be a string"
+        )
         with self.assertRaisesRegexp(ConfigurationError, expected_error_msg):
             config.load(
                 build_config_details(