Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor ls command, enhance argument handling, and add unit tests #198

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
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
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ require (
github.com/skeema/knownhosts v1.1.0 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/stretchr/objx v0.4.0 // indirect
github.com/subosito/gotenv v1.4.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
Expand Down
86 changes: 49 additions & 37 deletions pkg/cmd/ls/ls.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package ls

import (
"fmt"
"os"

"github.com/brevdev/brev-cli/pkg/analytics"
"github.com/brevdev/brev-cli/pkg/cmd/cmderrors"
Expand Down Expand Up @@ -39,7 +38,7 @@ func NewCmdLs(t *terminal.Terminal, loginLsStore LsStore, noLoginLsStore LsStore

cmd := &cobra.Command{
Annotations: map[string]string{"context": ""},
Use: "ls",
Use: "ls [orgs|organizations|workspaces|users|hosts]",
Aliases: []string{"list"},
Short: "List instances within active org",
Long: "List instances within your active org. List all instances if no active org is set.",
Expand Down Expand Up @@ -90,8 +89,14 @@ func NewCmdLs(t *terminal.Terminal, loginLsStore LsStore, noLoginLsStore LsStore

return nil
},
Args: cmderrors.TransformToValidationError(cobra.MinimumNArgs(0)),
ValidArgs: []string{"orgs", "workspaces"},
Args: cmderrors.TransformToValidationError(func(cmd *cobra.Command, args []string) error {
// Allow 0 or 1 argument, and only valid ones
if len(args) > 1 {
return fmt.Errorf("this command accepts only zero or one argument")
}
return cobra.OnlyValidArgs(cmd, args)
}),
ValidArgs: []string{"org", "orgs", "organization", "organizations", "workspace", "workspaces", "user", "users", "host", "hosts"},
RunE: func(cmd *cobra.Command, args []string) error {
err := RunLs(t, loginLsStore, args, org, showAll)
if err != nil {
Expand Down Expand Up @@ -162,61 +167,68 @@ func RunLs(t *terminal.Terminal, lsStore LsStore, args []string, orgflag string,
return breverrors.WrapAndTrace(err)
}

org, err := getOrgForRunLs(lsStore, orgflag)
orgEntity, err := getOrgForRunLs(lsStore, orgflag)
if err != nil {
return breverrors.WrapAndTrace(err)
}
if len(args) > 1 {
return breverrors.NewValidationError("too many args provided")
}

if len(args) == 1 { //nolint:gocritic // don't want to switch
err = handleLsArg(ls, args[0], user, org, showAll)
if len(args) == 0 {
// No argument provided, list workspaces by default
err = ls.RunWorkspaces(orgEntity, user, showAll)
if err != nil {
return breverrors.WrapAndTrace(err)
}
} else if len(args) == 0 {
err = ls.RunWorkspaces(org, user, showAll)
} else {
// Handle the provided argument
err = handleLsArg(ls, args[0], user, orgEntity, showAll)
if err != nil {
return breverrors.WrapAndTrace(err)
}
} else {
return fmt.Errorf("unhandle ls arguments")
}

return nil
}

func handleLsArg(ls *Ls, arg string, user *entity.User, org *entity.Organization, showAll bool) error {
// todo refactor this to cmd.register
//nolint:gocritic // idk how to write this as a switch
if util.IsSingularOrPlural(arg, "org") || util.IsSingularOrPlural(arg, "organization") { // handle org, orgs, and organization(s)
err := ls.RunOrgs()
if err != nil {
switch {
case util.IsSingularOrPlural(arg, "org") || util.IsSingularOrPlural(arg, "organization"):
// Handle organizations
if err := ls.RunOrgs(); err != nil {
return breverrors.WrapAndTrace(err)
}
return nil
} else if util.IsSingularOrPlural(arg, "workspace") {
err := ls.RunWorkspaces(org, user, showAll)
if err != nil {
case util.IsSingularOrPlural(arg, "workspace"):
// Handle workspaces
if err := ls.RunWorkspaces(org, user, showAll); err != nil {
return breverrors.WrapAndTrace(err)
}
} else if util.IsSingularOrPlural(arg, "user") && featureflag.IsAdmin(user.GlobalUserType) {
err := ls.RunUser(showAll)
if err != nil {
return breverrors.WrapAndTrace(err)
case util.IsSingularOrPlural(arg, "user"):
// Handle users, only if the user is an admin
if featureflag.IsAdmin(user.GlobalUserType) {
if err := ls.RunUser(showAll); err != nil {
return breverrors.WrapAndTrace(err)
}
} else {
return breverrors.NewValidationError("user management is only available for admins")
}
return nil
} else if util.IsSingularOrPlural(arg, "host") && featureflag.IsAdmin(user.GlobalUserType) {
err := ls.RunHosts(org)
if err != nil {
return breverrors.WrapAndTrace(err)
case util.IsSingularOrPlural(arg, "host"):
// Handle hosts, only if the user is an admin
if featureflag.IsAdmin(user.GlobalUserType) {
if err := ls.RunHosts(org); err != nil {
return breverrors.WrapAndTrace(err)
}
} else {
return breverrors.NewValidationError("host management is only available for admins")
}
return nil
default:
// If the argument is not recognized, return a validation error
return breverrors.NewValidationError("unrecognized argument")
}

return nil
}


type Ls struct {
lsStore LsStore
terminal *terminal.Terminal
Expand Down Expand Up @@ -412,7 +424,7 @@ func displayProjects(t *terminal.Terminal, orgName string, projects []virtualpro
if len(projects) > 0 {
fmt.Print("\n")
t.Vprintf("%d other projects in Org "+t.Yellow(orgName)+"\n", len(projects))
displayProjectsTable(projects)
displayProjectsTable(t, projects)

fmt.Print("\n")
t.Vprintf(t.Green("Join a project:\n") +
Expand All @@ -438,7 +450,7 @@ func getBrevTableOptions() table.Options {

func displayWorkspacesTable(t *terminal.Terminal, workspaces []entity.Workspace, userID string) {
ta := table.NewWriter()
ta.SetOutputMirror(os.Stdout)
ta.SetOutputMirror(t.Out())
ta.Style().Options = getBrevTableOptions()
header := table.Row{"Name", "Status", "ID", "Machine"}
if enableSSHCol {
Expand Down Expand Up @@ -471,7 +483,7 @@ func getWorkspaceDisplayStatus(w entity.Workspace) string {

func displayOrgTable(t *terminal.Terminal, orgs []entity.Organization, currentOrg *entity.Organization) {
ta := table.NewWriter()
ta.SetOutputMirror(os.Stdout)
ta.SetOutputMirror(t.Out())
ta.Style().Options = getBrevTableOptions()
header := table.Row{"NAME", "ID"}
ta.AppendHeader(header)
Expand All @@ -485,9 +497,9 @@ func displayOrgTable(t *terminal.Terminal, orgs []entity.Organization, currentOr
ta.Render()
}

func displayProjectsTable(projects []virtualproject.VirtualProject) {
func displayProjectsTable(t *terminal.Terminal, projects []virtualproject.VirtualProject) {
ta := table.NewWriter()
ta.SetOutputMirror(os.Stdout)
ta.SetOutputMirror(t.Out())
ta.Style().Options = getBrevTableOptions()
header := table.Row{"NAME", "MEMBERS"}
ta.AppendHeader(header)
Expand Down
Loading