From 4f3f6d611e695435c24eef482717da1aca11d185 Mon Sep 17 00:00:00 2001 From: Michal Sokolowski <0michalsokolowski0@gmail.com> Date: Wed, 28 Aug 2024 13:27:00 +0200 Subject: [PATCH 1/6] refactor: Use searchStacks over stacks for listing stacks --- internal/cmd/stack/list.go | 53 +++++++++------------------- internal/cmd/stack/open_command.go | 36 ++----------------- internal/cmd/stack/stack_selector.go | 36 ++++++++++++++++++- 3 files changed, 54 insertions(+), 71 deletions(-) diff --git a/internal/cmd/stack/list.go b/internal/cmd/stack/list.go index bcaf7b5..3311828 100644 --- a/internal/cmd/stack/list.go +++ b/internal/cmd/stack/list.go @@ -1,14 +1,11 @@ package stack import ( - "context" "fmt" - "sort" + "github.com/spacelift-io/spacectl/client/structs" "strings" - "github.com/pkg/errors" "github.com/spacelift-io/spacectl/internal/cmd" - "github.com/spacelift-io/spacectl/internal/cmd/authenticated" "github.com/urfave/cli/v2" ) @@ -23,49 +20,33 @@ func listStacks() cli.ActionFunc { case cmd.OutputFormatTable: return listStacksTable(cliCtx) case cmd.OutputFormatJSON: - return listStacksJSON(cliCtx.Context) + return listStacksJSON(cliCtx) } return fmt.Errorf("unknown output format: %v", outputFormat) } } -func listStacksJSON(ctx context.Context) error { - var query struct { - Stacks []stack `graphql:"stacks" json:"stacks,omitempty"` +func listStacksJSON(ctx *cli.Context) error { + stacks, err := searchStacks(ctx.Context, structs.SearchInput{}) + if err != nil { + return err } - if err := authenticated.Client.Query(ctx, &query, map[string]interface{}{}); err != nil { - return errors.Wrap(err, "failed to query list of stacks") - } - return cmd.OutputJSON(query.Stacks) + return cmd.OutputJSON(stacks) } func listStacksTable(ctx *cli.Context) error { - var query struct { - Stacks []struct { - ID string `graphql:"id" json:"id,omitempty"` - LockedBy string `graphql:"lockedBy"` - Name string `graphql:"name"` - State string `graphql:"state"` - Labels []string `graphql:"labels"` - TrackedCommit struct { - AuthorName string `graphql:"authorName"` - Hash string `graphql:"hash"` - } `graphql:"trackedCommit"` - WorkerPool struct { - Name string `graphql:"name"` - } `graphql:"workerPool"` - } `graphql:"stacks"` - } - - if err := authenticated.Client.Query(ctx.Context, &query, map[string]interface{}{}); err != nil { - return errors.Wrap(err, "failed to query list of stacks") - } - - sort.SliceStable(query.Stacks, func(i, j int) bool { - return strings.Compare(strings.ToLower(query.Stacks[i].Name), strings.ToLower(query.Stacks[j].Name)) < 0 + stacks, err := searchStacks(ctx.Context, structs.SearchInput{ + OrderBy: &structs.QueryOrder{ + Field: "name", + // TODO: Make sure the order is correct + Direction: "ASC", + }, }) + if err != nil { + return err + } columns := []string{"Name", "ID", "Commit", "Author", "State", "Worker Pool", "Locked By"} if ctx.Bool(flagShowLabels.Name) { @@ -73,7 +54,7 @@ func listStacksTable(ctx *cli.Context) error { } tableData := [][]string{columns} - for _, stack := range query.Stacks { + for _, stack := range stacks { row := []string{ stack.Name, stack.ID, diff --git a/internal/cmd/stack/open_command.go b/internal/cmd/stack/open_command.go index 807879a..9f4e755 100644 --- a/internal/cmd/stack/open_command.go +++ b/internal/cmd/stack/open_command.go @@ -163,7 +163,7 @@ type stackSearchParams struct { branch *string } -func searchStacks(ctx context.Context, p *stackSearchParams) ([]stack, error) { +func searchStacks(ctx context.Context, input structs.SearchInput) ([]stack, error) { var query struct { SearchStacksOutput struct { Edges []struct { @@ -172,43 +172,11 @@ func searchStacks(ctx context.Context, p *stackSearchParams) ([]stack, error) { PageInfo structs.PageInfo `graphql:"pageInfo"` } `graphql:"searchStacks(input: $input)"` } - conditions := []structs.QueryPredicate{ - { - Field: graphql.String("repository"), - Constraint: structs.QueryFieldConstraint{ - StringMatches: &[]graphql.String{graphql.String(p.repositoryName)}, - }, - }, - } - - if p.projectRoot != nil && *p.projectRoot != "" { - root := strings.TrimSuffix(*p.projectRoot, "/") - conditions = append(conditions, structs.QueryPredicate{ - Field: graphql.String("projectRoot"), - Constraint: structs.QueryFieldConstraint{ - StringMatches: &[]graphql.String{graphql.String(root), graphql.String(root + "/")}, - }, - }) - } - - if p.branch != nil { - conditions = append(conditions, structs.QueryPredicate{ - Field: graphql.String("branch"), - Constraint: structs.QueryFieldConstraint{ - StringMatches: &[]graphql.String{graphql.String(*p.branch)}, - }, - }) - } - - variables := map[string]interface{}{"input": structs.SearchInput{ - First: graphql.NewInt(graphql.Int(p.count)), //nolint: gosec - Predicates: &conditions, - }} if err := authenticated.Client.Query( ctx, &query, - variables, + map[string]interface{}{"input": input}, graphql.WithHeader("Spacelift-GraphQL-Query", "StacksPage"), ); err != nil { return nil, errors.Wrap(err, "failed search for stacks") diff --git a/internal/cmd/stack/stack_selector.go b/internal/cmd/stack/stack_selector.go index 4f2053a..890eeb9 100644 --- a/internal/cmd/stack/stack_selector.go +++ b/internal/cmd/stack/stack_selector.go @@ -3,6 +3,7 @@ package stack import ( "context" "fmt" + "github.com/spacelift-io/spacectl/client/structs" "strings" "github.com/manifoldco/promptui" @@ -90,7 +91,40 @@ func stackGetByID(ctx context.Context, stackID string) (*stack, error) { } func findAndSelectStack(ctx context.Context, p *stackSearchParams, forcePrompt bool) (*stack, error) { - stacks, err := searchStacks(ctx, p) + conditions := []structs.QueryPredicate{ + { + Field: graphql.String("repository"), + Constraint: structs.QueryFieldConstraint{ + StringMatches: &[]graphql.String{graphql.String(p.repositoryName)}, + }, + }, + } + + if p.projectRoot != nil && *p.projectRoot != "" { + root := strings.TrimSuffix(*p.projectRoot, "/") + conditions = append(conditions, structs.QueryPredicate{ + Field: "projectRoot", + Constraint: structs.QueryFieldConstraint{ + StringMatches: &[]graphql.String{graphql.String(root), graphql.String(root + "/")}, + }, + }) + } + + if p.branch != nil { + conditions = append(conditions, structs.QueryPredicate{ + Field: "branch", + Constraint: structs.QueryFieldConstraint{ + StringMatches: &[]graphql.String{graphql.String(*p.branch)}, + }, + }) + } + + input := structs.SearchInput{ + First: graphql.NewInt(graphql.Int(p.count)), //nolint: gosec + Predicates: &conditions, + } + + stacks, err := searchStacks(ctx, input) if err != nil { return nil, err } From cec8fb15ffe3b4966cd3b0cd11799f488bfbd943 Mon Sep 17 00:00:00 2001 From: Michal Sokolowski <0michalsokolowski0@gmail.com> Date: Wed, 28 Aug 2024 13:28:30 +0200 Subject: [PATCH 2/6] refactor: Resolve linter issues --- internal/cmd/stack/list.go | 2 +- internal/cmd/stack/stack_selector.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/cmd/stack/list.go b/internal/cmd/stack/list.go index 3311828..c3199f4 100644 --- a/internal/cmd/stack/list.go +++ b/internal/cmd/stack/list.go @@ -2,9 +2,9 @@ package stack import ( "fmt" - "github.com/spacelift-io/spacectl/client/structs" "strings" + "github.com/spacelift-io/spacectl/client/structs" "github.com/spacelift-io/spacectl/internal/cmd" "github.com/urfave/cli/v2" ) diff --git a/internal/cmd/stack/stack_selector.go b/internal/cmd/stack/stack_selector.go index 890eeb9..ad78d24 100644 --- a/internal/cmd/stack/stack_selector.go +++ b/internal/cmd/stack/stack_selector.go @@ -3,12 +3,12 @@ package stack import ( "context" "fmt" - "github.com/spacelift-io/spacectl/client/structs" "strings" "github.com/manifoldco/promptui" "github.com/pkg/errors" "github.com/shurcooL/graphql" + "github.com/spacelift-io/spacectl/client/structs" "github.com/spacelift-io/spacectl/internal/cmd/authenticated" "github.com/urfave/cli/v2" ) From 39b1203edc64f02d15dc458208e433ac93d601f1 Mon Sep 17 00:00:00 2001 From: Michal Sokolowski <0michalsokolowski0@gmail.com> Date: Wed, 28 Aug 2024 13:46:36 +0200 Subject: [PATCH 3/6] refactor: Fix --- internal/cmd/stack/list.go | 3 +-- internal/cmd/stack/stack_selector.go | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/internal/cmd/stack/list.go b/internal/cmd/stack/list.go index c3199f4..e6e1224 100644 --- a/internal/cmd/stack/list.go +++ b/internal/cmd/stack/list.go @@ -39,8 +39,7 @@ func listStacksJSON(ctx *cli.Context) error { func listStacksTable(ctx *cli.Context) error { stacks, err := searchStacks(ctx.Context, structs.SearchInput{ OrderBy: &structs.QueryOrder{ - Field: "name", - // TODO: Make sure the order is correct + Field: "name", Direction: "ASC", }, }) diff --git a/internal/cmd/stack/stack_selector.go b/internal/cmd/stack/stack_selector.go index ad78d24..4335ce9 100644 --- a/internal/cmd/stack/stack_selector.go +++ b/internal/cmd/stack/stack_selector.go @@ -15,7 +15,7 @@ import ( var errNoStackFound = errors.New("no stack found") -// getStackID will try to retreive a stack ID from multiple sources. +// getStackID will try to retrieve a stack ID from multiple sources. // It will do so in the following order: // 1. Check the --id flag, if set, use that value. // 2. Check the current directory to determine repository and subdirectory and search for a stack. From 2d7797ce4b02f3000d234c94d1aa2e0f38c03eb2 Mon Sep 17 00:00:00 2001 From: Michal Sokolowski <0michalsokolowski0@gmail.com> Date: Wed, 28 Aug 2024 14:04:36 +0200 Subject: [PATCH 4/6] refactor: Change order of stack in table --- internal/cmd/stack/list.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/cmd/stack/list.go b/internal/cmd/stack/list.go index e6e1224..4451853 100644 --- a/internal/cmd/stack/list.go +++ b/internal/cmd/stack/list.go @@ -39,8 +39,8 @@ func listStacksJSON(ctx *cli.Context) error { func listStacksTable(ctx *cli.Context) error { stacks, err := searchStacks(ctx.Context, structs.SearchInput{ OrderBy: &structs.QueryOrder{ - Field: "name", - Direction: "ASC", + Field: "starred", + Direction: "DESC", }, }) if err != nil { From 56a8c005c23415b4c07cd61350c60996a343aa4d Mon Sep 17 00:00:00 2001 From: Michal Sokolowski <0michalsokolowski0@gmail.com> Date: Wed, 28 Aug 2024 14:32:19 +0200 Subject: [PATCH 5/6] refactor: Retrieve all stacks using searchStacks --- internal/cmd/stack/list.go | 48 +++++++++++++++++++++------- internal/cmd/stack/open_command.go | 18 ++++++++--- internal/cmd/stack/stack_selector.go | 8 ++--- 3 files changed, 54 insertions(+), 20 deletions(-) diff --git a/internal/cmd/stack/list.go b/internal/cmd/stack/list.go index 4451853..1e040c6 100644 --- a/internal/cmd/stack/list.go +++ b/internal/cmd/stack/list.go @@ -1,9 +1,11 @@ package stack import ( + "context" "fmt" "strings" + "github.com/shurcooL/graphql" "github.com/spacelift-io/spacectl/client/structs" "github.com/spacelift-io/spacectl/internal/cmd" "github.com/urfave/cli/v2" @@ -28,7 +30,9 @@ func listStacks() cli.ActionFunc { } func listStacksJSON(ctx *cli.Context) error { - stacks, err := searchStacks(ctx.Context, structs.SearchInput{}) + stacks, err := searchAllStacks(ctx.Context, structs.SearchInput{ + First: graphql.NewInt(50), + }) if err != nil { return err } @@ -37,7 +41,8 @@ func listStacksJSON(ctx *cli.Context) error { } func listStacksTable(ctx *cli.Context) error { - stacks, err := searchStacks(ctx.Context, structs.SearchInput{ + stacks, err := searchAllStacks(ctx.Context, structs.SearchInput{ + First: graphql.NewInt(50), OrderBy: &structs.QueryOrder{ Field: "starred", Direction: "DESC", @@ -53,18 +58,18 @@ func listStacksTable(ctx *cli.Context) error { } tableData := [][]string{columns} - for _, stack := range stacks { + for _, s := range stacks { row := []string{ - stack.Name, - stack.ID, - cmd.HumanizeGitHash(stack.TrackedCommit.Hash), - stack.TrackedCommit.AuthorName, - stack.State, - stack.WorkerPool.Name, - stack.LockedBy, + s.Name, + s.ID, + cmd.HumanizeGitHash(s.TrackedCommit.Hash), + s.TrackedCommit.AuthorName, + s.State, + s.WorkerPool.Name, + s.LockedBy, } if ctx.Bool(flagShowLabels.Name) { - row = append(row, strings.Join(stack.Labels, ", ")) + row = append(row, strings.Join(s.Labels, ", ")) } tableData = append(tableData, row) @@ -73,6 +78,27 @@ func listStacksTable(ctx *cli.Context) error { return cmd.OutputTable(tableData, true) } +func searchAllStacks(ctx context.Context, input structs.SearchInput) ([]stack, error) { + out := []stack{} + + for { + result, err := searchStacks(ctx, input) + if err != nil { + return nil, err + } + + out = append(out, result.Stacks...) + + if !result.PageInfo.HasNextPage { + break + } else { + input.After = graphql.NewString(graphql.String(result.PageInfo.EndCursor)) + } + } + + return out, nil +} + type stack struct { ID string `graphql:"id" json:"id,omitempty"` Administrative bool `graphql:"administrative" json:"administrative,omitempty"` diff --git a/internal/cmd/stack/open_command.go b/internal/cmd/stack/open_command.go index 9f4e755..eec44e8 100644 --- a/internal/cmd/stack/open_command.go +++ b/internal/cmd/stack/open_command.go @@ -163,7 +163,12 @@ type stackSearchParams struct { branch *string } -func searchStacks(ctx context.Context, input structs.SearchInput) ([]stack, error) { +type searchStacksResult struct { + Stacks []stack + PageInfo structs.PageInfo +} + +func searchStacks(ctx context.Context, input structs.SearchInput) (searchStacksResult, error) { var query struct { SearchStacksOutput struct { Edges []struct { @@ -179,13 +184,16 @@ func searchStacks(ctx context.Context, input structs.SearchInput) ([]stack, erro map[string]interface{}{"input": input}, graphql.WithHeader("Spacelift-GraphQL-Query", "StacksPage"), ); err != nil { - return nil, errors.Wrap(err, "failed search for stacks") + return searchStacksResult{}, errors.Wrap(err, "failed search for stacks") } - result := make([]stack, 0) + stacks := make([]stack, 0) for _, q := range query.SearchStacksOutput.Edges { - result = append(result, q.Node) + stacks = append(stacks, q.Node) } - return result, nil + return searchStacksResult{ + Stacks: stacks, + PageInfo: query.SearchStacksOutput.PageInfo, + }, nil } diff --git a/internal/cmd/stack/stack_selector.go b/internal/cmd/stack/stack_selector.go index 4335ce9..02c4f2d 100644 --- a/internal/cmd/stack/stack_selector.go +++ b/internal/cmd/stack/stack_selector.go @@ -124,16 +124,16 @@ func findAndSelectStack(ctx context.Context, p *stackSearchParams, forcePrompt b Predicates: &conditions, } - stacks, err := searchStacks(ctx, input) + result, err := searchStacks(ctx, input) if err != nil { return nil, err } items := []string{} found := map[string]stack{} - for _, stack := range stacks { - items = append(items, stack.Name) - found[stack.Name] = stack + for _, s := range result.Stacks { + items = append(items, s.Name) + found[s.Name] = s } if len(found) == 0 { From 119d6073b0e4e85ded512992c340abbf640a149f Mon Sep 17 00:00:00 2001 From: Michal Sokolowski <0michalsokolowski0@gmail.com> Date: Wed, 28 Aug 2024 14:35:54 +0200 Subject: [PATCH 6/6] refactor: Improve readablilty --- internal/cmd/stack/list.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/cmd/stack/list.go b/internal/cmd/stack/list.go index 1e040c6..32a3f19 100644 --- a/internal/cmd/stack/list.go +++ b/internal/cmd/stack/list.go @@ -89,10 +89,10 @@ func searchAllStacks(ctx context.Context, input structs.SearchInput) ([]stack, e out = append(out, result.Stacks...) - if !result.PageInfo.HasNextPage { - break - } else { + if result.PageInfo.HasNextPage { input.After = graphql.NewString(graphql.String(result.PageInfo.EndCursor)) + } else { + break } }