Repository: compose-spec/compose-go
Pull request #526 (2024-01-15 13:15:44)

fix regression merging overrides
`service.networks` can be defined as a sequence or mapping. Sequence syntax is equivalent to a mapping with value=null. Merge must operate on the mapping representation

includes test case

closes https://github.com/docker/compose/issues/11339


Patch:
diff --git a/override/merge.go b/override/merge.go
index 0628382..c22ca78 100644
--- a/override/merge.go
+++ b/override/merge.go
@@ -40,6 +40,7 @@ var mergeSpecials = map[tree.Path]merger{}
 
 func init() {
 	mergeSpecials["services.*.logging"] = mergeLogging
+	mergeSpecials["services.*.networks"] = mergeNetworks
 	mergeSpecials["services.*.command"] = override
 	mergeSpecials["services.*.entrypoint"] = override
 	mergeSpecials["services.*.healthcheck.test"] = override
@@ -106,6 +107,12 @@ func mergeLogging(c any, o any, p tree.Path) (any, error) {
 	return other, nil
 }
 
+func mergeNetworks(c any, o any, path tree.Path) (any, error) {
+	right := convertIntoMapping(c)
+	left := convertIntoMapping(o)
+	return mergeMappings(right, left, path)
+}
+
 // environment must be first converted into yaml sequence syntax so we can append
 func mergeEnvironment(c any, o any, _ tree.Path) (any, error) {
 	right := convertIntoSequence(c)
@@ -144,6 +151,20 @@ func mergeUlimit(_ any, o any, p tree.Path) (any, error) {
 	return o, nil
 }
 
+func convertIntoMapping(a any) map[string]any {
+	switch v := a.(type) {
+	case map[string]any:
+		return v
+	case []any:
+		converted := map[string]any{}
+		for _, s := range v {
+			converted[s.(string)] = nil
+		}
+		return converted
+	}
+	return nil
+}
+
 func override(_ any, other any, _ tree.Path) (any, error) {
 	return other, nil
 }


Test patch:
diff --git a/loader/override_test.go b/loader/override_test.go
new file mode 100644
index 0000000..1433cc2
--- /dev/null
+++ b/loader/override_test.go
@@ -0,0 +1,63 @@
+/*
+   Copyright 2020 The Compose Specification Authors.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package loader
+
+import (
+	"context"
+	"testing"
+
+	"github.com/compose-spec/compose-go/v2/types"
+	"gotest.tools/v3/assert"
+)
+
+func TestOverrideNetworks(t *testing.T) {
+	yaml := `
+name: test-override-networks
+services:
+  test:
+    image: test
+    networks:
+      - test_network
+
+networks:
+  test_network: {}
+`
+
+	override := `
+services:
+  test:
+    image: test
+    networks:
+      test_network: 
+        aliases:
+          - alias1
+          - alias2
+`
+	_, err := LoadWithContext(context.Background(), types.ConfigDetails{
+		ConfigFiles: []types.ConfigFile{
+			{
+				Filename: "base",
+				Content:  []byte(yaml),
+			},
+			{
+				Filename: "override",
+				Content:  []byte(override),
+			},
+		},
+	})
+	assert.NilError(t, err)
+}