diff --git a/internal/cmd/affinity-groups/list/list.go b/internal/cmd/affinity-groups/list/list.go index fe9abad60..fb75bf2f3 100644 --- a/internal/cmd/affinity-groups/list/list.go +++ b/internal/cmd/affinity-groups/list/list.go @@ -18,6 +18,7 @@ import ( "github.com/stackitcloud/stackit-cli/internal/pkg/flags" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" + "github.com/stackitcloud/stackit-cli/internal/pkg/projectname" "github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/client" ) @@ -63,16 +64,19 @@ func NewCmd(params *types.CmdParams) *cobra.Command { if err != nil { return fmt.Errorf("list affinity groups: %w", err) } + items := result.GetItems() - if items := result.Items; items != nil { - if model.Limit != nil && len(*items) > int(*model.Limit) { - *items = (*items)[:*model.Limit] - } - return outputResult(params.Printer, *model, *items) + projectLabel, err := projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) + if err != nil { + params.Printer.Debug(print.ErrorLevel, "get project name: %v", err) + projectLabel = model.ProjectId } - params.Printer.Outputln("No affinity groups found") - return nil + // Truncate Output + if model.Limit != nil && len(items) > int(*model.Limit) { + items = items[:*model.Limit] + } + return outputResult(params.Printer, model.OutputFormat, projectLabel, items) }, } configureFlags(cmd) @@ -110,13 +114,12 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, return &model, nil } -func outputResult(p *print.Printer, model inputModel, items []iaas.AffinityGroup) error { - var outputFormat string - if model.GlobalFlagModel != nil { - outputFormat = model.OutputFormat - } - +func outputResult(p *print.Printer, outputFormat, projectLabel string, items []iaas.AffinityGroup) error { return p.OutputResult(outputFormat, items, func() error { + if len(items) == 0 { + p.Outputf("No affinity groups found for project %q\n", projectLabel) + return nil + } table := tables.NewTable() table.SetHeader("ID", "NAME", "POLICY") for _, item := range items { diff --git a/internal/cmd/affinity-groups/list/list_test.go b/internal/cmd/affinity-groups/list/list_test.go index c872f4b45..f8d7610da 100644 --- a/internal/cmd/affinity-groups/list/list_test.go +++ b/internal/cmd/affinity-groups/list/list_test.go @@ -142,16 +142,19 @@ func TestBuildRequest(t *testing.T) { } func TestOutputResult(t *testing.T) { + type args struct { + outputFormat string + projectLabel string + instances []iaas.AffinityGroup + } tests := []struct { description string - model inputModel - response []iaas.AffinityGroup + args args isValid bool }{ { description: "empty", - model: inputModel{}, - response: []iaas.AffinityGroup{}, + args: args{}, isValid: true, }, } @@ -159,7 +162,7 @@ func TestOutputResult(t *testing.T) { p.Cmd = NewCmd(&types.CmdParams{Printer: p}) for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { - err := outputResult(p, tt.model, tt.response) + err := outputResult(p, tt.args.outputFormat, tt.args.projectLabel, tt.args.instances) if err != nil { if !tt.isValid { return diff --git a/internal/cmd/image/list/list.go b/internal/cmd/image/list/list.go index ba21fbe84..26fccfa24 100644 --- a/internal/cmd/image/list/list.go +++ b/internal/cmd/image/list/list.go @@ -81,21 +81,18 @@ func NewCmd(params *types.CmdParams) *cobra.Command { // Call API request := buildRequest(ctx, model, apiClient) - response, err := request.Execute() if err != nil { return fmt.Errorf("list images: %w", err) } + items := response.GetItems() - if items := response.GetItems(); len(items) == 0 { - params.Printer.Info("No images found for project %q", projectLabel) - } else { - if model.Limit != nil && len(items) > int(*model.Limit) { - items = (items)[:*model.Limit] - } - if err := outputResult(params.Printer, model.OutputFormat, items); err != nil { - return fmt.Errorf("output images: %w", err) - } + // Truncate output + if model.Limit != nil && len(items) > int(*model.Limit) { + items = (items)[:*model.Limit] + } + if err := outputResult(params.Printer, model.OutputFormat, projectLabel, items); err != nil { + return fmt.Errorf("output images: %w", err) } return nil @@ -149,8 +146,12 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return request } -func outputResult(p *print.Printer, outputFormat string, items []iaas.Image) error { +func outputResult(p *print.Printer, outputFormat, projectLabel string, items []iaas.Image) error { return p.OutputResult(outputFormat, items, func() error { + if len(items) == 0 { + p.Outputf("No images found for project %q\n", projectLabel) + return nil + } table := tables.NewTable() table.SetHeader("ID", "NAME", "OS", "ARCHITECTURE", "DISTRIBUTION", "VERSION", "SCOPE", "OWNER", "LABELS") for i := range items { diff --git a/internal/cmd/image/list/list_test.go b/internal/cmd/image/list/list_test.go index 7521d2023..b8cd70ce3 100644 --- a/internal/cmd/image/list/list_test.go +++ b/internal/cmd/image/list/list_test.go @@ -189,6 +189,7 @@ func TestBuildRequest(t *testing.T) { func Test_outputResult(t *testing.T) { type args struct { outputFormat string + projectLabel string items []iaas.Image } tests := []struct { @@ -217,7 +218,7 @@ func Test_outputResult(t *testing.T) { p.Cmd = NewCmd(&types.CmdParams{Printer: p}) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(p, tt.args.outputFormat, tt.args.items); (err != nil) != tt.wantErr { + if err := outputResult(p, tt.args.outputFormat, tt.args.projectLabel, tt.args.items); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/internal/cmd/key-pair/list/list.go b/internal/cmd/key-pair/list/list.go index 3820eb038..6abc21158 100644 --- a/internal/cmd/key-pair/list/list.go +++ b/internal/cmd/key-pair/list/list.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/stackitcloud/stackit-cli/internal/pkg/projectname" "github.com/stackitcloud/stackit-cli/internal/pkg/types" "github.com/stackitcloud/stackit-cli/internal/pkg/utils" @@ -77,17 +78,20 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return fmt.Errorf("list key pairs: %w", err) } - if resp.Items == nil || len(*resp.Items) == 0 { - params.Printer.Info("No key pairs found\n") - return nil + items := resp.GetItems() + + projectLabel, err := projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) + if err != nil { + params.Printer.Debug(print.ErrorLevel, "get project name: %v", err) + projectLabel = model.ProjectId } - items := *resp.Items + // Truncate output if model.Limit != nil && len(items) > int(*model.Limit) { items = items[:*model.Limit] } - return outputResult(params.Printer, model.OutputFormat, items) + return outputResult(params.Printer, model.OutputFormat, projectLabel, items) }, } configureFlags(cmd) @@ -128,8 +132,13 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return req } -func outputResult(p *print.Printer, outputFormat string, keyPairs []iaas.Keypair) error { +func outputResult(p *print.Printer, outputFormat, projectLabel string, keyPairs []iaas.Keypair) error { return p.OutputResult(outputFormat, keyPairs, func() error { + if len(keyPairs) == 0 { + p.Outputf("No key pairs found for project %q\n", projectLabel) + return nil + } + table := tables.NewTable() table.SetHeader("KEY PAIR NAME", "LABELS", "FINGERPRINT", "CREATED AT", "UPDATED AT") diff --git a/internal/cmd/key-pair/list/list_test.go b/internal/cmd/key-pair/list/list_test.go index 2ceb0d426..5eee4cced 100644 --- a/internal/cmd/key-pair/list/list_test.go +++ b/internal/cmd/key-pair/list/list_test.go @@ -155,6 +155,7 @@ func TestBuildRequest(t *testing.T) { func Test_outputResult(t *testing.T) { type args struct { outputFormat string + projectLabel string keyPairs []iaas.Keypair } tests := []struct { @@ -179,7 +180,7 @@ func Test_outputResult(t *testing.T) { p := print.NewPrinter() p.Cmd = NewCmd(&types.CmdParams{Printer: p}) - if err := outputResult(p, tt.args.outputFormat, tt.args.keyPairs); (err != nil) != tt.wantErr { + if err := outputResult(p, tt.args.outputFormat, tt.args.projectLabel, tt.args.keyPairs); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/internal/cmd/network-area/list/list.go b/internal/cmd/network-area/list/list.go index cf8d9975d..15e1a9c11 100644 --- a/internal/cmd/network-area/list/list.go +++ b/internal/cmd/network-area/list/list.go @@ -80,31 +80,30 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return fmt.Errorf("list network areas: %w", err) } - if resp.Items == nil || len(*resp.Items) == 0 { - var orgLabel string - rmApiClient, err := rmClient.ConfigureClient(params.Printer, params.CliVersion) - if err == nil { - orgLabel, err = rmUtils.GetOrganizationName(ctx, rmApiClient, *model.OrganizationId) - if err != nil { - params.Printer.Debug(print.ErrorLevel, "get organization name: %v", err) - orgLabel = *model.OrganizationId - } else if orgLabel == "" { - orgLabel = *model.OrganizationId - } - } else { - params.Printer.Debug(print.ErrorLevel, "configure resource manager client: %v", err) + items := resp.GetItems() + + var orgLabel string + rmApiClient, err := rmClient.ConfigureClient(params.Printer, params.CliVersion) + if err == nil { + orgLabel, err = rmUtils.GetOrganizationName(ctx, rmApiClient, *model.OrganizationId) + if err != nil { + params.Printer.Debug(print.ErrorLevel, "get organization name: %v", err) + orgLabel = *model.OrganizationId } - params.Printer.Info("No STACKIT Network Areas found for organization %q\n", orgLabel) - return nil + } else { + params.Printer.Debug(print.ErrorLevel, "configure resource manager client: %v", err) + } + + if orgLabel == "" { + orgLabel = *model.OrganizationId } // Truncate output - items := *resp.Items if model.Limit != nil && len(items) > int(*model.Limit) { items = items[:*model.Limit] } - return outputResult(params.Printer, model.OutputFormat, items) + return outputResult(params.Printer, orgLabel, model.OutputFormat, items) }, } configureFlags(cmd) @@ -149,8 +148,13 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return req } -func outputResult(p *print.Printer, outputFormat string, networkAreas []iaas.NetworkArea) error { +func outputResult(p *print.Printer, orgLabel, outputFormat string, networkAreas []iaas.NetworkArea) error { return p.OutputResult(outputFormat, networkAreas, func() error { + if len(networkAreas) == 0 { + p.Outputf("No STACKIT Network Areas found for organization %q\n", orgLabel) + return nil + } + table := tables.NewTable() table.SetHeader("ID", "Name", "# Attached Projects") diff --git a/internal/cmd/network-area/list/list_test.go b/internal/cmd/network-area/list/list_test.go index 2524bb8c8..f411a60da 100644 --- a/internal/cmd/network-area/list/list_test.go +++ b/internal/cmd/network-area/list/list_test.go @@ -169,6 +169,7 @@ func TestBuildRequest(t *testing.T) { func TestOutputResult(t *testing.T) { type args struct { outputFormat string + orgLabel string networkAreas []iaas.NetworkArea } tests := []struct { @@ -200,7 +201,7 @@ func TestOutputResult(t *testing.T) { p.Cmd = NewCmd(&types.CmdParams{Printer: p}) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(p, tt.args.outputFormat, tt.args.networkAreas); (err != nil) != tt.wantErr { + if err := outputResult(p, tt.args.outputFormat, tt.args.orgLabel, tt.args.networkAreas); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/internal/cmd/network/list/list.go b/internal/cmd/network/list/list.go index 6bc0a8b67..4731e717a 100644 --- a/internal/cmd/network/list/list.go +++ b/internal/cmd/network/list/list.go @@ -77,25 +77,20 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return fmt.Errorf("list networks: %w", err) } - if resp.Items == nil || len(*resp.Items) == 0 { - projectLabel, err := projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) - if err != nil { - params.Printer.Debug(print.ErrorLevel, "get project name: %v", err) - projectLabel = model.ProjectId - } else if projectLabel == "" { - projectLabel = model.ProjectId - } - params.Printer.Info("No networks found for project %q\n", projectLabel) - return nil + items := resp.GetItems() + + projectLabel, err := projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) + if err != nil { + params.Printer.Debug(print.ErrorLevel, "get project name: %v", err) + projectLabel = model.ProjectId } // Truncate output - items := *resp.Items if model.Limit != nil && len(items) > int(*model.Limit) { items = items[:*model.Limit] } - return outputResult(params.Printer, model.OutputFormat, items) + return outputResult(params.Printer, model.OutputFormat, projectLabel, items) }, } configureFlags(cmd) @@ -139,8 +134,13 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return req } -func outputResult(p *print.Printer, outputFormat string, networks []iaas.Network) error { +func outputResult(p *print.Printer, outputFormat, projectLabel string, networks []iaas.Network) error { return p.OutputResult(outputFormat, networks, func() error { + if len(networks) == 0 { + p.Outputf("No networks found for project %q\n", projectLabel) + return nil + } + table := tables.NewTable() table.SetHeader("ID", "NAME", "STATUS", "PUBLIC IP", "PREFIXES", "ROUTED", "ROUTING TABLE ID") diff --git a/internal/cmd/network/list/list_test.go b/internal/cmd/network/list/list_test.go index 67e90a2b4..1769f0547 100644 --- a/internal/cmd/network/list/list_test.go +++ b/internal/cmd/network/list/list_test.go @@ -176,6 +176,7 @@ func TestBuildRequest(t *testing.T) { func TestOutputResult(t *testing.T) { type args struct { outputFormat string + projectLabel string networks []iaas.Network } tests := []struct { @@ -202,7 +203,7 @@ func TestOutputResult(t *testing.T) { p.Cmd = NewCmd(&types.CmdParams{Printer: p}) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(p, tt.args.outputFormat, tt.args.networks); (err != nil) != tt.wantErr { + if err := outputResult(p, tt.args.outputFormat, tt.args.projectLabel, tt.args.networks); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/internal/cmd/public-ip/list/list.go b/internal/cmd/public-ip/list/list.go index 1888e2d1d..a75d94f40 100644 --- a/internal/cmd/public-ip/list/list.go +++ b/internal/cmd/public-ip/list/list.go @@ -77,25 +77,22 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return fmt.Errorf("list public IPs: %w", err) } - if resp.Items == nil || len(*resp.Items) == 0 { - projectLabel, err := projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) - if err != nil { - params.Printer.Debug(print.ErrorLevel, "get project name: %v", err) - projectLabel = model.ProjectId - } else if projectLabel == "" { - projectLabel = model.ProjectId - } - params.Printer.Info("No public IPs found for project %q\n", projectLabel) - return nil + items := resp.GetItems() + + projectLabel, err := projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) + if err != nil { + params.Printer.Debug(print.ErrorLevel, "get project name: %v", err) + projectLabel = model.ProjectId + } else if projectLabel == "" { + projectLabel = model.ProjectId } // Truncate output - items := *resp.Items if model.Limit != nil && len(items) > int(*model.Limit) { items = items[:*model.Limit] } - return outputResult(params.Printer, model.OutputFormat, items) + return outputResult(params.Printer, model.OutputFormat, projectLabel, items) }, } configureFlags(cmd) @@ -140,8 +137,12 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return req } -func outputResult(p *print.Printer, outputFormat string, publicIps []iaas.PublicIp) error { +func outputResult(p *print.Printer, outputFormat, projectLabel string, publicIps []iaas.PublicIp) error { return p.OutputResult(outputFormat, publicIps, func() error { + if len(publicIps) == 0 { + p.Outputf("No public IPs found for project %q\n", projectLabel) + return nil + } table := tables.NewTable() table.SetHeader("ID", "IP ADDRESS", "USED BY") diff --git a/internal/cmd/public-ip/list/list_test.go b/internal/cmd/public-ip/list/list_test.go index 9a10067d9..2d6b57f8f 100644 --- a/internal/cmd/public-ip/list/list_test.go +++ b/internal/cmd/public-ip/list/list_test.go @@ -176,6 +176,7 @@ func TestBuildRequest(t *testing.T) { func TestOutputResult(t *testing.T) { type args struct { outputFormat string + projectLabel string publicIps []iaas.PublicIp } tests := []struct { @@ -193,7 +194,7 @@ func TestOutputResult(t *testing.T) { p.Cmd = NewCmd(&types.CmdParams{Printer: p}) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(p, tt.args.outputFormat, tt.args.publicIps); (err != nil) != tt.wantErr { + if err := outputResult(p, tt.args.outputFormat, tt.args.projectLabel, tt.args.publicIps); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/internal/cmd/security-group/list/list.go b/internal/cmd/security-group/list/list.go index d3788ee9c..6613a3864 100644 --- a/internal/cmd/security-group/list/list.go +++ b/internal/cmd/security-group/list/list.go @@ -25,10 +25,12 @@ import ( type inputModel struct { *globalflags.GlobalFlagModel LabelSelector *string + Limit *int64 } const ( labelSelectorFlag = "label-selector" + limitFlag = "limit" ) func NewCmd(params *types.CmdParams) *cobra.Command { @@ -38,8 +40,16 @@ func NewCmd(params *types.CmdParams) *cobra.Command { Long: "Lists security groups by its internal ID.", Args: args.NoArgs, Example: examples.Build( - examples.NewExample(`List all groups`, `$ stackit security-group list`), - examples.NewExample(`List groups with labels`, `$ stackit security-group list --label-selector label1=value1,label2=value2`), + examples.NewExample(`Lists all security groups`, `$ stackit security-group list`), + examples.NewExample(`Lists security groups with labels`, `$ stackit security-group list --label-selector label1=value1,label2=value2`), + examples.NewExample( + `Lists all security groups in JSON format`, + "$ stackit security-group list --output-format json", + ), + examples.NewExample( + `Lists up to 10 security groups`, + "$ stackit security-group list --limit 10", + ), ), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() @@ -54,12 +64,6 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return err } - projectLabel, err := projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) - if err != nil { - params.Printer.Debug(print.ErrorLevel, "get project name: %v", err) - projectLabel = model.ProjectId - } - // Call API request := buildRequest(ctx, model, apiClient) @@ -68,15 +72,21 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return fmt.Errorf("list security group: %w", err) } - if items := response.GetItems(); len(items) == 0 { - params.Printer.Info("No security groups found for project %q", projectLabel) - } else { - if err := outputResult(params.Printer, model.OutputFormat, items); err != nil { - return fmt.Errorf("output security groups: %w", err) - } + items := response.GetItems() + + projectLabel, err := projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) + if err != nil { + params.Printer.Debug(print.ErrorLevel, "get project name: %v", err) + projectLabel = model.ProjectId } - return nil + // Truncate output + if model.Limit != nil && len(items) > int(*model.Limit) { + items = items[:*model.Limit] + } + + return outputResult(params.Printer, model.OutputFormat, projectLabel, items) + }, } @@ -86,6 +96,7 @@ func NewCmd(params *types.CmdParams) *cobra.Command { func configureFlags(cmd *cobra.Command) { cmd.Flags().String(labelSelectorFlag, "", "Filter by label") + cmd.Flags().Int64(limitFlag, 0, "Maximum number of entries to list") } func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, error) { @@ -94,9 +105,18 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, return nil, &errors.ProjectIdError{} } + limit := flags.FlagToInt64Pointer(p, cmd, limitFlag) + if limit != nil && *limit < 1 { + return nil, &errors.FlagValidationError{ + Flag: limitFlag, + Details: "must be greater than 0", + } + } + model := inputModel{ GlobalFlagModel: globalFlags, LabelSelector: flags.FlagToStringPointer(p, cmd, labelSelectorFlag), + Limit: limit, } p.DebugInputModel(model) @@ -111,8 +131,12 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return request } -func outputResult(p *print.Printer, outputFormat string, items []iaas.SecurityGroup) error { +func outputResult(p *print.Printer, outputFormat, projectLabel string, items []iaas.SecurityGroup) error { return p.OutputResult(outputFormat, items, func() error { + if len(items) == 0 { + p.Outputf("No security groups found for project %q\n", projectLabel) + return nil + } table := tables.NewTable() table.SetHeader("ID", "NAME", "STATEFUL", "DESCRIPTION", "LABELS") for _, item := range items { diff --git a/internal/cmd/security-group/list/list_test.go b/internal/cmd/security-group/list/list_test.go index 18cfa967e..e5a0f1b84 100644 --- a/internal/cmd/security-group/list/list_test.go +++ b/internal/cmd/security-group/list/list_test.go @@ -36,6 +36,7 @@ func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]st globalflags.RegionFlag: testRegion, labelSelectorFlag: testLabels, + limitFlag: "10", } for _, mod := range mods { mod(flagValues) @@ -51,6 +52,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { Verbosity: globalflags.VerbosityDefault, }, LabelSelector: utils.Ptr(testLabels), + Limit: utils.Ptr(int64(10)), } for _, mod := range mods { mod(model) @@ -127,6 +129,20 @@ func TestParseInput(t *testing.T) { model.LabelSelector = utils.Ptr("foo=bar") }), }, + { + description: "limit invalid", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[limitFlag] = "invalid" + }), + isValid: false, + }, + { + description: "limit invalid 2", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + flagValues[limitFlag] = "0" + }), + isValid: false, + }, } for _, tt := range tests { @@ -184,6 +200,7 @@ func TestBuildRequest(t *testing.T) { func TestOutputResult(t *testing.T) { type args struct { outputFormat string + projectLabel string items []iaas.SecurityGroup } tests := []struct { @@ -201,7 +218,7 @@ func TestOutputResult(t *testing.T) { p.Cmd = NewCmd(&types.CmdParams{Printer: p}) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(p, tt.args.outputFormat, tt.args.items); (err != nil) != tt.wantErr { + if err := outputResult(p, tt.args.outputFormat, tt.args.projectLabel, tt.args.items); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/internal/cmd/server/list/list.go b/internal/cmd/server/list/list.go index 54c058dc0..2ecb2a16a 100644 --- a/internal/cmd/server/list/list.go +++ b/internal/cmd/server/list/list.go @@ -78,23 +78,20 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return fmt.Errorf("list servers: %w", err) } - if resp.Items == nil || len(*resp.Items) == 0 { - projectLabel, err := projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) - if err != nil { - params.Printer.Debug(print.ErrorLevel, "get project name: %v", err) - projectLabel = model.ProjectId - } - params.Printer.Info("No servers found for project %q\n", projectLabel) - return nil + items := resp.GetItems() + + projectLabel, err := projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) + if err != nil { + params.Printer.Debug(print.ErrorLevel, "get project name: %v", err) + projectLabel = model.ProjectId } // Truncate output - items := *resp.Items if model.Limit != nil && len(items) > int(*model.Limit) { items = items[:*model.Limit] } - return outputResult(params.Printer, model.OutputFormat, items) + return outputResult(params.Printer, model.OutputFormat, projectLabel, items) }, } configureFlags(cmd) @@ -140,7 +137,7 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return req } -func outputResult(p *print.Printer, outputFormat string, servers []iaas.Server) error { +func outputResult(p *print.Printer, outputFormat, projectLabel string, servers []iaas.Server) error { switch outputFormat { case print.JSONOutputFormat: details, err := json.MarshalIndent(servers, "", " ") @@ -164,6 +161,10 @@ func outputResult(p *print.Printer, outputFormat string, servers []iaas.Server) return nil default: + if len(servers) == 0 { + p.Outputf("No servers found for project %q\n", projectLabel) + return nil + } table := tables.NewTable() table.SetHeader("ID", "Name", "Status", "Machine Type", "Availability Zones", "Nic IPv4", "Public IPs") diff --git a/internal/cmd/server/list/list_test.go b/internal/cmd/server/list/list_test.go index 4eb3a78cf..5166cc118 100644 --- a/internal/cmd/server/list/list_test.go +++ b/internal/cmd/server/list/list_test.go @@ -177,6 +177,7 @@ func TestBuildRequest(t *testing.T) { func TestOutputResult(t *testing.T) { type args struct { outputFormat string + projectLabel string servers []iaas.Server } tests := []struct { @@ -194,7 +195,7 @@ func TestOutputResult(t *testing.T) { p.Cmd = NewCmd(&types.CmdParams{Printer: p}) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(p, tt.args.outputFormat, tt.args.servers); (err != nil) != tt.wantErr { + if err := outputResult(p, tt.args.outputFormat, tt.args.projectLabel, tt.args.servers); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } })