Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

local environment to override included .env #449

Merged
merged 1 commit into from Aug 25, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 2 additions & 6 deletions cli/options.go
Expand Up @@ -66,7 +66,7 @@ type ProjectOptions struct {
// NOTE: For security, the loader does not automatically expose any
// process environment variables. For convenience, WithOsEnv can be
// used if appropriate.
Environment map[string]string
Environment types.Mapping

// EnvFiles are file paths to ".env" files with additional environment
// variable data.
Expand Down Expand Up @@ -256,11 +256,7 @@ func WithDotEnv(o *ProjectOptions) error {
if err != nil {
return err
}
for k, v := range envMap {
if _, set := o.Environment[k]; !set {
o.Environment[k] = v
}
}
o.Environment.Merge(envMap)
return nil
}

Expand Down
7 changes: 4 additions & 3 deletions cli/options_test.go
Expand Up @@ -22,6 +22,7 @@ import (
"path/filepath"
"testing"

"github.com/compose-spec/compose-go/types"
"gotest.tools/v3/assert"

"github.com/compose-spec/compose-go/consts"
Expand Down Expand Up @@ -314,13 +315,13 @@ func TestEnvVariablePrecedence(t *testing.T) {
name string
dotEnv string
osEnv []string
expected map[string]string
expected types.Mapping
}{
{
"no value set in environment",
"FOO=foo\nBAR=${FOO}",
nil,
map[string]string{
types.Mapping{
"FOO": "foo",
"BAR": "foo",
},
Expand All @@ -329,7 +330,7 @@ func TestEnvVariablePrecedence(t *testing.T) {
"conflict with value set in environment",
"FOO=foo\nBAR=${FOO}",
[]string{"FOO=zot"},
map[string]string{
types.Mapping{
"FOO": "zot",
"BAR": "zot",
},
Expand Down
4 changes: 2 additions & 2 deletions loader/include.go
Expand Up @@ -73,15 +73,15 @@ func loadInclude(ctx context.Context, filename string, configDetails types.Confi
loadOptions.SkipNormalization = true
loadOptions.SkipConsistencyCheck = true

env, err := dotenv.GetEnvFromFile(configDetails.Environment, r.ProjectDirectory, r.EnvFile)
envFromFile, err := dotenv.GetEnvFromFile(configDetails.Environment, r.ProjectDirectory, r.EnvFile)
if err != nil {
return nil, nil, err
}

config := types.ConfigDetails{
WorkingDir: r.ProjectDirectory,
ConfigFiles: types.ToConfigFiles(r.Path),
Environment: env,
Environment: configDetails.Environment.Clone().Merge(envFromFile),
}
loadOptions.Interpolate = &interp.Options{
Substitute: options.Interpolate.Substitute,
Expand Down
19 changes: 19 additions & 0 deletions loader/loader_test.go
Expand Up @@ -2555,6 +2555,25 @@ services:
},
})
assert.NilError(t, err)

p, err = Load(buildConfigDetails(`
name: 'test-include'

include:
- path: ./testdata/subdir/compose-test-extends-imported.yaml
env_file: ./testdata/subdir/extra.env

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)
assert.Equal(t, p.Services[1].ContainerName, "override")
}

func TestLoadWithIncludeCycle(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion types/config.go
Expand Up @@ -34,7 +34,7 @@ type ConfigDetails struct {
Version string
WorkingDir string
ConfigFiles []ConfigFile
Environment map[string]string
Environment Mapping
}

// LookupEnv provides a lookup function for environment variables
Expand Down
18 changes: 18 additions & 0 deletions types/types.go
Expand Up @@ -516,6 +516,24 @@ func (m Mapping) Resolve(s string) (string, bool) {
return v, ok
}

func (m Mapping) Clone() Mapping {
clone := Mapping{}
for k, v := range m {
clone[k] = v
}
return clone
}

// Merge adds all values from second mapping which are not already defined
func (m Mapping) Merge(o Mapping) Mapping {
for k, v := range o {
if _, set := m[k]; !set {
m[k] = v
}
}
return m
}

// Labels is a mapping type for labels
type Labels map[string]string

Expand Down