Skip to content
Open
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
13 changes: 9 additions & 4 deletions cmd/compose/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"sort"
"strings"

"github.com/compose-spec/compose-go/v2/cli"
"github.com/docker/cli/cli/command"
"github.com/spf13/cobra"

Expand All @@ -44,7 +45,9 @@ func completeServiceNames(dockerCli command.Cli, p *ProjectOptions) validArgsFn
return nil, cobra.ShellCompDirectiveNoFileComp
}

project, _, err := p.ToProject(cmd.Context(), dockerCli, backend, nil)
// only service names are needed, so skip environment resolution: a missing
// env_file must not prevent completion
project, _, err := p.ToProject(cmd.Context(), dockerCli, backend, nil, cli.WithoutEnvironmentResolution)
if err != nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
Expand Down Expand Up @@ -90,7 +93,9 @@ func completeProfileNames(dockerCli command.Cli, p *ProjectOptions) validArgsFn
return nil, cobra.ShellCompDirectiveNoFileComp
}

project, _, err := p.ToProject(cmd.Context(), dockerCli, backend, nil)
// only profile names are needed, so skip environment resolution: a missing
// env_file must not prevent completion
project, _, err := p.ToProject(cmd.Context(), dockerCli, backend, nil, cli.WithoutEnvironmentResolution)
if err != nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
Expand All @@ -108,9 +113,9 @@ func completeProfileNames(dockerCli command.Cli, p *ProjectOptions) validArgsFn
}
}

func completeScaleArgs(cli command.Cli, p *ProjectOptions) cobra.CompletionFunc {
func completeScaleArgs(dockerCli command.Cli, p *ProjectOptions) cobra.CompletionFunc {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
completions, directive := completeServiceNames(cli, p)(cmd, args, toComplete)
completions, directive := completeServiceNames(dockerCli, p)(cmd, args, toComplete)
for i, completion := range completions {
completions[i] = completion + "="
}
Expand Down
10 changes: 9 additions & 1 deletion cmd/compose/scale.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"strconv"
"strings"

"github.com/compose-spec/compose-go/v2/cli"
"github.com/compose-spec/compose-go/v2/types"
"github.com/docker/cli/cli/command"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -67,7 +68,14 @@ func runScale(ctx context.Context, dockerCli command.Cli, backendOptions *Backen
}

services := slices.Sorted(maps.Keys(serviceReplicaTuples))
project, _, err := opts.ToProject(ctx, dockerCli, backend, services)
project, _, err := opts.ToProject(ctx, dockerCli, backend, services, cli.WithoutEnvironmentResolution)
if err != nil {
return err
}

// resolve environment after the project has been reduced to selected services,
// so env_file declared by unrelated services doesn't need to exist
project, err = project.WithServicesEnvironmentResolved(true)
if err != nil {
return err
}
Expand Down
10 changes: 9 additions & 1 deletion cmd/compose/watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"fmt"

"github.com/compose-spec/compose-go/v2/cli"
"github.com/compose-spec/compose-go/v2/types"
"github.com/docker/cli/cli/command"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -71,7 +72,14 @@ func runWatch(ctx context.Context, dockerCli command.Cli, backendOptions *Backen
return err
}

project, _, err := watchOpts.ToProject(ctx, dockerCli, backend, services)
project, _, err := watchOpts.ToProject(ctx, dockerCli, backend, services, cli.WithoutEnvironmentResolution)
if err != nil {
return err
}

// resolve environment after the project has been reduced to selected services,
// so env_file declared by unrelated services doesn't need to exist
project, err = project.WithServicesEnvironmentResolved(true)
if err != nil {
return err
}
Expand Down
19 changes: 19 additions & 0 deletions pkg/e2e/env_file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,25 @@ func TestUnusedMissingEnvFile(t *testing.T) {
c.RunDockerComposeCmd(t, "-f", "./fixtures/env_file/compose.yaml", "ps")
c.RunDockerComposeCmd(t, "-f", "./fixtures/env_file/compose.yaml", "logs")
c.RunDockerComposeCmd(t, "-f", "./fixtures/env_file/compose.yaml", "exec", "serviceA", "echo", "hello")

// scale should work even with missing env file on a service not being scaled
c.RunDockerComposeCmd(t, "-f", "./fixtures/env_file/compose.yaml", "scale", "serviceA=2")

// but scaling the service with the missing env file must still fail
res := c.RunDockerComposeCmdNoCheck(t, "-f", "./fixtures/env_file/compose.yaml", "scale", "serviceB=1")
res.Assert(t, icmd.Expected{ExitCode: 1, Err: "env file /doesnotexist/.env not found"})

// shell completion should list services even with missing env file.
// ComposeStandalonePath fails the test outside standalone mode, so only the
// plugin form can be the default here.
completeCmd := []string{DockerExecutableName, "__complete", "compose"}
if composeStandaloneMode {
completeCmd = []string{ComposeStandalonePath(t), "__complete"}
}
res = c.RunCmd(t, append(completeCmd, "-f", "./fixtures/env_file/compose.yaml", "exec", "")...)
res.Assert(t, icmd.Expected{Out: "serviceA"})
res.Assert(t, icmd.Expected{Out: "serviceB"})

c.RunDockerComposeCmd(t, "-f", "./fixtures/env_file/compose.yaml", "down")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[low] No e2e test for watch tolerating missing env_file on unrelated service

The PR title and description explicitly name watch as one of the three commands fixed, and cmd/compose/watch.go gets the same WithoutEnvironmentResolution + WithServicesEnvironmentResolved treatment as scale. However, TestUnusedMissingEnvFile adds coverage for scale and shell completion but not for watch.

A minimal watch-specific check would be something like:

// watch should work even with missing env file on a service not being watched
// (requires --no-up to avoid a blocking daemon; or check exit code directly)
res = c.RunDockerComposeCmdNoCheck(t, "-f", "./fixtures/env_file/compose.yaml", "watch", "--no-up", "serviceA")
// watch starts a long-running daemon, so just assert it doesn't immediately fail
// with the env_file error
res.Assert(t, icmd.Expected{ExitCode: 0})

Without this, a future regression (e.g. removing WithoutEnvironmentResolution from watch.go) would not be caught by the test suite.

Confidence Score
🟢 strong 100/100

}

Expand Down
Loading