Repository: compose-spec/compose-go
Pull request #508 (2023-12-13 15:07:05)

restore support for extends short syntax
According to https://github.com/compose-spec/compose-spec/blob/master/05-services.md#extends `extends` should be a mapping, but the json schema indeed allows use of a single string. So we need to fix the docs, but let's also fixes the code!

closes https://github.com/docker/compose/issues/11267


Patch:
diff --git a/loader/extends.go b/loader/extends.go
index 6fa611a..4bfd2d6 100644
--- a/loader/extends.go
+++ b/loader/extends.go
@@ -41,10 +41,20 @@ func ApplyExtends(ctx context.Context, dict map[string]any, workingdir string, o
 		if err := ct.Add(ctx.Value(consts.ComposeFileKey{}).(string), name); err != nil {
 			return err
 		}
-		extends := x.(map[string]any)
+		var (
+			ref  string
+			file any
+		)
+		switch v := x.(type) {
+		case map[string]any:
+			ref = v["service"].(string)
+			file = v["file"]
+		case string:
+			ref = v
+		}
+
 		var base any
-		ref := extends["service"].(string)
-		if file, ok := extends["file"]; ok {
+		if file != nil {
 			path := file.(string)
 			for _, loader := range opts.ResourceLoaders {
 				if !loader.Accept(path) {
diff --git a/transform/canonical.go b/transform/canonical.go
index c873039..6569f43 100644
--- a/transform/canonical.go
+++ b/transform/canonical.go
@@ -28,6 +28,7 @@ func init() {
 	transformers["services.*"] = transformService
 	transformers["services.*.build.secrets.*"] = transformFileMount
 	transformers["services.*.depends_on"] = transformDependsOn
+	transformers["services.*.extends"] = transformExtends
 	transformers["services.*.networks"] = transformServiceNetworks
 	transformers["services.*.volumes.*"] = transformVolumeMount
 	transformers["services.*.secrets.*"] = transformFileMount
diff --git a/transform/extends.go b/transform/extends.go
new file mode 100644
index 0000000..6c65f7b
--- /dev/null
+++ b/transform/extends.go
@@ -0,0 +1,35 @@
+/*
+   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 transform
+
+import (
+	"github.com/compose-spec/compose-go/v2/tree"
+	"github.com/pkg/errors"
+)
+
+func transformExtends(data any, p tree.Path) (any, error) {
+	switch v := data.(type) {
+	case map[string]any:
+		return transformMapping(v, p)
+	case string:
+		return map[string]any{
+			"service": v,
+		}, nil
+	default:
+		return data, errors.Errorf("invalid type %T for extends", v)
+	}
+}


Test patch:
diff --git a/loader/loader_test.go b/loader/loader_test.go
index 2712aef..0ab4f6c 100644
--- a/loader/loader_test.go
+++ b/loader/loader_test.go
@@ -325,8 +325,7 @@ name: load-extends
 services:
   foo:
     image: busybox
-    extends:
-      service: bar
+    extends: bar
   bar:
     image: alpine
     command: echo`)