diff --git a/aci/compose.go b/aci/compose.go index 60a42b170..edf822424 100644 --- a/aci/compose.go +++ b/aci/compose.go @@ -163,20 +163,17 @@ func (cs *aciComposeService) Ps(ctx context.Context, project string) ([]compose. return res, nil } -func (cs *aciComposeService) List(ctx context.Context, project string) ([]compose.Stack, error) { +func (cs *aciComposeService) List(ctx context.Context) ([]compose.Stack, error) { containerGroups, err := getACIContainerGroups(ctx, cs.ctx.SubscriptionID, cs.ctx.ResourceGroup) if err != nil { return nil, err } - stacks := []compose.Stack{} + var stacks []compose.Stack for _, group := range containerGroups { if _, found := group.Tags[composeContainerTag]; !found { continue } - if project != "" && *group.Name != project { - continue - } state := compose.RUNNING for _, container := range *group.ContainerGroupProperties.Containers { containerState := convert.GetStatus(container, group) diff --git a/api/client/compose.go b/api/client/compose.go index 072b06b99..449645afa 100644 --- a/api/client/compose.go +++ b/api/client/compose.go @@ -64,7 +64,7 @@ func (c *composeService) Ps(context.Context, string) ([]compose.ContainerSummary return nil, errdefs.ErrNotImplemented } -func (c *composeService) List(context.Context, string) ([]compose.Stack, error) { +func (c *composeService) List(context.Context) ([]compose.Stack, error) { return nil, errdefs.ErrNotImplemented } diff --git a/api/compose/api.go b/api/compose/api.go index 19a535b22..0f196c1ff 100644 --- a/api/compose/api.go +++ b/api/compose/api.go @@ -44,7 +44,7 @@ type Service interface { // Ps executes the equivalent to a `compose ps` Ps(ctx context.Context, projectName string) ([]ContainerSummary, error) // List executes the equivalent to a `docker stack ls` - List(ctx context.Context, projectName string) ([]Stack, error) + List(ctx context.Context) ([]Stack, error) // Convert translate compose model into backend's native format Convert(ctx context.Context, project *types.Project, options ConvertOptions) ([]byte, error) // RunOneOffContainer creates a service oneoff container and starts its dependencies diff --git a/cli/cmd/compose/list.go b/cli/cmd/compose/list.go index c0175f493..b45b8f2a4 100644 --- a/cli/cmd/compose/list.go +++ b/cli/cmd/compose/list.go @@ -23,6 +23,7 @@ import ( "os" "strings" + "github.com/docker/cli/opts" "github.com/spf13/cobra" "github.com/docker/compose-cli/api/client" @@ -33,10 +34,11 @@ import ( type lsOptions struct { Format string Quiet bool + Filter opts.FilterOpt } func listCommand() *cobra.Command { - opts := lsOptions{} + opts := lsOptions{Filter: opts.NewFilterOpt()} lsCmd := &cobra.Command{ Use: "ls", Short: "List running compose projects", @@ -45,16 +47,28 @@ func listCommand() *cobra.Command { }, } lsCmd.Flags().StringVar(&opts.Format, "format", "pretty", "Format the output. Values: [pretty | json].") - lsCmd.Flags().BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs") + lsCmd.Flags().BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs.") + lsCmd.Flags().Var(&opts.Filter, "filter", "Filter output based on conditions provided.") + return lsCmd } +var acceptedListFilters = map[string]bool{ + "name": true, +} + func runList(ctx context.Context, opts lsOptions) error { + filters := opts.Filter.Value() + err := filters.Validate(acceptedListFilters) + if err != nil { + return err + } + c, err := client.NewWithDefaultLocalBackend(ctx) if err != nil { return err } - stackList, err := c.ComposeService().List(ctx, "") + stackList, err := c.ComposeService().List(ctx) if err != nil { return err } @@ -64,6 +78,18 @@ func runList(ctx context.Context, opts lsOptions) error { } return nil } + + if filters.Len() > 0 { + var filtered []compose.Stack + for _, s := range stackList { + if filters.Contains("name") && !filters.Match("name", s.Name) { + continue + } + filtered = append(filtered, s) + } + stackList = filtered + } + view := viewFromStackList(stackList) return formatter.Print(view, opts.Format, os.Stdout, func(w io.Writer) { for _, stack := range view { diff --git a/cli/server/proxy/compose.go b/cli/server/proxy/compose.go index edb07bcf3..43939549e 100644 --- a/cli/server/proxy/compose.go +++ b/cli/server/proxy/compose.go @@ -77,7 +77,7 @@ func (p *proxy) Services(ctx context.Context, request *composev1.ComposeServices } func (p *proxy) Stacks(ctx context.Context, request *composev1.ComposeStacksRequest) (*composev1.ComposeStacksResponse, error) { - stacks, err := Client(ctx).ComposeService().List(ctx, request.ProjectName) + stacks, err := Client(ctx).ComposeService().List(ctx) if err != nil { return nil, err } diff --git a/ecs/aws.go b/ecs/aws.go index 80234b38f..505622ba2 100644 --- a/ecs/aws.go +++ b/ecs/aws.go @@ -49,7 +49,7 @@ type API interface { UpdateStack(ctx context.Context, changeset string) error WaitStackComplete(ctx context.Context, name string, operation int) error GetStackID(ctx context.Context, name string) (string, error) - ListStacks(ctx context.Context, name string) ([]compose.Stack, error) + ListStacks(ctx context.Context) ([]compose.Stack, error) GetStackClusterID(ctx context.Context, stack string) (string, error) GetServiceTaskDefinition(ctx context.Context, cluster string, serviceArns []string) (map[string]string, error) ListStackServices(ctx context.Context, stack string) ([]string, error) diff --git a/ecs/aws_mock.go b/ecs/aws_mock.go index 1ed432d10..70aa9a833 100644 --- a/ecs/aws_mock.go +++ b/ecs/aws_mock.go @@ -6,14 +6,12 @@ package ecs import ( context "context" - reflect "reflect" - cloudformation "github.com/aws/aws-sdk-go/service/cloudformation" ecs "github.com/aws/aws-sdk-go/service/ecs" - gomock "github.com/golang/mock/gomock" - compose "github.com/docker/compose-cli/api/compose" secrets "github.com/docker/compose-cli/api/secrets" + gomock "github.com/golang/mock/gomock" + reflect "reflect" ) // MockAPI is a mock of API interface @@ -546,18 +544,18 @@ func (mr *MockAPIMockRecorder) ListStackServices(arg0, arg1 interface{}) *gomock } // ListStacks mocks base method -func (m *MockAPI) ListStacks(arg0 context.Context, arg1 string) ([]compose.Stack, error) { +func (m *MockAPI) ListStacks(arg0 context.Context) ([]compose.Stack, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListStacks", arg0, arg1) + ret := m.ctrl.Call(m, "ListStacks", arg0) ret0, _ := ret[0].([]compose.Stack) ret1, _ := ret[1].(error) return ret0, ret1 } // ListStacks indicates an expected call of ListStacks -func (mr *MockAPIMockRecorder) ListStacks(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockAPIMockRecorder) ListStacks(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListStacks", reflect.TypeOf((*MockAPI)(nil).ListStacks), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListStacks", reflect.TypeOf((*MockAPI)(nil).ListStacks), arg0) } // ListTasks mocks base method diff --git a/ecs/e2e/ecs/e2e-ecs_test.go b/ecs/e2e/ecs/e2e-ecs_test.go index d6dd78d03..576542d64 100644 --- a/ecs/e2e/ecs/e2e-ecs_test.go +++ b/ecs/e2e/ecs/e2e-ecs_test.go @@ -122,7 +122,7 @@ func TestCompose(t *testing.T) { }) t.Run("compose ls", func(t *testing.T) { - res := c.RunDockerCmd("compose", "ls", "--project-name", stack) + res := c.RunDockerCmd("compose", "ls", "--filter", "name="+stack) lines := strings.Split(strings.TrimSpace(res.Stdout()), "\n") assert.Equal(t, 2, len(lines)) diff --git a/ecs/list.go b/ecs/list.go index ce96208b5..e54e780c8 100644 --- a/ecs/list.go +++ b/ecs/list.go @@ -23,8 +23,8 @@ import ( "github.com/docker/compose-cli/api/compose" ) -func (b *ecsAPIService) List(ctx context.Context, project string) ([]compose.Stack, error) { - stacks, err := b.aws.ListStacks(ctx, project) +func (b *ecsAPIService) List(ctx context.Context) ([]compose.Stack, error) { + stacks, err := b.aws.ListStacks(ctx) if err != nil { return nil, err } diff --git a/ecs/local/compose.go b/ecs/local/compose.go index b20741afe..9b993f32d 100644 --- a/ecs/local/compose.go +++ b/ecs/local/compose.go @@ -161,8 +161,8 @@ func (e ecsLocalSimulation) Logs(ctx context.Context, projectName string, consum func (e ecsLocalSimulation) Ps(ctx context.Context, projectName string) ([]compose.ContainerSummary, error) { return e.compose.Ps(ctx, projectName) } -func (e ecsLocalSimulation) List(ctx context.Context, projectName string) ([]compose.Stack, error) { - return e.compose.List(ctx, projectName) +func (e ecsLocalSimulation) List(ctx context.Context) ([]compose.Stack, error) { + return e.compose.List(ctx) } func (e ecsLocalSimulation) RunOneOffContainer(ctx context.Context, project *types.Project, opts compose.RunOptions) error { return errors.Wrap(errdefs.ErrNotImplemented, "use docker-compose run") diff --git a/ecs/sdk.go b/ecs/sdk.go index 92a2b3f26..0c3ca93e1 100644 --- a/ecs/sdk.go +++ b/ecs/sdk.go @@ -444,11 +444,8 @@ func (s sdk) GetStackID(ctx context.Context, name string) (string, error) { return *stacks.Stacks[0].StackId, nil } -func (s sdk) ListStacks(ctx context.Context, name string) ([]compose.Stack, error) { +func (s sdk) ListStacks(ctx context.Context) ([]compose.Stack, error) { params := cloudformation.DescribeStacksInput{} - if name != "" { - params.StackName = &name - } var token *string var stacks []compose.Stack for { diff --git a/local/compose/ls.go b/local/compose/ls.go index 322ad5b65..1466d3a09 100644 --- a/local/compose/ls.go +++ b/local/compose/ls.go @@ -27,7 +27,7 @@ import ( "github.com/docker/docker/api/types/filters" ) -func (s *composeService) List(ctx context.Context, projectName string) ([]compose.Stack, error) { +func (s *composeService) List(ctx context.Context) ([]compose.Stack, error) { list, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{ Filters: filters.NewArgs(hasProjectLabelFilter()), })