diff --git a/loader/include.go b/loader/include.go index cc50734d..21d5871f 100644 --- a/loader/include.go +++ b/loader/include.go @@ -71,7 +71,7 @@ func ApplyInclude(ctx context.Context, configDetails types.ConfigDetails, model break } } - r.Path[i] = absPath(configDetails.WorkingDir, p) + r.Path[i] = p } mainFile := r.Path[0] @@ -85,13 +85,18 @@ func ApplyInclude(ctx context.Context, configDetails types.ConfigDetails, model if r.ProjectDirectory == "" { r.ProjectDirectory = filepath.Dir(mainFile) } + relworkingdir, err := filepath.Rel(configDetails.WorkingDir, r.ProjectDirectory) + if err != nil { + // included file path is not inside project working directory => use absolute path + relworkingdir = r.ProjectDirectory + } loadOptions := options.clone() loadOptions.ResolvePaths = true loadOptions.SkipNormalization = true loadOptions.SkipConsistencyCheck = true loadOptions.ResourceLoaders = append(loadOptions.RemoteResourceLoaders(), localResourceLoader{ - WorkingDir: r.ProjectDirectory, + WorkingDir: relworkingdir, }) if len(r.EnvFile) == 0 { @@ -107,7 +112,7 @@ func ApplyInclude(ctx context.Context, configDetails types.ConfigDetails, model } config := types.ConfigDetails{ - WorkingDir: r.ProjectDirectory, + WorkingDir: relworkingdir, ConfigFiles: types.ToConfigFiles(r.Path), Environment: configDetails.Environment.Clone().Merge(envFromFile), } diff --git a/loader/include_test.go b/loader/include_test.go new file mode 100644 index 00000000..c0d17ff5 --- /dev/null +++ b/loader/include_test.go @@ -0,0 +1,91 @@ +/* + Copyright 2020 The Compose Specification Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package loader + +import ( + "context" + "path/filepath" + "testing" + + "github.com/compose-spec/compose-go/v2/types" + "gotest.tools/v3/assert" +) + +func TestLoadWithMultipleInclude(t *testing.T) { + // include same service twice should not trigger an error + p, err := Load(buildConfigDetails(` +name: 'test-multi-include' + +include: + - path: ./testdata/subdir/compose-test-extends-imported.yaml + env_file: ./testdata/subdir/extra.env + - path: ./testdata/compose-include.yaml + +services: + foo: + image: busybox + depends_on: + - imported +`, map[string]string{"SOURCE": "override"}), func(options *Options) { + options.SkipNormalization = true + options.ResolvePaths = true + }) + assert.NilError(t, err) + imported, err := p.GetService("imported") + assert.NilError(t, err) + assert.Equal(t, imported.ContainerName, "override") + + // include 2 different services with same name should trigger an error + p, err = Load(buildConfigDetails(` +name: 'test-multi-include' + +include: + - path: ./testdata/subdir/compose-test-extends-imported.yaml + env_file: ./testdata/subdir/extra.env + - path: ./testdata/compose-include.yaml + env_file: ./testdata/subdir/extra.env + + +services: + bar: + image: busybox +`, map[string]string{"SOURCE": "override"}), func(options *Options) { + options.SkipNormalization = true + options.ResolvePaths = true + }) + assert.ErrorContains(t, err, "services.bar conflicts with imported resource", err) +} + +func TestIncludeRelative(t *testing.T) { + wd, err := filepath.Abs(filepath.Join("testdata", "include")) + assert.NilError(t, err) + p, err := LoadWithContext(context.Background(), types.ConfigDetails{ + ConfigFiles: []types.ConfigFile{ + { + Filename: filepath.Join("testdata", "include", "compose.yaml"), + }, + }, + WorkingDir: wd, + }, func(options *Options) { + options.projectName = "test-include-relative" + options.ResolvePaths = false + }) + assert.NilError(t, err) + included := p.Services["included"] + assert.Equal(t, included.Build.Context, ".") + assert.Equal(t, included.Volumes[0].Source, ".") +} diff --git a/loader/loader_test.go b/loader/loader_test.go index 41cb7a88..c01d7bb3 100644 --- a/loader/loader_test.go +++ b/loader/loader_test.go @@ -2611,51 +2611,6 @@ func TestLoadDependsOnCycle(t *testing.T) { assert.Error(t, err, "dependency cycle detected: service2 -> service3 -> service1", err) } -func TestLoadWithMultipleInclude(t *testing.T) { - // include same service twice should not trigger an error - p, err := Load(buildConfigDetails(` -name: 'test-multi-include' - -include: - - path: ./testdata/subdir/compose-test-extends-imported.yaml - env_file: ./testdata/subdir/extra.env - - path: ./testdata/compose-include.yaml - -services: - foo: - image: busybox - depends_on: - - imported -`, map[string]string{"SOURCE": "override"}), func(options *Options) { - options.SkipNormalization = true - options.ResolvePaths = true - }) - assert.NilError(t, err) - imported, err := p.GetService("imported") - assert.NilError(t, err) - assert.Equal(t, imported.ContainerName, "override") - - // include 2 different services with same name should trigger an error - p, err = Load(buildConfigDetails(` -name: 'test-multi-include' - -include: - - path: ./testdata/subdir/compose-test-extends-imported.yaml - env_file: ./testdata/subdir/extra.env - - path: ./testdata/compose-include.yaml - env_file: ./testdata/subdir/extra.env - - -services: - bar: - image: busybox -`, map[string]string{"SOURCE": "override"}), func(options *Options) { - options.SkipNormalization = true - options.ResolvePaths = true - }) - assert.ErrorContains(t, err, "services.bar conflicts with imported resource", err) -} - func TestLoadWithDependsOn(t *testing.T) { p, err := loadYAML(` name: test-depends-on diff --git a/loader/testdata/include/compose.yaml b/loader/testdata/include/compose.yaml new file mode 100644 index 00000000..bb8ad4d9 --- /dev/null +++ b/loader/testdata/include/compose.yaml @@ -0,0 +1,2 @@ +include: + - path: included.yaml diff --git a/loader/testdata/include/included.yaml b/loader/testdata/include/included.yaml new file mode 100644 index 00000000..9713a915 --- /dev/null +++ b/loader/testdata/include/included.yaml @@ -0,0 +1,5 @@ +services: + included: + build: . + volumes: + - ./:/mnt