mirror of
https://github.com/docker/compose.git
synced 2025-07-22 13:14:29 +02:00
allow a local .env file to override compose.yaml sibling .env
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
da8189cf22
commit
9e8c8caa2b
@ -171,7 +171,7 @@ func (o *ProjectOptions) addProjectFlags(f *pflag.FlagSet) {
|
||||
f.StringArrayVar(&o.Profiles, "profile", []string{}, "Specify a profile to enable")
|
||||
f.StringVarP(&o.ProjectName, "project-name", "p", "", "Project name")
|
||||
f.StringArrayVarP(&o.ConfigPaths, "file", "f", []string{}, "Compose configuration files")
|
||||
f.StringArrayVar(&o.EnvFiles, "env-file", nil, "Specify an alternate environment file")
|
||||
f.StringArrayVar(&o.EnvFiles, "env-file", defaultStringArrayVar(ComposeEnvFiles), "Specify an alternate environment file")
|
||||
f.StringVar(&o.ProjectDir, "project-directory", "", "Specify an alternate working directory\n(default: the path of the, first specified, Compose file)")
|
||||
f.StringVar(&o.WorkDir, "workdir", "", "DEPRECATED! USE --project-directory INSTEAD.\nSpecify an alternate working directory\n(default: the path of the, first specified, Compose file)")
|
||||
f.BoolVar(&o.Compatibility, "compatibility", false, "Run compose in backward compatibility mode")
|
||||
@ -180,6 +180,13 @@ func (o *ProjectOptions) addProjectFlags(f *pflag.FlagSet) {
|
||||
_ = f.MarkHidden("workdir")
|
||||
}
|
||||
|
||||
// get default value for a command line flag that is set by a coma-separated value in environment variable
|
||||
func defaultStringArrayVar(env string) []string {
|
||||
return strings.FieldsFunc(os.Getenv(env), func(c rune) bool {
|
||||
return c == ','
|
||||
})
|
||||
}
|
||||
|
||||
func (o *ProjectOptions) projectOrName(ctx context.Context, dockerCli command.Cli, services ...string) (*types.Project, string, error) {
|
||||
name := o.ProjectName
|
||||
var project *types.Project
|
||||
@ -384,7 +391,7 @@ func RootCommand(dockerCli command.Cli, backend Backend) *cobra.Command { //noli
|
||||
ctx := cmd.Context()
|
||||
|
||||
// (1) process env vars
|
||||
err := setEnvWithDotEnv(&opts)
|
||||
err := setEnvWithLocalDotEnv(&opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -594,18 +601,29 @@ func RootCommand(dockerCli command.Cli, backend Backend) *cobra.Command { //noli
|
||||
return c
|
||||
}
|
||||
|
||||
func setEnvWithDotEnv(prjOpts *ProjectOptions) error {
|
||||
if len(prjOpts.EnvFiles) == 0 {
|
||||
if envFiles := os.Getenv(ComposeEnvFiles); envFiles != "" {
|
||||
prjOpts.EnvFiles = strings.Split(envFiles, ",")
|
||||
}
|
||||
// If user has a local .env file, load it as os.environment so it can be used to set COMPOSE_ variables
|
||||
// This also allows to override values set by the default .env in a compose project when ran from a distinct folder
|
||||
func setEnvWithLocalDotEnv(prjOpts *ProjectOptions) error {
|
||||
if len(prjOpts.EnvFiles) > 0 {
|
||||
return nil
|
||||
}
|
||||
options, err := prjOpts.toProjectOptions()
|
||||
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return compose.WrapComposeError(err)
|
||||
}
|
||||
|
||||
envFromFile, err := dotenv.GetEnvFromFile(composegoutils.GetAsEqualsMap(os.Environ()), options.EnvFiles)
|
||||
defaultDotEnv := filepath.Join(wd, ".env")
|
||||
|
||||
s, err := os.Stat(defaultDotEnv)
|
||||
if os.IsNotExist(err) || s.IsDir() {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
envFromFile, err := dotenv.GetEnvFromFile(composegoutils.GetAsEqualsMap(os.Environ()), []string{defaultDotEnv})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -117,7 +117,8 @@ func TestEnvPriority(t *testing.T) {
|
||||
"run", "--rm", "-e", "WHEREAMI", "env-compose-priority")
|
||||
cmd.Env = append(cmd.Env, "COMPOSE_ENV_FILES=./fixtures/environment/env-priority/.env.override.with.default")
|
||||
res := icmd.RunCmd(cmd)
|
||||
assert.Equal(t, strings.TrimSpace(res.Stdout()), "EnvFileDefaultValue")
|
||||
stdout := res.Stdout()
|
||||
assert.Equal(t, strings.TrimSpace(stdout), "EnvFileDefaultValue")
|
||||
})
|
||||
|
||||
// No Compose file and env variable pass to the run command
|
||||
|
@ -329,3 +329,24 @@ func TestResolveDotEnv(t *testing.T) {
|
||||
Out: "image: backend:latest",
|
||||
})
|
||||
}
|
||||
|
||||
func TestNestedDotEnv(t *testing.T) {
|
||||
c := NewCLI(t)
|
||||
|
||||
cmd := c.NewDockerComposeCmd(t, "run", "echo")
|
||||
cmd.Dir = filepath.Join(".", "fixtures", "nested")
|
||||
res := icmd.RunCmd(cmd)
|
||||
res.Assert(t, icmd.Expected{
|
||||
ExitCode: 0,
|
||||
Out: "root win=root",
|
||||
})
|
||||
|
||||
cmd = c.NewDockerComposeCmd(t, "run", "echo")
|
||||
cmd.Dir = filepath.Join(".", "fixtures", "nested", "sub")
|
||||
res = icmd.RunCmd(cmd)
|
||||
res.Assert(t, icmd.Expected{
|
||||
ExitCode: 0,
|
||||
Out: "root sub win=sub",
|
||||
})
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
services:
|
||||
env-compose-priority:
|
||||
image: env-compose-priority
|
||||
build:
|
||||
context: .
|
||||
|
2
pkg/e2e/fixtures/nested/.env
Normal file
2
pkg/e2e/fixtures/nested/.env
Normal file
@ -0,0 +1,2 @@
|
||||
ROOT=root
|
||||
WIN=root
|
4
pkg/e2e/fixtures/nested/compose.yaml
Normal file
4
pkg/e2e/fixtures/nested/compose.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
services:
|
||||
echo:
|
||||
image: alpine
|
||||
command: echo $ROOT $SUB win=$WIN
|
2
pkg/e2e/fixtures/nested/sub/.env
Normal file
2
pkg/e2e/fixtures/nested/sub/.env
Normal file
@ -0,0 +1,2 @@
|
||||
SUB=sub
|
||||
WIN=sub
|
Loading…
x
Reference in New Issue
Block a user