Skip to content

Commit 3d3411d

Browse files
ndeloofglours
authored andcommitted
Allow importing compose file to override resource definition
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
1 parent dbfe619 commit 3d3411d

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
@@ -154,7 +155,7 @@ func ApplyInclude(ctx context.Context, workingDir string, environment types.Mapp
154155
if err != nil {
155156
return err
156157
}
157-
err = importResources(imported, model)
158+
err = importResources(imported, model, processor)
158159
if err != nil {
159160
return err
160161
}
@@ -164,29 +165,29 @@ func ApplyInclude(ctx context.Context, workingDir string, environment types.Mapp
164165
}
165166

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

189-
func importResource(source map[string]any, target map[string]any, key string) error {
190+
func importResource(source map[string]any, target map[string]any, key string, processor PostProcessor) error {
190191
from := source[key]
191192
if from != nil {
192193
var to map[string]any
@@ -196,13 +197,25 @@ func importResource(source map[string]any, target map[string]any, key string) er
196197
to = map[string]any{}
197198
}
198199
for name, a := range from.(map[string]any) {
199-
if conflict, ok := to[name]; ok {
200-
if reflect.DeepEqual(a, conflict) {
201-
continue
202-
}
203-
return fmt.Errorf("%s.%s conflicts with imported resource", key, name)
200+
conflict, ok := to[name]
201+
if !ok {
202+
to[name] = a
203+
continue
204+
}
205+
err := processor.Apply(map[string]any{
206+
key: map[string]any{
207+
name: a,
208+
},
209+
})
210+
if err != nil {
211+
return err
212+
}
213+
214+
merged, err := override.MergeYaml(a, conflict, tree.NewPath(key, name))
215+
if err != nil {
216+
return err
204217
}
205-
to[name] = a
218+
to[name] = merged
206219
}
207220
target[key] = to
208221
}

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)