From af73475892c217e04a5af8a15e7490821c1ce2ca Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Mon, 16 Oct 2023 14:47:21 +0200 Subject: [PATCH] fix TestMergeTopLevelExtensions Signed-off-by: Nicolas De Loof --- consts/consts.go | 2 +- loader/loader.go | 17 +++++---------- loader/merge_test.go | 41 ++++++++++-------------------------- loader/paths_test.go | 49 ++++++++++++++++--------------------------- override/merge.go | 28 +++++++++++-------------- override/uncity.go | 26 ++++++++++++++--------- transform/services.go | 2 +- 7 files changed, 64 insertions(+), 101 deletions(-) diff --git a/consts/consts.go b/consts/consts.go index 7a54d07f..90955e13 100644 --- a/consts/consts.go +++ b/consts/consts.go @@ -23,4 +23,4 @@ const ( ComposeProfiles = "COMPOSE_PROFILES" ) -const Extensions = "#Extensions" // Using # prefix, we prevent risk to conflict with an actual yaml key +const Extensions = "#extensions" // Using # prefix, we prevent risk to conflict with an actual yaml key diff --git a/loader/loader.go b/loader/loader.go index 3db578f4..f0e19d53 100644 --- a/loader/loader.go +++ b/loader/loader.go @@ -394,22 +394,14 @@ func load(ctx context.Context, configDetails types.ConfigDetails, opts *Options, return nil, errors.New("empty compose file") } - var model types.Config - err = Transform(dict, &model) - if err != nil { - return nil, err - } - project := &types.Project{ Name: opts.projectName, WorkingDir: configDetails.WorkingDir, - Services: model.Services, - Networks: model.Networks, - Volumes: model.Volumes, - Secrets: model.Secrets, - Configs: model.Configs, Environment: configDetails.Environment, - Extensions: model.Extensions, + } + err = Transform(dict, project) + if err != nil { + return nil, err } if len(includeRefs) != 0 { @@ -557,6 +549,7 @@ func groupXFieldsIntoExtensions(dict map[string]interface{}) map[string]interfac if strings.HasPrefix(key, "x-") { extras[key] = value delete(dict, key) + continue } switch v := value.(type) { case map[string]interface{}: diff --git a/loader/merge_test.go b/loader/merge_test.go index c3b7cbdc..a4b06385 100644 --- a/loader/merge_test.go +++ b/loader/merge_test.go @@ -524,10 +524,10 @@ func TestLoadMultipleConfigobjsConfig(t *testing.T) { }, expected: []types.ServiceConfigObjConfig{ { - Source: "bar_config", + Source: "foo_config", }, { - Source: "foo_config", + Source: "bar_config", }, }, }, @@ -556,15 +556,15 @@ func TestLoadMultipleConfigobjsConfig(t *testing.T) { }, expected: []types.ServiceConfigObjConfig{ { - Source: "bar_config", - Target: "bof_config", + Source: "foo_config", }, { Source: "baz_config", Target: "waw_config", }, { - Source: "foo_config", + Source: "bar_config", + Target: "bof_config", }, }, }, @@ -605,11 +605,6 @@ func TestLoadMultipleConfigobjsConfig(t *testing.T) { Scale: 1, }, }, - Networks: types.Networks{}, - Volumes: types.Volumes{}, - Secrets: types.Secrets{}, - Configs: types.Configs{}, - Extensions: types.Extensions{}, }, config) }) } @@ -835,11 +830,6 @@ func TestLoadMultipleServiceNetworks(t *testing.T) { Scale: 1, }, }, - Networks: types.Networks{}, - Volumes: types.Volumes{}, - Secrets: types.Secrets{}, - Configs: types.Configs{}, - Extensions: types.Extensions{}, }, config) }) } @@ -1096,22 +1086,13 @@ func TestMergeTopLevelExtensions(t *testing.T) { } config, err := loadTestProject(configDetails) assert.NilError(t, err) - assert.DeepEqual(t, &types.Project{ - Name: "", - WorkingDir: "", - Services: nil, - Networks: types.Networks{}, - Volumes: types.Volumes{}, - Secrets: types.Secrets{}, - Configs: types.Configs{}, - Extensions: types.Extensions{ - "x-foo": "foo", - "x-bar": map[string]interface{}{ - "base": "qix", - }, - "x-zot": "zot", + assert.DeepEqual(t, types.Extensions{ + "x-foo": "foo", + "x-bar": map[string]interface{}{ + "base": "qix", }, - }, config) + "x-zot": "zot", + }, config.Extensions) } func TestMergeCommands(t *testing.T) { diff --git a/loader/paths_test.go b/loader/paths_test.go index 3c437e91..3f7b35ed 100644 --- a/loader/paths_test.go +++ b/loader/paths_test.go @@ -47,39 +47,26 @@ func TestResolveComposeFilePaths(t *testing.T) { } func TestResolveBuildContextPaths(t *testing.T) { - wd, _ := os.Getwd() - project := types.Project{ - Name: "myProject", - WorkingDir: wd, - Services: []types.ServiceConfig{ - { - Name: "foo", - Build: &types.BuildConfig{ - Context: "./testdata", - Dockerfile: "Dockerfile-sample", - }, - Scale: 1, - }, - }, - } - expected := types.Project{ - Name: "myProject", - WorkingDir: wd, - Services: []types.ServiceConfig{ - { - Name: "foo", - Build: &types.BuildConfig{ - Context: filepath.Join(wd, "testdata"), - Dockerfile: "Dockerfile-sample", - }, - Scale: 1, - }, - }, - } - err := ResolveRelativePaths(&project) + yaml := ` +name: test-resolve-build-context-paths +services: + foo: + build: + context: ./testdata + dockerfile: Dockerfile-sample +` + project, err := loadYAML(yaml) assert.NilError(t, err) - assert.DeepEqual(t, expected, project) + + wd, err := os.Getwd() + assert.NilError(t, err) + + expected := types.BuildConfig{ + Context: filepath.Join(wd, "testdata"), + Dockerfile: "Dockerfile-sample", + } + assert.DeepEqual(t, expected, *project.Services[0].Build) } func TestResolveAdditionalContexts(t *testing.T) { diff --git a/override/merge.go b/override/merge.go index 28592f48..bf1d3b66 100644 --- a/override/merge.go +++ b/override/merge.go @@ -18,6 +18,7 @@ package override import ( "fmt" + "strings" "github.com/compose-spec/compose-go/tree" "golang.org/x/exp/slices" @@ -44,6 +45,8 @@ func init() { mergeSpecials["services.*.healthcheck.test"] = override mergeSpecials["services.*.environment"] = mergeEnvironment mergeSpecials["services.*.ulimits.*"] = mergeUlimit + mergeSpecials["services.*.configs.*"] = mergeMount + mergeSpecials["services.*.secrets.*"] = mergeMount } // mergeYaml merges map[string]any yaml trees handling special rules @@ -77,14 +80,12 @@ func mergeYaml(e any, o any, p tree.Path) (any, error) { func mergeMappings(mapping map[string]any, other map[string]any, p tree.Path) (map[string]any, error) { for k, v := range other { - next := p.Next(k) e, ok := mapping[k] - if !ok { - if !isEmpty(v) { - mapping[k] = v - } + if !ok || strings.HasPrefix(k, "x-") { + mapping[k] = v continue } + next := p.Next(k) merged, err := mergeYaml(e, v, next) if err != nil { return nil, err @@ -94,17 +95,6 @@ func mergeMappings(mapping map[string]any, other map[string]any, p tree.Path) (m return mapping, nil } -func isEmpty(value any) bool { - switch v := value.(type) { - case map[string]any: - return len(v) == 0 - case []any: - return len(v) == 0 - default: - return false - } -} - // logging driver options are merged only when both compose file define the same driver func mergeLogging(c any, o any, p tree.Path) (any, error) { config := c.(map[string]any) @@ -133,6 +123,12 @@ func mergeUlimit(c any, o any, p tree.Path) (any, error) { return o, nil } +func mergeMount(c any, o any, path tree.Path) (any, error) { + right := convertIntoSequence(c) + left := convertIntoSequence(o) + return append(right, left...), nil +} + func convertIntoSequence(value any) []any { switch v := value.(type) { case map[string]any: diff --git a/override/uncity.go b/override/uncity.go index 852f0fd2..7cb6cfe2 100644 --- a/override/uncity.go +++ b/override/uncity.go @@ -34,8 +34,8 @@ func init() { unique["services.*.environment"] = environmentIndexer unique["services.*.volumes"] = volumeIndexer unique["services.*.expose"] = exposeIndexer - unique["services.*.secrets"] = mountIndexer - unique["services.*.configs"] = mountIndexer + unique["services.*.secrets"] = mountIndexer("/run/secrets") + unique["services.*.configs"] = mountIndexer("") } // EnforceUnicity removes redefinition of elements declared in a sequence @@ -120,13 +120,19 @@ func exposeIndexer(a any, path tree.Path) (string, error) { } } -func mountIndexer(a any, path tree.Path) (string, error) { - switch v := a.(type) { - case string: - return v, nil - case map[string]any: - return v["source"].(string), nil - default: - return "", fmt.Errorf("%s: unsupported expose value %s", path, a) +func mountIndexer(defaultPath string) indexer { + return func(a any, path tree.Path) (string, error) { + switch v := a.(type) { + case string: + return v, nil + case map[string]any: + t, ok := v["target"] + if ok { + return t.(string), nil + } + return fmt.Sprintf("%s/%s", defaultPath, v["source"]), nil + default: + return "", fmt.Errorf("%s: unsupported expose value %s", path, a) + } } } diff --git a/transform/services.go b/transform/services.go index 84de1956..76a209ce 100644 --- a/transform/services.go +++ b/transform/services.go @@ -37,7 +37,7 @@ func makeServicesSlice(data any, p tree.Path) (any, error) { servicesAsSlice[i] = canonical i++ } - return servicesAsSlice, nil + return servicesAsSlice, nil //TODO(ndeloof) required for loading but not actually canonical. Shall we change compose-go types? } func transformServiceNetworks(data any, p tree.Path) (any, error) {