Repository: compose-spec/compose-go
Pull request #540 (2024-01-22 10:27:33)

fix build.args merge issue when defined with a list
Closes https://github.com/docker/compose/issues/11389


Patch:
diff --git a/override/merge.go b/override/merge.go
index d8e91d3..6cbfdc5 100644
--- a/override/merge.go
+++ b/override/merge.go
@@ -39,6 +39,7 @@ type merger func(any, any, tree.Path) (any, error)
 var mergeSpecials = map[tree.Path]merger{}
 
 func init() {
+	mergeSpecials["services.*.build.args"] = mergeToSequence
 	mergeSpecials["services.*.build"] = mergeBuild
 	mergeSpecials["services.*.depends_on"] = mergeDependsOn
 	mergeSpecials["services.*.logging"] = mergeLogging
@@ -46,7 +47,7 @@ func init() {
 	mergeSpecials["services.*.command"] = override
 	mergeSpecials["services.*.entrypoint"] = override
 	mergeSpecials["services.*.healthcheck.test"] = override
-	mergeSpecials["services.*.environment"] = mergeEnvironment
+	mergeSpecials["services.*.environment"] = mergeToSequence
 	mergeSpecials["services.*.ulimits.*"] = mergeUlimit
 }
 
@@ -142,8 +143,7 @@ func mergeNetworks(c any, o any, path tree.Path) (any, error) {
 	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) {
+func mergeToSequence(c any, o any, _ tree.Path) (any, error) {
 	right := convertIntoSequence(c)
 	left := convertIntoSequence(o)
 	return append(right, left...), nil
diff --git a/override/uncity.go b/override/uncity.go
index d549843..432bb9c 100644
--- a/override/uncity.go
+++ b/override/uncity.go
@@ -31,7 +31,8 @@ type indexer func(any, tree.Path) (string, error)
 var unique = map[tree.Path]indexer{}
 
 func init() {
-	unique["services.*.environment"] = environmentIndexer
+	unique["services.*.environment"] = keyValueIndexer
+	unique["services.*.build.args"] = keyValueIndexer
 	unique["services.*.volumes"] = volumeIndexer
 	unique["services.*.expose"] = exposeIndexer
 	unique["services.*.secrets"] = mountIndexer("/run/secrets")
@@ -83,7 +84,7 @@ func enforceUnicity(value any, p tree.Path) (any, error) {
 	return value, nil
 }
 
-func environmentIndexer(y any, _ tree.Path) (string, error) {
+func keyValueIndexer(y any, _ tree.Path) (string, error) {
 	value := y.(string)
 	key, _, found := strings.Cut(value, "=")
 	if !found {


Test patch:
diff --git a/override/merge_args_test.go b/override/merge_args_test.go
new file mode 100644
index 0000000..fde07dc
--- /dev/null
+++ b/override/merge_args_test.go
@@ -0,0 +1,131 @@
+/*
+   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 override
+
+import (
+	"testing"
+)
+
+func Test_mergeYamlArgsSequence(t *testing.T) {
+	assertMergeYaml(t, `
+services:
+  test:
+    build:
+      context: .
+      args:
+        - FOO=BAR
+`, `
+services:
+  test:
+    build:
+      context: .
+      args:
+        - GIT_COMMIT=cdc3b19
+        - EMPTY=
+        - NIL
+`, `
+services:
+  test:
+    build:
+      context: .
+      args:
+        - FOO=BAR
+        - GIT_COMMIT=cdc3b19
+        - EMPTY=
+        - NIL
+`)
+}
+
+func Test_mergeYamlArgsMapping(t *testing.T) {
+	assertMergeYaml(t, `
+services:
+  test:
+    build:
+      context: .
+      args:
+        FOO: BAR
+`, `
+services:
+  test:
+    build:
+      context: .
+      args:
+        EMPTY: ""
+        NIL: null
+        QIX: ZOT
+`, `
+services:
+  test:
+    build:
+      context: .
+      args:
+       - FOO=BAR
+       - EMPTY=
+       - NIL
+       - QIX=ZOT
+`)
+}
+
+func Test_mergeYamlArgsMixed(t *testing.T) {
+	assertMergeYaml(t, `
+services:
+  test:
+    build:
+      context: .
+      args:
+        FOO: BAR
+`, `
+services:
+  test:
+    build:
+      args:
+        - QIX=ZOT
+`, `
+services:
+  test:
+    build:
+      context: .
+      args:
+        - FOO=BAR
+        - QIX=ZOT
+`)
+}
+
+func Test_mergeYamlArgsNumber(t *testing.T) {
+	assertMergeYaml(t, `
+services:
+  test:
+    build:
+      context: .
+      args:
+        FOO: 1
+`, `
+services:
+  test:
+    build:
+      context: .
+      args:
+        FOO: 3
+`, `
+services:
+  test:
+    build:
+      context: .
+      args:
+       - FOO=3
+`)
+}