Skip to content

Commit 58f2fbb

Browse files
ndeloofglours
authored andcommitted
Restore ability to override an included resource in compose.override.yaml
Signed-off-by: Nicolas De Loof <[email protected]>
1 parent 3868ec4 commit 58f2fbb

File tree

4 files changed

+69
-31
lines changed

4 files changed

+69
-31
lines changed

loader/include.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ func loadIncludeConfig(source any) ([]types.IncludeConfig, error) {
3434
if source == nil {
3535
return nil, nil
3636
}
37+
configs := source.([]any)
38+
for i, config := range configs {
39+
if v, ok := config.(string); ok {
40+
configs[i] = map[string]any{
41+
"path": v,
42+
}
43+
}
44+
}
3745
var requires []types.IncludeConfig
3846
err := Transform(source, &requires)
3947
return requires, err

loader/loader.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,14 @@ func loadYamlModel(ctx context.Context, config types.ConfigDetails, opts *Option
355355
}
356356
}
357357

358+
if !opts.SkipInclude {
359+
included = append(included, config.ConfigFiles[0].Filename)
360+
err = ApplyInclude(ctx, config, cfg, opts, included)
361+
if err != nil {
362+
return err
363+
}
364+
}
365+
358366
dict, err = override.Merge(dict, cfg)
359367
if err != nil {
360368
return err
@@ -409,14 +417,6 @@ func loadYamlModel(ctx context.Context, config types.ConfigDetails, opts *Option
409417
return nil, err
410418
}
411419

412-
if !opts.SkipInclude {
413-
included = append(included, config.ConfigFiles[0].Filename)
414-
err = ApplyInclude(ctx, config, dict, opts, included)
415-
if err != nil {
416-
return nil, err
417-
}
418-
}
419-
420420
if !opts.SkipValidation {
421421
if err := validation.Validate(dict); err != nil {
422422
return nil, err

loader/loader_test.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2561,7 +2561,6 @@ services:
25612561
}
25622562

25632563
func TestLoadWithIncludeCycle(t *testing.T) {
2564-
25652564
workingDir, err := os.Getwd()
25662565
assert.NilError(t, err)
25672566
_, err = Load(types.ConfigDetails{
@@ -2575,6 +2574,26 @@ func TestLoadWithIncludeCycle(t *testing.T) {
25752574
assert.Check(t, strings.HasPrefix(err.Error(), "include cycle detected"))
25762575
}
25772576

2577+
func TestLoadWithIncludeOverride(t *testing.T) {
2578+
p, err := Load(buildConfigDetailsMultipleFiles(nil, `
2579+
name: 'test-include-override'
2580+
2581+
include:
2582+
- ./testdata/subdir/compose-test-extends-imported.yaml
2583+
`,
2584+
`
2585+
# override
2586+
services:
2587+
imported:
2588+
image: overridden
2589+
`), func(options *Options) {
2590+
options.SkipNormalization = true
2591+
options.ResolvePaths = true
2592+
})
2593+
assert.NilError(t, err)
2594+
assert.Equal(t, p.Services["imported"].Image, "overridden")
2595+
}
2596+
25782597
func TestLoadDependsOnCycle(t *testing.T) {
25792598
workingDir, err := os.Getwd()
25802599
assert.NilError(t, err)

parsing.md

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,18 @@ Extended service yaml definition is cloned into a plain new yaml subtree then
6969
the local service definition is merged as an override. This includes support
7070
for `!reset` to remove an element from original service definition.
7171

72-
# Phase 7: merge overrides
72+
# Phase 7: include resources from another compose model
73+
74+
A compose file can use `include` to rely on compose resources defined by third-parties
75+
as a separate compose file
76+
77+
Included compose definition is fully parsed (as described in this document) then included
78+
to the compose yaml model being processed. Conflicting resources are detected and rejected
79+
80+
The resulting compose model is equivalent to a copy/paste of the included compose model
81+
(fully resolved) into the local compose file.
82+
83+
# Phase 8: merge overrides
7384

7485
If loaded document is an override, the yaml tree is merged with the one from
7586
main compose file. `!reset` can be used to remove elements.
@@ -81,15 +92,31 @@ few exceptions:
8192
- Attributes which can be expressed both as a mapping and a sequence are converted
8293
so that merge can apply on equivalent data structures.
8394

84-
# Phase 8: enforce unicity
95+
# Phase 9: enforce unicity
8596

8697
While modeled as a list, some attributes actually require some unicity to be
8798
applied. Volume mount definition for a service typically must be unique
8899
regarding the target mount path. As such attribute can be defined as a single
89100
string and set by a variable, we have to apply the "_append to list_" merge
90101
strategy then check for unicity.
91102

92-
# Phase 9: transform into canonical representation
103+
# Phase 10: validation
104+
105+
During the loading process, some logical rules are checked. But some involved
106+
relations between exclusive attributes, and must be checked as a dedicated phase.
107+
108+
A typical example is the use of `external` in a resource definition. As such a
109+
resource is not managed by Compose, having some resource creation attributes set
110+
must result into an error being reported to the user
111+
112+
```yaml
113+
networks:
114+
foo:
115+
external: true
116+
driver: macvlan # This will trigger an error, as external network should not have any resource creation parameter set
117+
```
118+
119+
# Phase 11: transform into canonical representation
93120

94121
Compose specification allows many attribute to have both a "short" and a "long"
95122
syntax. It also supports use of single string or list of strings for some
@@ -100,29 +127,13 @@ During loading, all those attributes are transformed into canonical
100127
representation, so that we get a single format that will match to go structs
101128
for binding.
102129

103-
# Phase 10: extensions
130+
# Phase 12: extensions
104131

105132
Extension (`x-*` attributes) can be used in any place in the yaml document.
106133
To make unmarshalling easier, parsing move them all into a custom `#extension`
107134
attribute. This hack is very specific to the go binding.
108135

109-
# Phase 11: validation
110-
111-
During the loading process, some logical rules are checked. But some involved
112-
relations between exclusive attributes, and must be checked as a dedicated phase.
113-
114-
A typical example is the use of `external` in a resource definition. As such a
115-
resource is not managed by Compose, having some resource creation attributes set
116-
must result into an error being reported to the user
117-
118-
```yaml
119-
networks:
120-
foo:
121-
external: true
122-
driver: macvlan # This will trigger an error, as external network should not have any resource creation parameter set
123-
```
124-
125-
# Phase 12: relative paths
136+
# Phase 13: relative paths
126137

127138
Compose allows paths to be set relative to the project directory. Those get resolved
128139
into absolute paths during this phase. This involves a few corner cases, as
@@ -141,7 +152,7 @@ volumes:
141152
device: './data' # such a relative path must be resolved
142153
```
143154

144-
# Phase 13: go binding
155+
# Phase 14: go binding
145156

146157
Eventually, the yaml tree can be unmarshalled into go structs. We rely on
147158
[mapstructure](https://github.com/mitchellh/mapstructure) library for this purpose.

0 commit comments

Comments
 (0)