From abce83ef25528fb36979208888ba0033c89f47a3 Mon Sep 17 00:00:00 2001
From: Joffrey F <joffrey@docker.com>
Date: Mon, 13 Feb 2017 16:04:06 -0800
Subject: [PATCH] Fix `config` command output with service.secrets section

Signed-off-by: Joffrey F <joffrey@docker.com>
---
 compose/config/serialize.py      |  3 ++
 compose/config/types.py          |  7 ++--
 tests/unit/config/config_test.py | 57 ++++++++++++++++++++++++++++++++
 3 files changed, 62 insertions(+), 5 deletions(-)

diff --git a/compose/config/serialize.py b/compose/config/serialize.py
index 3745de82d..46d283f08 100644
--- a/compose/config/serialize.py
+++ b/compose/config/serialize.py
@@ -102,4 +102,7 @@ def denormalize_service_dict(service_dict, version):
                 service_dict['healthcheck']['timeout']
             )
 
+    if 'secrets' in service_dict:
+        service_dict['secrets'] = map(lambda s: s.repr(), service_dict['secrets'])
+
     return service_dict
diff --git a/compose/config/types.py b/compose/config/types.py
index f86c03199..811e6c1fc 100644
--- a/compose/config/types.py
+++ b/compose/config/types.py
@@ -256,8 +256,5 @@ class ServiceSecret(namedtuple('_ServiceSecret', 'source target uid gid mode')):
 
     def repr(self):
         return dict(
-            source=self.source,
-            target=self.target,
-            uid=self.uid,
-            gid=self.gid,
-            mode=self.mode)
+            [(k, v) for k, v in self._asdict().items() if v is not None]
+        )
diff --git a/tests/unit/config/config_test.py b/tests/unit/config/config_test.py
index d4d1ad2c4..c26272d9e 100644
--- a/tests/unit/config/config_test.py
+++ b/tests/unit/config/config_test.py
@@ -54,6 +54,10 @@ def service_sort(services):
     return sorted(services, key=itemgetter('name'))
 
 
+def secret_sort(secrets):
+    return sorted(secrets, key=itemgetter('source'))
+
+
 class ConfigTest(unittest.TestCase):
     def test_load(self):
         service_dicts = config.load(
@@ -1771,6 +1775,38 @@ class ConfigTest(unittest.TestCase):
             'labels': {'com.docker.compose.test': 'yes'}
         }
 
+    def test_merge_different_secrets(self):
+        base = {
+            'image': 'busybox',
+            'secrets': [
+                {'source': 'src.txt'}
+            ]
+        }
+        override = {'secrets': ['other-src.txt']}
+
+        actual = config.merge_service_dicts(base, override, V3_1)
+        assert secret_sort(actual['secrets']) == secret_sort([
+            {'source': 'src.txt'},
+            {'source': 'other-src.txt'}
+        ])
+
+    def test_merge_secrets_override(self):
+        base = {
+            'image': 'busybox',
+            'secrets': ['src.txt'],
+        }
+        override = {
+            'secrets': [
+                {
+                    'source': 'src.txt',
+                    'target': 'data.txt',
+                    'mode': 0o400
+                }
+            ]
+        }
+        actual = config.merge_service_dicts(base, override, V3_1)
+        assert actual['secrets'] == override['secrets']
+
     def test_external_volume_config(self):
         config_details = build_config_details({
             'version': '2',
@@ -3491,3 +3527,24 @@ class SerializeTest(unittest.TestCase):
         denormalized_service = denormalize_service_dict(processed_service, V2_1)
         assert denormalized_service['healthcheck']['interval'] == '100s'
         assert denormalized_service['healthcheck']['timeout'] == '30s'
+
+    def test_denormalize_secrets(self):
+        service_dict = {
+            'name': 'web',
+            'image': 'example/web',
+            'secrets': [
+                types.ServiceSecret('one', None, None, None, None),
+                types.ServiceSecret('source', 'target', '100', '200', 0o777),
+            ],
+        }
+        denormalized_service = denormalize_service_dict(service_dict, V3_1)
+        assert secret_sort(denormalized_service['secrets']) == secret_sort([
+            {'source': 'one'},
+            {
+                'source': 'source',
+                'target': 'target',
+                'uid': '100',
+                'gid': '200',
+                'mode': 0o777,
+            },
+        ])