Skip to content

Commit 6111574

Browse files
committed
Allow importing compose file to override resource definition
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
1 parent 61f9cea commit 6111574

File tree

6 files changed

+50
-26
lines changed

6 files changed

+50
-26
lines changed

loader/include.go

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@ import (
2121
"fmt"
2222
"os"
2323
"path/filepath"
24-
"reflect"
2524
"strings"
2625

2726
"github.com/compose-spec/compose-go/v2/dotenv"
2827
interp "github.com/compose-spec/compose-go/v2/interpolation"
28+
"github.com/compose-spec/compose-go/v2/override"
29+
"github.com/compose-spec/compose-go/v2/tree"
2930
"github.com/compose-spec/compose-go/v2/types"
3031
)
3132

@@ -50,7 +51,7 @@ func loadIncludeConfig(source any) ([]types.IncludeConfig, error) {
5051
return requires, err
5152
}
5253

53-
func ApplyInclude(ctx context.Context, workingDir string, environment types.Mapping, model map[string]any, options *Options, included []string) error {
54+
func ApplyInclude(ctx context.Context, workingDir string, environment types.Mapping, model map[string]any, options *Options, included []string, processor PostProcessor) error {
5455
includeConfig, err := loadIncludeConfig(model["include"])
5556
if err != nil {
5657
return err
@@ -151,7 +152,7 @@ func ApplyInclude(ctx context.Context, workingDir string, environment types.Mapp
151152
if err != nil {
152153
return err
153154
}
154-
err = importResources(imported, model)
155+
err = importResources(imported, model, processor)
155156
if err != nil {
156157
return err
157158
}
@@ -161,29 +162,29 @@ func ApplyInclude(ctx context.Context, workingDir string, environment types.Mapp
161162
}
162163

163164
// importResources import into model all resources defined by imported, and report error on conflict
164-
func importResources(source map[string]any, target map[string]any) error {
165-
if err := importResource(source, target, "services"); err != nil {
165+
func importResources(source map[string]any, target map[string]any, processor PostProcessor) error {
166+
if err := importResource(source, target, "services", processor); err != nil {
166167
return err
167168
}
168-
if err := importResource(source, target, "volumes"); err != nil {
169+
if err := importResource(source, target, "volumes", processor); err != nil {
169170
return err
170171
}
171-
if err := importResource(source, target, "networks"); err != nil {
172+
if err := importResource(source, target, "networks", processor); err != nil {
172173
return err
173174
}
174-
if err := importResource(source, target, "secrets"); err != nil {
175+
if err := importResource(source, target, "secrets", processor); err != nil {
175176
return err
176177
}
177-
if err := importResource(source, target, "configs"); err != nil {
178+
if err := importResource(source, target, "configs", processor); err != nil {
178179
return err
179180
}
180-
if err := importResource(source, target, "models"); err != nil {
181+
if err := importResource(source, target, "models", processor); err != nil {
181182
return err
182183
}
183184
return nil
184185
}
185186

186-
func importResource(source map[string]any, target map[string]any, key string) error {
187+
func importResource(source map[string]any, target map[string]any, key string, processor PostProcessor) error {
187188
from := source[key]
188189
if from != nil {
189190
var to map[string]any
@@ -193,13 +194,25 @@ func importResource(source map[string]any, target map[string]any, key string) er
193194
to = map[string]any{}
194195
}
195196
for name, a := range from.(map[string]any) {
196-
if conflict, ok := to[name]; ok {
197-
if reflect.DeepEqual(a, conflict) {
198-
continue
199-
}
200-
return fmt.Errorf("%s.%s conflicts with imported resource", key, name)
197+
conflict, ok := to[name]
198+
if !ok {
199+
to[name] = a
200+
continue
201+
}
202+
err := processor.Apply(map[string]any{
203+
key: map[string]any{
204+
name: a,
205+
},
206+
})
207+
if err != nil {
208+
return err
209+
}
210+
211+
merged, err := override.MergeYaml(a, conflict, tree.NewPath(key, name))
212+
if err != nil {
213+
return err
201214
}
202-
to[name] = a
215+
to[name] = merged
203216
}
204217
target[key] = to
205218
}

loader/include_test.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,21 @@ include:
8181
services:
8282
bar:
8383
image: busybox
84+
environment: !override
85+
- ZOT=QIX
8486
`, map[string]string{"SOURCE": "override"})
85-
_, err := LoadWithContext(context.TODO(), details, func(options *Options) {
87+
p, err := LoadWithContext(context.TODO(), details, func(options *Options) {
8688
options.SkipNormalization = true
8789
options.ResolvePaths = true
8890
})
89-
assert.ErrorContains(t, err, "services.bar conflicts with imported resource", err)
91+
assert.NilError(t, err)
92+
assert.DeepEqual(t, p.Services["bar"], types.ServiceConfig{
93+
Name: "bar",
94+
Image: "busybox",
95+
Environment: types.MappingWithEquals{
96+
"ZOT": strPtr("QIX"),
97+
},
98+
})
9099
}
91100

92101
func TestIncludeRelative(t *testing.T) {

loader/loader.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ func loadYamlFile(ctx context.Context,
459459

460460
if !opts.SkipInclude {
461461
included = append(included, file.Filename)
462-
err = ApplyInclude(ctx, workingDir, environment, cfg, opts, included)
462+
err = ApplyInclude(ctx, workingDir, environment, cfg, opts, included, processor)
463463
if err != nil {
464464
return err
465465
}

loader/testdata/compose-include.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@ include:
33

44
services:
55
bar:
6-
image: bar
6+
image: bar
7+
environment:
8+
- FOO=BAR

override/extends.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ package override
1919
import "github.com/compose-spec/compose-go/v2/tree"
2020

2121
func ExtendService(base, override map[string]any) (map[string]any, error) {
22-
yaml, err := mergeYaml(base, override, tree.NewPath("services.x"))
22+
yaml, err := MergeYaml(base, override, tree.NewPath("services.x"))
2323
if err != nil {
2424
return nil, err
2525
}

override/merge.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import (
2626

2727
// Merge applies overrides to a config model
2828
func Merge(right, left map[string]any) (map[string]any, error) {
29-
merged, err := mergeYaml(right, left, tree.NewPath())
29+
merged, err := MergeYaml(right, left, tree.NewPath())
3030
if err != nil {
3131
return nil, err
3232
}
@@ -70,8 +70,8 @@ func init() {
7070
mergeSpecials["services.*.ulimits.*"] = mergeUlimit
7171
}
7272

73-
// mergeYaml merges map[string]any yaml trees handling special rules
74-
func mergeYaml(e any, o any, p tree.Path) (any, error) {
73+
// MergeYaml merges map[string]any yaml trees handling special rules
74+
func MergeYaml(e any, o any, p tree.Path) (any, error) {
7575
for pattern, merger := range mergeSpecials {
7676
if p.Matches(pattern) {
7777
merged, err := merger(e, o, p)
@@ -110,7 +110,7 @@ func mergeMappings(mapping map[string]any, other map[string]any, p tree.Path) (m
110110
continue
111111
}
112112
next := p.Next(k)
113-
merged, err := mergeYaml(e, v, next)
113+
merged, err := MergeYaml(e, v, next)
114114
if err != nil {
115115
return nil, err
116116
}

0 commit comments

Comments
 (0)