Skip to content

Commit

Permalink
Add stack list command
Browse files Browse the repository at this point in the history
- At the moment it just returns the full list of stacks, with no filtering.
- I've tried to strip down the amount of columns used in the table output as much as possible to try to keep things readable.
- I've also not included certain things like the before and after hook scripts - I think we could add them to a separate `stack show` command to get all the info about a particular stack.

Issues: #33
  • Loading branch information
adamconnelly committed Jul 9, 2021
1 parent 14997e1 commit 2bc935e
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 0 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/gookit/color v1.4.2 // indirect
github.com/mholt/archiver/v3 v3.5.0
github.com/onsi/gomega v1.11.0
github.com/pkg/errors v0.9.1
github.com/pterm/pterm v0.12.13
github.com/sabhiram/go-gitignore v0.0.0-20201211210132-54b8a0bf510f
github.com/shurcooL/graphql v0.0.0-20200928012149-18c5c3165e3a
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQ
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
Expand Down
138 changes: 138 additions & 0 deletions internal/cmd/stack/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package stack

import (
"context"
"fmt"
"sort"
"strings"

"github.com/pkg/errors"
"github.com/urfave/cli/v2"

"github.com/spacelift-io/spacectl/internal/cmd"
"github.com/spacelift-io/spacectl/internal/cmd/authenticated"
)

func listStacks() cli.ActionFunc {
return func(cliCtx *cli.Context) error {
outputFormat, err := cmd.GetOutputFormat(cliCtx)
if err != nil {
return err
}

switch outputFormat {
case cmd.OutputFormatTable:
return listStacksTable(cliCtx.Context)
case cmd.OutputFormatJSON:
return listStacksJSON(cliCtx.Context)
}

return fmt.Errorf("unknown output format: %v", outputFormat)
}
}

func listStacksJSON(ctx context.Context) error {
var query struct {
Stacks []struct {
ID string `graphql:"id" json:"id,omitempty"`
Administrative bool `graphql:"administrative" json:"administrative,omitempty"`
Autodeploy bool `graphql:"autodeploy" json:"autodeploy,omitempty"`
Autoretry bool `graphql:"autoretry" json:"autoretry,omitempty"`
Blocker struct {
ID string `graphql:"id" json:"id,omitempty"`
} `graphql:"blocker"`
AfterApply []string `graphql:"afterApply" json:"afterApply,omitempty"`
BeforeApply []string `graphql:"beforeApply" json:"beforeApply,omitempty"`
AfterInit []string `graphql:"afterInit" json:"afterInit,omitempty"`
BeforeInit []string `graphql:"beforeInit" json:"beforeInit,omitempty"`
AfterPlan []string `graphql:"afterPlan" json:"afterPlan,omitempty"`
BeforePlan []string `graphql:"beforePlan" json:"beforePlan,omitempty"`
AfterPerform []string `graphql:"afterPerform" json:"afterPerform,omitempty"`
BeforePerform []string `graphql:"beforePerform" json:"beforePerform,omitempty"`
AfterDestroy []string `graphql:"afterDestroy" json:"afterDestroy,omitempty"`
BeforeDestroy []string `graphql:"beforeDestroy" json:"beforeDestroy,omitempty"`
Branch string `graphql:"branch" json:"branch,omitempty"`
CanWrite bool `graphql:"canWrite" json:"canWrite,omitempty"`
CreatedAt int64 `graphql:"createdAt" json:"createdAt,omitempty"`
Deleted bool `graphql:"deleted" json:"deleted,omitempty"`
Deleting bool `graphql:"deleting" json:"deleting,omitempty"`
Description string `graphql:"description" json:"description,omitempty"`
Labels []string `graphql:"labels" json:"labels,omitempty"`
LocalPreviewEnabled bool `graphql:"localPreviewEnabled" json:"localPreviewEnabled,omitempty"`
LockedBy string `graphql:"lockedBy" json:"lockedBy,omitempty"`
ManagesStateFile bool `graphql:"managesStateFile" json:"managesStateFile,omitempty"`
Name string `graphql:"name" json:"name,omitempty"`
Namespace string `graphql:"namespace" json:"namespace,omitempty"`
ProjectRoot string `graphql:"projectRoot" json:"projectRoot,omitempty"`
Provider string `graphql:"provider" json:"provider,omitempty"`
Repository string `graphql:"repository" json:"repository,omitempty"`
RunnerImage string `graphql:"runnerImage" json:"runnerImage,omitempty"`
Starred bool `graphql:"starred" json:"starred,omitempty"`
State string `graphql:"state" json:"state,omitempty"`
StateSetAt int64 `graphql:"stateSetAt" json:"stateSetAt,omitempty"`
TerraformVersion string `graphql:"terraformVersion" json:"terraformVersion,omitempty"`
TrackedCommit struct {
AuthorLogin string `graphql:"authorLogin" json:"authorLogin,omitempty"`
AuthorName string `graphql:"authorName" json:"authorName,omitempty"`
Hash string `graphql:"hash" json:"hash,omitempty"`
Message string `graphql:"message" json:"message,omitempty"`
Timestamp int64 `graphql:"timestamp" json:"timestamp,omitempty"`
URL string `graphql:"url" json:"url,omitempty"`
} `graphql:"trackedCommit" json:"trackedCommit,omitempty"`
TrackedCommitSetBy string `graphql:"trackedCommitSetBy" json:"trackedCommitSetBy,omitempty"`
WorkerPool struct {
ID string `graphql:"id" json:"id,omitempty"`
Name string `graphql:"name" json:"name,omitempty"`
} `graphql:"workerPool" json:"workerPool,omitempty"`
} `graphql:"stacks" json:"stacks,omitempty"`
}

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)
}

func listStacksTable(ctx context.Context) error {
var query struct {
Stacks []struct {
LockedBy string `graphql:"lockedBy"`
Name string `graphql:"name"`
State string `graphql:"state"`
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, &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
})

tableData := [][]string{{"Name", "Commit", "Author", "State", "Worker Pool", "Locked By"}}
for _, stack := range query.Stacks {
var shortenedHash string
if len(stack.TrackedCommit.Hash) > 8 {
shortenedHash = stack.TrackedCommit.Hash[0:8]
}

tableData = append(tableData, []string{
stack.Name,
shortenedHash,
stack.TrackedCommit.AuthorName,
stack.State,
stack.WorkerPool.Name,
stack.LockedBy,
})
}

return cmd.OutputTable(tableData)
}
10 changes: 10 additions & 0 deletions internal/cmd/stack/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ func Command() *cli.Command {
Before: authenticated.Ensure,
ArgsUsage: cmd.EmptyArgsUsage,
},
{
Name: "list",
Usage: "List the stacks you have access to",
Flags: []cli.Flag{
cmd.FlagOutputFormat,
},
Action: listStacks(),
Before: authenticated.Ensure,
ArgsUsage: cmd.EmptyArgsUsage,
},
{
Category: "Run local preview",
Name: "local-preview",
Expand Down

0 comments on commit 2bc935e

Please sign in to comment.