Skip to content

Commit f63fde4

Browse files
ndeloofglours
authored andcommitted
fix apply !override while processing extends on services declared in same file
Signed-off-by: Nicolas De Loof <[email protected]>
1 parent 75fb1ab commit f63fde4

File tree

4 files changed

+141
-82
lines changed

4 files changed

+141
-82
lines changed

loader/extends.go

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import (
2727
"github.com/compose-spec/compose-go/v2/types"
2828
)
2929

30-
func ApplyExtends(ctx context.Context, dict map[string]any, opts *Options, tracker *cycleTracker, post ...PostProcessor) error {
30+
func ApplyExtends(ctx context.Context, dict map[string]any, opts *Options, tracker *cycleTracker, post PostProcessor) error {
3131
a, ok := dict["services"]
3232
if !ok {
3333
return nil
@@ -37,7 +37,7 @@ func ApplyExtends(ctx context.Context, dict map[string]any, opts *Options, track
3737
return fmt.Errorf("services must be a mapping")
3838
}
3939
for name := range services {
40-
merged, err := applyServiceExtends(ctx, name, services, opts, tracker, post...)
40+
merged, err := applyServiceExtends(ctx, name, services, opts, tracker, post)
4141
if err != nil {
4242
return err
4343
}
@@ -47,7 +47,7 @@ func ApplyExtends(ctx context.Context, dict map[string]any, opts *Options, track
4747
return nil
4848
}
4949

50-
func applyServiceExtends(ctx context.Context, name string, services map[string]any, opts *Options, tracker *cycleTracker, post ...PostProcessor) (any, error) {
50+
func applyServiceExtends(ctx context.Context, name string, services map[string]any, opts *Options, tracker *cycleTracker, post PostProcessor) (any, error) {
5151
s := services[name]
5252
if s == nil {
5353
return nil, nil
@@ -81,7 +81,7 @@ func applyServiceExtends(ctx context.Context, name string, services map[string]a
8181

8282
var (
8383
base any
84-
processor PostProcessor = NoopPostProcessor{}
84+
processor = post
8585
)
8686

8787
if file != nil {
@@ -114,16 +114,15 @@ func applyServiceExtends(ctx context.Context, name string, services map[string]a
114114
}
115115
source := deepClone(base).(map[string]any)
116116

117-
for _, processor := range post {
118-
err = processor.Apply(map[string]any{
119-
"services": map[string]any{
120-
name: source,
121-
},
122-
})
123-
if err != nil {
124-
return nil, err
125-
}
117+
err = post.Apply(map[string]any{
118+
"services": map[string]any{
119+
name: source,
120+
},
121+
})
122+
if err != nil {
123+
return nil, err
126124
}
125+
127126
merged, err := override.ExtendService(source, service)
128127
if err != nil {
129128
return nil, err

loader/loader.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ func loadYamlFile(ctx context.Context,
427427
file.Content = content
428428
}
429429

430-
processRawYaml := func(raw interface{}, processors ...PostProcessor) error {
430+
processRawYaml := func(raw interface{}, processor PostProcessor) error {
431431
converted, err := convertToStringKeysRecursive(raw, "")
432432
if err != nil {
433433
return err
@@ -447,16 +447,14 @@ func loadYamlFile(ctx context.Context,
447447
fixEmptyNotNull(cfg)
448448

449449
if !opts.SkipExtends {
450-
err = ApplyExtends(ctx, cfg, opts, ct, processors...)
450+
err = ApplyExtends(ctx, cfg, opts, ct, processor)
451451
if err != nil {
452452
return err
453453
}
454454
}
455455

456-
for _, processor := range processors {
457-
if err := processor.Apply(dict); err != nil {
458-
return err
459-
}
456+
if err := processor.Apply(dict); err != nil {
457+
return err
460458
}
461459

462460
if !opts.SkipInclude {
@@ -519,7 +517,7 @@ func loadYamlFile(ctx context.Context,
519517
}
520518
}
521519
} else {
522-
if err := processRawYaml(file.Config); err != nil {
520+
if err := processRawYaml(file.Config, NoopPostProcessor{}); err != nil {
523521
return nil, nil, err
524522
}
525523
}

loader/loader_test.go

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3917,65 +3917,3 @@ services:
39173917
assert.Equal(t, build.Provenance, "mode=max")
39183918
assert.Equal(t, build.SBOM, "true")
39193919
}
3920-
3921-
func TestOverrideMiddle(t *testing.T) {
3922-
pwd := t.TempDir()
3923-
base := filepath.Join(pwd, "base.yaml")
3924-
err := os.WriteFile(base, []byte(`
3925-
services:
3926-
base:
3927-
volumes:
3928-
- /foo:/foo
3929-
`), 0o700)
3930-
assert.NilError(t, err)
3931-
3932-
override := filepath.Join(pwd, "override.yaml")
3933-
err = os.WriteFile(override, []byte(`
3934-
services:
3935-
override:
3936-
extends:
3937-
file: ./base.yaml
3938-
service: base
3939-
volumes: !override
3940-
- /bar:/bar
3941-
`), 0o700)
3942-
assert.NilError(t, err)
3943-
3944-
compose := filepath.Join(pwd, "compose.yaml")
3945-
err = os.WriteFile(compose, []byte(`
3946-
name: test
3947-
services:
3948-
test:
3949-
image: test
3950-
extends:
3951-
file: ./override.yaml
3952-
service: override
3953-
volumes:
3954-
- /zot:/zot
3955-
`), 0o700)
3956-
assert.NilError(t, err)
3957-
3958-
project, err := LoadWithContext(context.TODO(), types.ConfigDetails{
3959-
WorkingDir: pwd,
3960-
ConfigFiles: []types.ConfigFile{
3961-
{Filename: compose},
3962-
},
3963-
})
3964-
assert.NilError(t, err)
3965-
test := project.Services["test"]
3966-
assert.Equal(t, len(test.Volumes), 2)
3967-
assert.DeepEqual(t, test.Volumes, []types.ServiceVolumeConfig{
3968-
{
3969-
Type: "bind",
3970-
Source: "/bar",
3971-
Target: "/bar",
3972-
Bind: &types.ServiceVolumeBind{CreateHostPath: true},
3973-
},
3974-
{
3975-
Type: "bind",
3976-
Source: "/zot",
3977-
Target: "/zot",
3978-
Bind: &types.ServiceVolumeBind{CreateHostPath: true},
3979-
},
3980-
})
3981-
}

loader/override_test.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ package loader
1818

1919
import (
2020
"context"
21+
"os"
22+
"path/filepath"
2123
"testing"
2224

2325
"github.com/compose-spec/compose-go/v2/types"
@@ -197,3 +199,125 @@ services:
197199
assert.NilError(t, err)
198200
assert.Equal(t, len(p.Services["test"].Volumes), 1)
199201
}
202+
203+
// see https://github.com/docker/compose/issues/13298
204+
func TestOverrideMiddle(t *testing.T) {
205+
pwd := t.TempDir()
206+
base := filepath.Join(pwd, "base.yaml")
207+
err := os.WriteFile(base, []byte(`
208+
services:
209+
base:
210+
volumes:
211+
- /foo:/foo
212+
networks:
213+
- foo
214+
`), 0o700)
215+
assert.NilError(t, err)
216+
217+
override := filepath.Join(pwd, "override.yaml")
218+
err = os.WriteFile(override, []byte(`
219+
services:
220+
override:
221+
extends:
222+
file: ./base.yaml
223+
service: base
224+
volumes: !override
225+
- /bar:/bar
226+
networks: !override
227+
- bar
228+
`), 0o700)
229+
assert.NilError(t, err)
230+
231+
compose := filepath.Join(pwd, "compose.yaml")
232+
err = os.WriteFile(compose, []byte(`
233+
name: test
234+
services:
235+
test:
236+
image: test
237+
extends:
238+
file: ./override.yaml
239+
service: override
240+
volumes:
241+
- /zot:/zot
242+
networks: !override
243+
- zot
244+
245+
networks:
246+
zot: {}
247+
`), 0o700)
248+
assert.NilError(t, err)
249+
250+
project, err := LoadWithContext(context.TODO(), types.ConfigDetails{
251+
WorkingDir: pwd,
252+
ConfigFiles: []types.ConfigFile{
253+
{Filename: compose},
254+
},
255+
})
256+
assert.NilError(t, err)
257+
test := project.Services["test"]
258+
assert.Equal(t, len(test.Volumes), 2)
259+
assert.DeepEqual(t, test.Volumes, []types.ServiceVolumeConfig{
260+
{
261+
Type: "bind",
262+
Source: "/bar",
263+
Target: "/bar",
264+
Bind: &types.ServiceVolumeBind{CreateHostPath: true},
265+
},
266+
{
267+
Type: "bind",
268+
Source: "/zot",
269+
Target: "/zot",
270+
Bind: &types.ServiceVolumeBind{CreateHostPath: true},
271+
},
272+
})
273+
assert.DeepEqual(t, test.Networks, map[string]*types.ServiceNetworkConfig{
274+
"zot": nil,
275+
})
276+
}
277+
278+
// https://github.com/docker/compose/issues/13346
279+
func TestOverrideSelfExtends(t *testing.T) {
280+
yaml := `
281+
name: test-override-extends
282+
services:
283+
depend_base:
284+
image: nginx
285+
ports:
286+
- "8092:80"
287+
depend_one:
288+
image: nginx
289+
ports:
290+
- "8091:80"
291+
depend_two:
292+
extends:
293+
service: depend_one
294+
main_one:
295+
image: nginx
296+
depends_on:
297+
- depend_one
298+
ports:
299+
- "8090:80"
300+
main_two:
301+
extends: main_one
302+
depends_on: !override
303+
- depend_two
304+
main:
305+
extends:
306+
service: main_two
307+
depends_on:
308+
- depend_base
309+
`
310+
p, err := LoadWithContext(context.Background(), types.ConfigDetails{
311+
ConfigFiles: []types.ConfigFile{
312+
{
313+
Filename: "-",
314+
Content: []byte(yaml),
315+
},
316+
},
317+
})
318+
assert.NilError(t, err)
319+
assert.DeepEqual(t, p.Services["main"].DependsOn, types.DependsOnConfig{
320+
"depend_base": {Condition: "service_started", Required: true},
321+
"depend_two": {Condition: "service_started", Required: true},
322+
})
323+
}

0 commit comments

Comments
 (0)