Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cli/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ func ProjectFromOptions(ctx context.Context, options *ProjectOptions) (*types.Pr
options.loadOptions = append(options.loadOptions,
withNamePrecedenceLoad(workingDir, options),
withConvertWindowsPaths(options),
withListener(options))
withListeners(options))

project, err := loader.LoadWithContext(ctx, types.ConfigDetails{
ConfigFiles: configs,
Expand Down Expand Up @@ -484,9 +484,9 @@ func withConvertWindowsPaths(options *ProjectOptions) func(*loader.Options) {
}

// save listeners from ProjectOptions (compose) to loader.Options
func withListener(options *ProjectOptions) func(*loader.Options) {
func withListeners(options *ProjectOptions) func(*loader.Options) {
return func(opts *loader.Options) {
opts.Listeners = options.Listeners
opts.Listeners = append(opts.Listeners, options.Listeners...)
}
}

Expand Down
59 changes: 59 additions & 0 deletions loader/environment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
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 (
"fmt"

"github.com/compose-spec/compose-go/v2/types"
)

// Will update the environment variables for the format {- VAR} (without interpolation)
// This function should resolve context environment vars for include (passed in env_file)
func resolveServicesEnvironment(dict map[string]any, config types.ConfigDetails) {
services, ok := dict["services"].(map[string]any)
if !ok {
return
}

for service, cfg := range services {
serviceConfig, ok := cfg.(map[string]any)
if !ok {
continue
}
serviceEnv, ok := serviceConfig["environment"].([]any)
if !ok {
continue
}
envs := []any{}
for _, env := range serviceEnv {
varEnv, ok := env.(string)
if !ok {
continue
}
if found, ok := config.Environment[varEnv]; ok {
envs = append(envs, fmt.Sprintf("%s=%s", varEnv, found))
} else {
// either does not exist or it was already resolved in interpolation
envs = append(envs, varEnv)
}
}
serviceConfig["environment"] = envs
services[service] = serviceConfig
}
dict["services"] = services
}
16 changes: 16 additions & 0 deletions loader/include.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,22 @@ func ApplyInclude(ctx context.Context, configDetails types.ConfigDetails, model
if s, err := os.Stat(f); err == nil && !s.IsDir() {
r.EnvFile = types.StringList{f}
}
} else {
envFile := []string{}
for _, f := range r.EnvFile {
if !filepath.IsAbs(f) {
f = filepath.Join(configDetails.WorkingDir, f)
s, err := os.Stat(f)
if err != nil {
return err
}
if s.IsDir() {
return fmt.Errorf("%s is not a file", f)
}
}
envFile = append(envFile, f)
}
r.EnvFile = envFile
}

envFromFile, err := dotenv.GetEnvFromFile(configDetails.Environment, r.EnvFile)
Expand Down
71 changes: 70 additions & 1 deletion loader/include_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package loader

import (
"context"
"os"
"path/filepath"
"testing"

Expand Down Expand Up @@ -50,7 +51,7 @@ services:
assert.Equal(t, imported.ContainerName, "override")

// include 2 different services with same name should trigger an error
p, err = Load(buildConfigDetails(`
_, err = Load(buildConfigDetails(`
name: 'test-multi-include'

include:
Expand Down Expand Up @@ -89,3 +90,71 @@ func TestIncludeRelative(t *testing.T) {
assert.Equal(t, included.Build.Context, ".")
assert.Equal(t, included.Volumes[0].Source, ".")
}

func TestLoadWithIncludeEnv(t *testing.T) {
fileName := "compose.yml"
tmpdir := t.TempDir()
// file in root
yaml := `
include:
- path:
- ./module/compose.yml
env_file:
- ./custom.env
services:
a:
image: alpine
environment:
- VAR_NAME`
createFile(t, tmpdir, `VAR_NAME=value`, "custom.env")
path := createFile(t, tmpdir, yaml, fileName)
// file in /module
yaml = `
services:
b:
image: alpine
environment:
- VAR_NAME
c:
image: alpine
environment:
- VAR_NAME`
createFileSubDir(t, tmpdir, "module", yaml, fileName)

p, err := Load(types.ConfigDetails{
WorkingDir: tmpdir,
ConfigFiles: []types.ConfigFile{{
Filename: path,
}},
Environment: nil,
}, func(options *Options) {
options.SkipNormalization = true
options.ResolvePaths = true
options.SetProjectName("project", true)
})
assert.NilError(t, err)
a := p.Services["a"]
// make sure VAR_NAME is only accessible in include context
assert.Check(t, a.Environment["VAR_NAME"] == nil, "VAR_NAME should not be defined in environment")
b := p.Services["b"]
assert.Check(t, b.Environment["VAR_NAME"] != nil, "VAR_NAME is not defined in environment")
assert.Equal(t, *b.Environment["VAR_NAME"], "value")
c := p.Services["c"]
assert.Check(t, c.Environment["VAR_NAME"] != nil, "VAR_NAME is not defined in environment")
assert.Equal(t, *c.Environment["VAR_NAME"], "value")

}

func createFile(t *testing.T, rootDir, content, fileName string) string {
path := filepath.Join(rootDir, fileName)
assert.NilError(t, os.WriteFile(path, []byte(content), 0o600))
return path
}

func createFileSubDir(t *testing.T, rootDir, subDir, content, fileName string) string {
subDirPath := filepath.Join(rootDir, subDir)
assert.NilError(t, os.Mkdir(subDirPath, 0o700))
path := filepath.Join(subDirPath, fileName)
assert.NilError(t, os.WriteFile(path, []byte(content), 0o600))
return path
}
1 change: 1 addition & 0 deletions loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@ func loadYamlModel(ctx context.Context, config types.ConfigDetails, opts *Option
return nil, err
}
}
resolveServicesEnvironment(dict, config)

return dict, nil
}
Expand Down