diff --git a/cmd/compose/run.go b/cmd/compose/run.go index 259905f196a..ff2657f79b5 100644 --- a/cmd/compose/run.go +++ b/cmd/compose/run.go @@ -36,27 +36,28 @@ import ( type runOptions struct { *composeOptions - Service string - Command []string - environment []string - Detach bool - Remove bool - noTty bool - tty bool - interactive bool - user string - workdir string - entrypoint string - entrypointCmd []string - labels []string - volumes []string - publish []string - useAliases bool - servicePorts bool - name string - noDeps bool - ignoreOrphans bool - quietPull bool + Service string + Command []string + environment []string + Detach bool + Remove bool + noTty bool + tty bool + interactive bool + user string + workdir string + entrypoint string + entrypointCmd []string + labels []string + volumes []string + publish []string + useAliases bool + servicePorts bool + name string + noDeps bool + ignoreOrphans bool + quietPull bool + ServiceEnvFiles []string } func (opts runOptions) apply(project *types.Project) error { @@ -156,6 +157,7 @@ func runCommand(p *ProjectOptions, streams api.Streams, backend api.Service) *co flags := cmd.Flags() flags.BoolVarP(&opts.Detach, "detach", "d", false, "Run container in background and print container ID") flags.StringArrayVarP(&opts.environment, "env", "e", []string{}, "Set environment variables") + flags.StringArrayVar(&opts.ServiceEnvFiles, "service-env-file", []string{}, "Read in a file of environment variables") flags.StringArrayVarP(&opts.labels, "label", "l", []string{}, "Add or override a label") flags.BoolVar(&opts.Remove, "rm", false, "Automatically remove the container when it exits") flags.BoolVarP(&opts.noTty, "no-TTY", "T", !streams.Out().IsTerminal(), "Disable pseudo-TTY allocation (default: auto-detected).") @@ -233,6 +235,7 @@ func runRun(ctx context.Context, backend api.Service, project *types.Project, op NoDeps: opts.noDeps, Index: 0, QuietPull: opts.quietPull, + ServiceEnvFiles: opts.ServiceEnvFiles, } for i, service := range project.Services { diff --git a/pkg/api/api.go b/pkg/api/api.go index 11f798b2737..5820b8ca756 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -259,7 +259,8 @@ type RunOptions struct { // QuietPull makes the pulling process quiet QuietPull bool // used by exec - Index int + Index int + ServiceEnvFiles []string } // EventsOptions group options of the Events API diff --git a/pkg/compose/run.go b/pkg/compose/run.go index bd16b435b54..28ecb5490ab 100644 --- a/pkg/compose/run.go +++ b/pkg/compose/run.go @@ -127,4 +127,8 @@ func applyRunOptions(project *types.Project, service *types.ServiceConfig, opts for k, v := range opts.Labels { service.Labels = service.Labels.Add(k, v) } + + if opts.ServiceEnvFiles != nil { + service.EnvFile = append(service.EnvFile, opts.ServiceEnvFiles...) + } } diff --git a/pkg/compose/run_test.go b/pkg/compose/run_test.go new file mode 100644 index 00000000000..4cb6f785ee7 --- /dev/null +++ b/pkg/compose/run_test.go @@ -0,0 +1,58 @@ +package compose + +import ( + "testing" + + "github.com/compose-spec/compose-go/types" + "github.com/docker/compose/v2/pkg/api" + "gotest.tools/v3/assert" +) + +func TestServiceEnvFiles(t *testing.T) { + + t.Run("Verify service.EnvFile shouldn't modify", func(t *testing.T) { + fooService := types.ServiceConfig{ + Name: "foo", + EnvFile: []string{}, + } + + project := types.Project{ + Name: "test-project", + Services: types.Services{ + fooService, + }, + } + + opts := api.RunOptions{ + ServiceEnvFiles: nil, + } + + applyRunOptions(&project, &fooService, opts) + + assert.Assert(t, len(fooService.EnvFile) == 0) + }) + + t.Run("Verify appends ServiceEnvFiles", func(t *testing.T) { + fooService := &types.ServiceConfig{ + Name: "foo", + EnvFile: []string{"./existing.env"}, + } + + project := types.Project{ + Name: "test-project", + Services: types.Services{ + *fooService, + }, + } + + opts := api.RunOptions{ + ServiceEnvFiles: []string{"./file.env"}, + } + + applyRunOptions(&project, fooService, opts) + + assert.Assert(t, len(fooService.EnvFile) == 2) + assert.Assert(t, fooService.EnvFile[0] == "./existing.env") + assert.Assert(t, fooService.EnvFile[1] == "./file.env") + }) +}