diff --git a/cmd/compose/down.go b/cmd/compose/down.go index e868bbf8536..a8713ee2cfe 100644 --- a/cmd/compose/down.go +++ b/cmd/compose/down.go @@ -44,7 +44,7 @@ func downCommand(p *ProjectOptions, backend api.Service) *cobra.Command { ProjectOptions: p, } downCmd := &cobra.Command{ - Use: "down [OPTIONS]", + Use: "down [OPTIONS] [SERVICES]", Short: "Stop and remove containers, networks", PreRunE: AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error { opts.timeChanged = cmd.Flags().Changed("timeout") @@ -56,9 +56,8 @@ func downCommand(p *ProjectOptions, backend api.Service) *cobra.Command { return nil }), RunE: Adapt(func(ctx context.Context, args []string) error { - return runDown(ctx, backend, opts) + return runDown(ctx, backend, opts, args) }), - Args: cobra.NoArgs, ValidArgsFunction: noCompletion(), } flags := downCmd.Flags() @@ -77,7 +76,7 @@ func downCommand(p *ProjectOptions, backend api.Service) *cobra.Command { return downCmd } -func runDown(ctx context.Context, backend api.Service, opts downOptions) error { +func runDown(ctx context.Context, backend api.Service, opts downOptions, services []string) error { project, name, err := opts.projectOrName() if err != nil { return err @@ -94,5 +93,6 @@ func runDown(ctx context.Context, backend api.Service, opts downOptions) error { Timeout: timeout, Images: opts.images, Volumes: opts.volumes, + Services: services, }) } diff --git a/docs/reference/docker_compose_down.yaml b/docs/reference/docker_compose_down.yaml index 9b4916bd4a2..b536a259caf 100644 --- a/docs/reference/docker_compose_down.yaml +++ b/docs/reference/docker_compose_down.yaml @@ -14,7 +14,7 @@ long: |- Anonymous volumes are not removed by default. However, as they don’t have a stable name, they will not be automatically mounted by a subsequent `up`. For data that needs to persist between updates, use explicit paths as bind mounts or named volumes. -usage: docker compose down [OPTIONS] +usage: docker compose down [OPTIONS] [SERVICES] pname: docker compose plink: docker_compose.yaml options: diff --git a/pkg/api/api.go b/pkg/api/api.go index a31e32e992a..f4f730a8f45 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -232,6 +232,8 @@ type DownOptions struct { Images string // Volumes remove volumes, both declared in the `volumes` section and anonymous ones Volumes bool + // Services passed in the command line to be stopped + Services []string } // ConfigOptions group options of the Config API diff --git a/pkg/compose/down.go b/pkg/compose/down.go index 7c4def35a74..34cd7dc2c58 100644 --- a/pkg/compose/down.go +++ b/pkg/compose/down.go @@ -44,7 +44,7 @@ func (s *composeService) Down(ctx context.Context, projectName string, options a }, s.stdinfo()) } -func (s *composeService) down(ctx context.Context, projectName string, options api.DownOptions) error { +func (s *composeService) down(ctx context.Context, projectName string, options api.DownOptions) error { //golint:nocyclo w := progress.ContextWriter(ctx) resourceToRemove := false @@ -70,6 +70,9 @@ func (s *composeService) down(ctx context.Context, projectName string, options a } err = InReverseDependencyOrder(ctx, project, func(c context.Context, service string) error { + if len(options.Services) > 0 && !utils.StringContains(options.Services, service) { + return nil + } serviceContainers := containers.filter(isService(service)) err := s.removeContainers(ctx, w, serviceContainers, options.Timeout, options.Volumes) return err diff --git a/pkg/e2e/compose_test.go b/pkg/e2e/compose_test.go index 700856dac20..dad8a0d1d3c 100644 --- a/pkg/e2e/compose_test.go +++ b/pkg/e2e/compose_test.go @@ -102,6 +102,14 @@ func TestLocalComposeUp(t *testing.T) { res.Assert(t, icmd.Expected{Out: `compose-e2e-demo-words-1 gtardif/sentences-api latest`}) }) + t.Run("down SERVICE", func(t *testing.T) { + _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down", "web") + + res := c.RunDockerComposeCmd(t, "--project-name", projectName, "ps") + assert.Assert(t, !strings.Contains(res.Combined(), "compose-e2e-demo-web-1"), res.Combined()) + assert.Assert(t, strings.Contains(res.Combined(), "compose-e2e-demo-db-1"), res.Combined()) + }) + t.Run("down", func(t *testing.T) { _ = c.RunDockerComposeCmd(t, "--project-name", projectName, "down") }) diff --git a/pkg/progress/event.go b/pkg/progress/event.go index fbb85038851..26aca98d8d5 100644 --- a/pkg/progress/event.go +++ b/pkg/progress/event.go @@ -153,6 +153,15 @@ func RemovedEvent(id string) Event { return NewEvent(id, Done, "Removed") } +// SkippedEvent creates a new Skipped Event +func SkippedEvent(id string, reason string) Event { + return Event{ + ID: id, + Status: Warning, + StatusText: "Skipped: " + reason, + } +} + // NewEvent new event func NewEvent(id string, status EventStatus, statusText string) Event { return Event{