From 70b932b59da6e91d17b39cadb1de30e0900b36df Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Mon, 13 Apr 2026 11:17:41 +0200 Subject: [PATCH 01/39] fix returning empty server array in case the response does not return any items via outputResult function instead of returning nil bluntly. adapted tests therefore. --- internal/cmd/server/list/list.go | 27 ++++++++++++++++----------- internal/cmd/server/list/list_test.go | 3 ++- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/internal/cmd/server/list/list.go b/internal/cmd/server/list/list.go index 54c058dc0..eeb3507b8 100644 --- a/internal/cmd/server/list/list.go +++ b/internal/cmd/server/list/list.go @@ -78,23 +78,25 @@ 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 + var items []iaas.Server + if resp.Items == nil { + items = []iaas.Server{} + } else { + items = *resp.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 } // 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 +142,10 @@ 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 string, projectLabel string, servers []iaas.Server) error { + if len(servers) == 0 { + p.Info("No servers found for project %q\n", projectLabel) + } switch outputFormat { case print.JSONOutputFormat: details, err := json.MarshalIndent(servers, "", " ") diff --git a/internal/cmd/server/list/list_test.go b/internal/cmd/server/list/list_test.go index e28b9f45a..22f3285d5 100644 --- a/internal/cmd/server/list/list_test.go +++ b/internal/cmd/server/list/list_test.go @@ -175,6 +175,7 @@ func TestBuildRequest(t *testing.T) { func TestOutputResult(t *testing.T) { type args struct { outputFormat string + projectLabel string servers []iaas.Server } tests := []struct { @@ -191,7 +192,7 @@ func TestOutputResult(t *testing.T) { params := testparams.NewTestParams() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.servers); (err != nil) != tt.wantErr { + if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.projectLabel, tt.args.servers); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) From 14cca956ca9339ff587c4bf6b84a4d047639c5c4 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Mon, 13 Apr 2026 11:53:08 +0200 Subject: [PATCH 02/39] adapted outputResult signature to comply to linter --- internal/cmd/server/list/list.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/cmd/server/list/list.go b/internal/cmd/server/list/list.go index eeb3507b8..bdeb78605 100644 --- a/internal/cmd/server/list/list.go +++ b/internal/cmd/server/list/list.go @@ -142,7 +142,7 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return req } -func outputResult(p *print.Printer, outputFormat string, projectLabel string, servers []iaas.Server) error { +func outputResult(p *print.Printer, outputFormat, projectLabel string, servers []iaas.Server) error { if len(servers) == 0 { p.Info("No servers found for project %q\n", projectLabel) } From 972a75e904064cfa52fd66e57c57e5ccf19decdd Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Mon, 13 Apr 2026 13:27:54 +0200 Subject: [PATCH 03/39] switched to getter for retrieving the items --- internal/cmd/server/list/list.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/internal/cmd/server/list/list.go b/internal/cmd/server/list/list.go index bdeb78605..25aeae32f 100644 --- a/internal/cmd/server/list/list.go +++ b/internal/cmd/server/list/list.go @@ -78,11 +78,9 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return fmt.Errorf("list servers: %w", err) } - var items []iaas.Server - if resp.Items == nil { + items := resp.GetItems() + if items == nil { items = []iaas.Server{} - } else { - items = *resp.Items } projectLabel, err := projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) From 7f78cf858b29864768020a8971f52056441700d8 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Mon, 13 Apr 2026 13:58:07 +0200 Subject: [PATCH 04/39] adapted printing behavior to align with expected behavior --- internal/cmd/server/list/list.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/internal/cmd/server/list/list.go b/internal/cmd/server/list/list.go index 25aeae32f..0880cfd08 100644 --- a/internal/cmd/server/list/list.go +++ b/internal/cmd/server/list/list.go @@ -141,9 +141,6 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli } func outputResult(p *print.Printer, outputFormat, projectLabel string, servers []iaas.Server) error { - if len(servers) == 0 { - p.Info("No servers found for project %q\n", projectLabel) - } switch outputFormat { case print.JSONOutputFormat: details, err := json.MarshalIndent(servers, "", " ") @@ -167,6 +164,10 @@ func outputResult(p *print.Printer, outputFormat, projectLabel string, servers [ return nil default: + if len(servers) == 0 { + p.Info("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") From 936bb0026139fe53c28ab6c97cf8d130851d5d04 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Mon, 13 Apr 2026 14:32:05 +0200 Subject: [PATCH 05/39] change printing to defined output instead of stderr --- internal/cmd/server/list/list.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/cmd/server/list/list.go b/internal/cmd/server/list/list.go index 0880cfd08..1f504460d 100644 --- a/internal/cmd/server/list/list.go +++ b/internal/cmd/server/list/list.go @@ -165,7 +165,7 @@ func outputResult(p *print.Printer, outputFormat, projectLabel string, servers [ return nil default: if len(servers) == 0 { - p.Info("No servers found for project %q\n", projectLabel) + p.Outputf("No servers found for project %q\n", projectLabel) return nil } table := tables.NewTable() From 07bb8397453cf8705a845ff81b82c3b6f3e4c8c4 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Mon, 13 Apr 2026 14:42:24 +0200 Subject: [PATCH 06/39] adapted network list command to align to expectations --- internal/cmd/network/list/list.go | 28 ++++++++++++++------------ internal/cmd/network/list/list_test.go | 3 ++- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/internal/cmd/network/list/list.go b/internal/cmd/network/list/list.go index 6bc0a8b67..2c18746c9 100644 --- a/internal/cmd/network/list/list.go +++ b/internal/cmd/network/list/list.go @@ -77,25 +77,22 @@ 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 + } 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) @@ -139,8 +136,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 1c1b620bb..1aa09530c 100644 --- a/internal/cmd/network/list/list_test.go +++ b/internal/cmd/network/list/list_test.go @@ -174,6 +174,7 @@ func TestBuildRequest(t *testing.T) { func TestOutputResult(t *testing.T) { type args struct { outputFormat string + projectLabel string networks []iaas.Network } tests := []struct { @@ -199,7 +200,7 @@ func TestOutputResult(t *testing.T) { params := testparams.NewTestParams() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.networks); (err != nil) != tt.wantErr { + if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.projectLabel, tt.args.networks); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) From f015fae15673cfb7504ed427b65c4d8f4aa9bdab Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Mon, 13 Apr 2026 14:45:43 +0200 Subject: [PATCH 07/39] remove unnecessary normalization of nil value in response items after feedback --- internal/cmd/server/list/list.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/internal/cmd/server/list/list.go b/internal/cmd/server/list/list.go index 1f504460d..2ecb2a16a 100644 --- a/internal/cmd/server/list/list.go +++ b/internal/cmd/server/list/list.go @@ -79,9 +79,6 @@ func NewCmd(params *types.CmdParams) *cobra.Command { } items := resp.GetItems() - if items == nil { - items = []iaas.Server{} - } projectLabel, err := projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) if err != nil { From 7fb466a3f8c738a8dece25e4b81a366269ebbc22 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Mon, 13 Apr 2026 15:21:50 +0200 Subject: [PATCH 08/39] adapted network-area list command to align to expectations --- internal/cmd/network-area/list/list.go | 40 +++++++++++---------- internal/cmd/network-area/list/list_test.go | 3 +- 2 files changed, 24 insertions(+), 19 deletions(-) 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 e561fe9ab..2cd2be0ac 100644 --- a/internal/cmd/network-area/list/list_test.go +++ b/internal/cmd/network-area/list/list_test.go @@ -167,6 +167,7 @@ func TestBuildRequest(t *testing.T) { func TestOutputResult(t *testing.T) { type args struct { outputFormat string + orgLabel string networkAreas []iaas.NetworkArea } tests := []struct { @@ -197,7 +198,7 @@ func TestOutputResult(t *testing.T) { params := testparams.NewTestParams() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.networkAreas); (err != nil) != tt.wantErr { + if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.orgLabel, tt.args.networkAreas); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) From 2e13f9827fc4e9df4945cd26fc3d376be514b0aa Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Mon, 13 Apr 2026 15:31:17 +0200 Subject: [PATCH 09/39] removed redundant check --- internal/cmd/network/list/list.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/cmd/network/list/list.go b/internal/cmd/network/list/list.go index 2c18746c9..4731e717a 100644 --- a/internal/cmd/network/list/list.go +++ b/internal/cmd/network/list/list.go @@ -83,8 +83,6 @@ func NewCmd(params *types.CmdParams) *cobra.Command { if err != nil { params.Printer.Debug(print.ErrorLevel, "get project name: %v", err) projectLabel = model.ProjectId - } else if projectLabel == "" { - projectLabel = model.ProjectId } // Truncate output From fd6ccb03260f6ede5461a9a1de061199b7f3bf79 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 15 Apr 2026 11:10:22 +0200 Subject: [PATCH 10/39] adapted affinity list command to align to expectations --- internal/cmd/affinity-groups/list/list.go | 29 ++++++++++--------- .../cmd/affinity-groups/list/list_test.go | 13 +++++---- 2 files changed, 24 insertions(+), 18 deletions(-) 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 df04a8024..b1141d13c 100644 --- a/internal/cmd/affinity-groups/list/list_test.go +++ b/internal/cmd/affinity-groups/list/list_test.go @@ -141,23 +141,26 @@ 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, }, } params := testparams.NewTestParams() for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { - err := outputResult(params.Printer, tt.model, tt.response) + err := outputResult(params.Printer, tt.args.outputFormat, tt.args.projectLabel, tt.args.instances) if err != nil { if !tt.isValid { return From 6752d884c82dabf834996a99a2e42d44d6fca53f Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 15 Apr 2026 11:26:05 +0200 Subject: [PATCH 11/39] adapted image list command to align to expectations --- internal/cmd/image/list/list.go | 23 ++++++++++++----------- internal/cmd/image/list/list_test.go | 3 ++- 2 files changed, 14 insertions(+), 12 deletions(-) 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 2307dc23a..417e1d6af 100644 --- a/internal/cmd/image/list/list_test.go +++ b/internal/cmd/image/list/list_test.go @@ -188,6 +188,7 @@ func TestBuildRequest(t *testing.T) { func Test_outputResult(t *testing.T) { type args struct { outputFormat string + projectLabel string items []iaas.Image } tests := []struct { @@ -215,7 +216,7 @@ func Test_outputResult(t *testing.T) { params := testparams.NewTestParams() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.items); (err != nil) != tt.wantErr { + if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.projectLabel, tt.args.items); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) From 3f6a8be0290991c6dec0734ef2f4f2cbcc4540df Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 15 Apr 2026 12:05:09 +0200 Subject: [PATCH 12/39] adapted key pair list command to align to expectations --- internal/cmd/key-pair/list/list.go | 22 +++++++++++++++------- internal/cmd/key-pair/list/list_test.go | 3 ++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/internal/cmd/key-pair/list/list.go b/internal/cmd/key-pair/list/list.go index 3820eb038..7a28b20f9 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" @@ -70,6 +71,11 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return err } + projectLabel, err := projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) + if err != nil { + return fmt.Errorf("list key pairs: %w", err) + } + // Call API req := buildRequest(ctx, model, apiClient) resp, err := req.Execute() @@ -77,17 +83,14 @@ 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() - 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 +131,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 779b57d49..665e1cfad 100644 --- a/internal/cmd/key-pair/list/list_test.go +++ b/internal/cmd/key-pair/list/list_test.go @@ -153,6 +153,7 @@ func TestBuildRequest(t *testing.T) { func Test_outputResult(t *testing.T) { type args struct { outputFormat string + projectLabel string keyPairs []iaas.Keypair } tests := []struct { @@ -176,7 +177,7 @@ func Test_outputResult(t *testing.T) { t.Run(tt.name, func(t *testing.T) { params := testparams.NewTestParams() - if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.keyPairs); (err != nil) != tt.wantErr { + if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.projectLabel, tt.args.keyPairs); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) From 8e340925748bd928d5f1ef4bff69bf21e69bfad6 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 15 Apr 2026 12:23:37 +0200 Subject: [PATCH 13/39] fixed debug print in key pair list command --- internal/cmd/key-pair/list/list.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/cmd/key-pair/list/list.go b/internal/cmd/key-pair/list/list.go index 7a28b20f9..92f7f0027 100644 --- a/internal/cmd/key-pair/list/list.go +++ b/internal/cmd/key-pair/list/list.go @@ -73,7 +73,8 @@ func NewCmd(params *types.CmdParams) *cobra.Command { projectLabel, err := projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) if err != nil { - return fmt.Errorf("list key pairs: %w", err) + params.Printer.Debug(print.ErrorLevel, "get project name: %v", err) + projectLabel = model.ProjectId } // Call API From 51fb3e175b116d6dd2c9c5451f9907214afd7f6e Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 15 Apr 2026 12:27:23 +0200 Subject: [PATCH 14/39] move project label retrieval --- internal/cmd/key-pair/list/list.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/cmd/key-pair/list/list.go b/internal/cmd/key-pair/list/list.go index 92f7f0027..6abc21158 100644 --- a/internal/cmd/key-pair/list/list.go +++ b/internal/cmd/key-pair/list/list.go @@ -71,12 +71,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 req := buildRequest(ctx, model, apiClient) resp, err := req.Execute() @@ -86,6 +80,12 @@ func NewCmd(params *types.CmdParams) *cobra.Command { 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 if model.Limit != nil && len(items) > int(*model.Limit) { items = items[:*model.Limit] From 4661dc56c65615472722f33dbefdf1d99420a8e9 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 15 Apr 2026 13:01:25 +0200 Subject: [PATCH 15/39] adapted public ip list command to align to expectations --- internal/cmd/public-ip/list/list.go | 27 ++++++++++++------------ internal/cmd/public-ip/list/list_test.go | 3 ++- 2 files changed, 16 insertions(+), 14 deletions(-) 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 c33162c1f..e2c840c24 100644 --- a/internal/cmd/public-ip/list/list_test.go +++ b/internal/cmd/public-ip/list/list_test.go @@ -174,6 +174,7 @@ func TestBuildRequest(t *testing.T) { func TestOutputResult(t *testing.T) { type args struct { outputFormat string + projectLabel string publicIps []iaas.PublicIp } tests := []struct { @@ -190,7 +191,7 @@ func TestOutputResult(t *testing.T) { params := testparams.NewTestParams() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.publicIps); (err != nil) != tt.wantErr { + if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.projectLabel, tt.args.publicIps); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) From e0db653825659e56db11dd880aec02d58fe3b4f5 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 15 Apr 2026 14:37:58 +0200 Subject: [PATCH 16/39] adapted security group list command to align to expectations --- internal/cmd/security-group/list/list.go | 27 +++++++++---------- internal/cmd/security-group/list/list_test.go | 3 ++- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/internal/cmd/security-group/list/list.go b/internal/cmd/security-group/list/list.go index d3788ee9c..71c7489ba 100644 --- a/internal/cmd/security-group/list/list.go +++ b/internal/cmd/security-group/list/list.go @@ -54,12 +54,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 +62,16 @@ 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 + return outputResult(params.Printer, model.OutputFormat, projectLabel, items) + }, } @@ -111,8 +106,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 5e413a7a1..c358a2dcd 100644 --- a/internal/cmd/security-group/list/list_test.go +++ b/internal/cmd/security-group/list/list_test.go @@ -182,6 +182,7 @@ func TestBuildRequest(t *testing.T) { func TestOutputResult(t *testing.T) { type args struct { outputFormat string + projectLabel string items []iaas.SecurityGroup } tests := []struct { @@ -198,7 +199,7 @@ func TestOutputResult(t *testing.T) { params := testparams.NewTestParams() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.items); (err != nil) != tt.wantErr { + if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.projectLabel, tt.args.items); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) From b3afc4b5f584762bd4400656690602016d7d67db Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 15 Apr 2026 14:50:15 +0200 Subject: [PATCH 17/39] added missing --limit flag for list security groups command --- internal/cmd/security-group/list/list.go | 29 +++++++++++++++++-- internal/cmd/security-group/list/list_test.go | 16 ++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/internal/cmd/security-group/list/list.go b/internal/cmd/security-group/list/list.go index 71c7489ba..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() @@ -70,6 +80,11 @@ func NewCmd(params *types.CmdParams) *cobra.Command { projectLabel = model.ProjectId } + // Truncate output + if model.Limit != nil && len(items) > int(*model.Limit) { + items = items[:*model.Limit] + } + return outputResult(params.Printer, model.OutputFormat, projectLabel, items) }, @@ -81,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) { @@ -89,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) diff --git a/internal/cmd/security-group/list/list_test.go b/internal/cmd/security-group/list/list_test.go index c358a2dcd..9677ec466 100644 --- a/internal/cmd/security-group/list/list_test.go +++ b/internal/cmd/security-group/list/list_test.go @@ -34,6 +34,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) @@ -49,6 +50,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) @@ -125,6 +127,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 { From f8d28299b3b5e13828227aa8a72ea455ada12ae3 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 15 Apr 2026 15:41:14 +0200 Subject: [PATCH 18/39] adapted volumes list command to align to expectations --- internal/cmd/volume/list/list.go | 23 ++++++++++++----------- internal/cmd/volume/list/list_test.go | 3 ++- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/internal/cmd/volume/list/list.go b/internal/cmd/volume/list/list.go index fa4b2c1f0..ed0192343 100644 --- a/internal/cmd/volume/list/list.go +++ b/internal/cmd/volume/list/list.go @@ -76,23 +76,20 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return fmt.Errorf("list volumes: %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 volumes 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) @@ -137,8 +134,12 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return req } -func outputResult(p *print.Printer, outputFormat string, volumes []iaas.Volume) error { +func outputResult(p *print.Printer, outputFormat, projectLabel string, volumes []iaas.Volume) error { return p.OutputResult(outputFormat, volumes, func() error { + if len(volumes) == 0 { + p.Outputf("No volumes found for project %q\n", projectLabel) + return nil + } table := tables.NewTable() table.SetHeader("ID", "Name", "Status", "Server", "Availability Zone", "Size (GB)") diff --git a/internal/cmd/volume/list/list_test.go b/internal/cmd/volume/list/list_test.go index 016d1dcf4..7fafae739 100644 --- a/internal/cmd/volume/list/list_test.go +++ b/internal/cmd/volume/list/list_test.go @@ -174,6 +174,7 @@ func TestBuildRequest(t *testing.T) { func TestOutputResult(t *testing.T) { type args struct { outputFormat string + projectLabel string volumes []iaas.Volume } tests := []struct { @@ -197,7 +198,7 @@ func TestOutputResult(t *testing.T) { params := testparams.NewTestParams() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.volumes); (err != nil) != tt.wantErr { + if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.projectLabel, tt.args.volumes); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) From bf4718f23abc3872529cf2d7fe24ad11c38d8f49 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 15 Apr 2026 16:04:48 +0200 Subject: [PATCH 19/39] adapted volume snapshots list command to align to expectations --- internal/cmd/volume/snapshot/list/list.go | 31 ++++++++----------- .../cmd/volume/snapshot/list/list_test.go | 5 +-- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/internal/cmd/volume/snapshot/list/list.go b/internal/cmd/volume/snapshot/list/list.go index a2d312b26..97b624189 100644 --- a/internal/cmd/volume/snapshot/list/list.go +++ b/internal/cmd/volume/snapshot/list/list.go @@ -72,25 +72,20 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return fmt.Errorf("list snapshots: %w", err) } - // Check if response is empty - 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 snapshots found for project %q\n", projectLabel) - return nil - } + snapshots := resp.GetItems() - snapshots := *resp.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 + } - // Apply limit if specified + // Truncate output if model.Limit != nil && int(*model.Limit) < len(snapshots) { snapshots = snapshots[:*model.Limit] } - return outputResult(params.Printer, model.OutputFormat, snapshots) + return outputResult(params.Printer, model.OutputFormat, projectLabel, snapshots) }, } @@ -137,12 +132,12 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return req } -func outputResult(p *print.Printer, outputFormat string, snapshots []iaas.Snapshot) error { - if snapshots == nil { - return fmt.Errorf("list snapshots response is empty") - } - +func outputResult(p *print.Printer, outputFormat, projectLabel string, snapshots []iaas.Snapshot) error { return p.OutputResult(outputFormat, snapshots, func() error { + if len(snapshots) == 0 { + p.Outputf("No snapshots found for project %q\n", projectLabel) + return nil + } table := tables.NewTable() table.SetHeader("ID", "NAME", "SIZE", "STATUS", "VOLUME ID", "LABELS", "CREATED AT", "UPDATED AT") diff --git a/internal/cmd/volume/snapshot/list/list_test.go b/internal/cmd/volume/snapshot/list/list_test.go index 0685c7447..090db90cf 100644 --- a/internal/cmd/volume/snapshot/list/list_test.go +++ b/internal/cmd/volume/snapshot/list/list_test.go @@ -181,6 +181,7 @@ func TestBuildRequest(t *testing.T) { func TestOutputResult(t *testing.T) { type args struct { outputFormat string + projectLabel string snapshots []iaas.Snapshot } tests := []struct { @@ -191,7 +192,7 @@ func TestOutputResult(t *testing.T) { { name: "empty", args: args{}, - wantErr: true, + wantErr: false, }, { name: "empty snapshot in slice", @@ -218,7 +219,7 @@ func TestOutputResult(t *testing.T) { params := testparams.NewTestParams() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.snapshots); (err != nil) != tt.wantErr { + if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.projectLabel, tt.args.snapshots); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) From a888af1cab7d46804c7b36ff0dcbddd66516094f Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 15 Apr 2026 16:13:49 +0200 Subject: [PATCH 20/39] adapted volume performance class list command to align to expectations --- .../cmd/volume/performance-class/list/list.go | 23 ++++++++++--------- .../performance-class/list/list_test.go | 3 ++- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/internal/cmd/volume/performance-class/list/list.go b/internal/cmd/volume/performance-class/list/list.go index ae62dd65d..9e4f9a453 100644 --- a/internal/cmd/volume/performance-class/list/list.go +++ b/internal/cmd/volume/performance-class/list/list.go @@ -77,23 +77,20 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return fmt.Errorf("list volume performance classes: %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 volume performance class 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) @@ -138,8 +135,12 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return req } -func outputResult(p *print.Printer, outputFormat string, performanceClasses []iaas.VolumePerformanceClass) error { +func outputResult(p *print.Printer, outputFormat, projectLabel string, performanceClasses []iaas.VolumePerformanceClass) error { return p.OutputResult(outputFormat, performanceClasses, func() error { + if len(performanceClasses) == 0 { + p.Outputf("No volume performance class found for project %q\n", projectLabel) + return nil + } table := tables.NewTable() table.SetHeader("Name", "Description") diff --git a/internal/cmd/volume/performance-class/list/list_test.go b/internal/cmd/volume/performance-class/list/list_test.go index 5a6b01ce9..0ad6eb32b 100644 --- a/internal/cmd/volume/performance-class/list/list_test.go +++ b/internal/cmd/volume/performance-class/list/list_test.go @@ -174,6 +174,7 @@ func TestBuildRequest(t *testing.T) { func TestOutputResult(t *testing.T) { type args struct { outputFormat string + projectLabel string performanceClasses []iaas.VolumePerformanceClass } tests := []struct { @@ -197,7 +198,7 @@ func TestOutputResult(t *testing.T) { params := testparams.NewTestParams() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.performanceClasses); (err != nil) != tt.wantErr { + if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.projectLabel, tt.args.performanceClasses); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) From 02db11e4c32ce8654e627770ee3c131ed2ab6174 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 15 Apr 2026 16:24:45 +0200 Subject: [PATCH 21/39] adapted volume backups list command to align to expectations --- internal/cmd/volume/backup/list/list.go | 28 +++++++++----------- internal/cmd/volume/backup/list/list_test.go | 5 ++-- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/internal/cmd/volume/backup/list/list.go b/internal/cmd/volume/backup/list/list.go index 9da088d13..a555d8fb9 100644 --- a/internal/cmd/volume/backup/list/list.go +++ b/internal/cmd/volume/backup/list/list.go @@ -72,23 +72,21 @@ func NewCmd(params *types.CmdParams) *cobra.Command { if err != nil { return fmt.Errorf("get backups: %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 backups found for project %s\n", projectLabel) - return nil + + backups := 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 } - backups := *resp.Items // Truncate output if model.Limit != nil && len(backups) > int(*model.Limit) { backups = backups[:*model.Limit] } - return outputResult(params.Printer, model.OutputFormat, backups) + return outputResult(params.Printer, model.OutputFormat, projectLabel, backups) }, } @@ -137,12 +135,12 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return req } -func outputResult(p *print.Printer, outputFormat string, backups []iaas.Backup) error { - if backups == nil { - return fmt.Errorf("backups is empty") - } - +func outputResult(p *print.Printer, outputFormat, projectLabel string, backups []iaas.Backup) error { return p.OutputResult(outputFormat, backups, func() error { + if len(backups) == 0 { + p.Outputf("No backups found for project %s\n", projectLabel) + return nil + } table := tables.NewTable() table.SetHeader("ID", "NAME", "SIZE", "STATUS", "SNAPSHOT ID", "VOLUME ID", "AVAILABILITY ZONE", "LABELS", "CREATED AT", "UPDATED AT") diff --git a/internal/cmd/volume/backup/list/list_test.go b/internal/cmd/volume/backup/list/list_test.go index 489821bfd..debb31c96 100644 --- a/internal/cmd/volume/backup/list/list_test.go +++ b/internal/cmd/volume/backup/list/list_test.go @@ -160,6 +160,7 @@ func TestBuildRequest(t *testing.T) { func TestOutputResult(t *testing.T) { type args struct { outputFormat string + projectLabel string backups []iaas.Backup } tests := []struct { @@ -170,7 +171,7 @@ func TestOutputResult(t *testing.T) { { name: "empty", args: args{}, - wantErr: true, + wantErr: false, }, { name: "empty backup in slice", @@ -190,7 +191,7 @@ func TestOutputResult(t *testing.T) { params := testparams.NewTestParams() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.backups); (err != nil) != tt.wantErr { + if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.projectLabel, tt.args.backups); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) From 42eafa4b8bd22ec8c1d4c230b93bc5ba527906f9 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 15 Apr 2026 16:41:48 +0200 Subject: [PATCH 22/39] fixed order of params --- internal/cmd/network-area/list/list.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/cmd/network-area/list/list.go b/internal/cmd/network-area/list/list.go index 15e1a9c11..93f9163d7 100644 --- a/internal/cmd/network-area/list/list.go +++ b/internal/cmd/network-area/list/list.go @@ -103,7 +103,7 @@ func NewCmd(params *types.CmdParams) *cobra.Command { items = items[:*model.Limit] } - return outputResult(params.Printer, orgLabel, model.OutputFormat, items) + return outputResult(params.Printer, model.OutputFormat, orgLabel, items) }, } configureFlags(cmd) @@ -148,7 +148,7 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return req } -func outputResult(p *print.Printer, orgLabel, outputFormat string, networkAreas []iaas.NetworkArea) error { +func outputResult(p *print.Printer, outputFormat, orgLabel 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) From 48e9f80a2c21b050d356f715878c98ebd4bf48de Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 15 Apr 2026 16:55:45 +0200 Subject: [PATCH 23/39] adapted network area network ranges list command to align to expectations --- .../network-area/network-range/list/list.go | 25 ++++++++++--------- .../network-range/list/list_test.go | 7 +++--- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/internal/cmd/network-area/network-range/list/list.go b/internal/cmd/network-area/network-range/list/list.go index 4ad161d30..593c3de66 100644 --- a/internal/cmd/network-area/network-range/list/list.go +++ b/internal/cmd/network-area/network-range/list/list.go @@ -75,24 +75,21 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return fmt.Errorf("list network ranges: %w", err) } - if resp.Items == nil || len(*resp.Items) == 0 { - var networkAreaLabel string - networkAreaLabel, err = iaasUtils.GetNetworkAreaName(ctx, apiClient, *model.OrganizationId, *model.NetworkAreaId) - if err != nil { - params.Printer.Debug(print.ErrorLevel, "get organization name: %v", err) - networkAreaLabel = *model.NetworkAreaId - } - params.Printer.Info("No network ranges found for SNA %q\n", networkAreaLabel) - return nil + items := resp.GetItems() + + var networkAreaLabel string + networkAreaLabel, err = iaasUtils.GetNetworkAreaName(ctx, apiClient, *model.OrganizationId, *model.NetworkAreaId) + if err != nil { + params.Printer.Debug(print.ErrorLevel, "get organization name: %v", err) + networkAreaLabel = *model.NetworkAreaId } // 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, networkAreaLabel, items) }, } configureFlags(cmd) @@ -133,8 +130,12 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return apiClient.ListNetworkAreaRanges(ctx, *model.OrganizationId, *model.NetworkAreaId, model.Region) } -func outputResult(p *print.Printer, outputFormat string, networkRanges []iaas.NetworkRange) error { +func outputResult(p *print.Printer, outputFormat, networkAreaLabel string, networkRanges []iaas.NetworkRange) error { return p.OutputResult(outputFormat, networkRanges, func() error { + if len(networkRanges) == 0 { + p.Outputf("No network ranges found for SNA %q\n", networkAreaLabel) + return nil + } table := tables.NewTable() table.SetHeader("ID", "Network Range") diff --git a/internal/cmd/network-area/network-range/list/list_test.go b/internal/cmd/network-area/network-range/list/list_test.go index 824b28a10..1bf8f1094 100644 --- a/internal/cmd/network-area/network-range/list/list_test.go +++ b/internal/cmd/network-area/network-range/list/list_test.go @@ -183,8 +183,9 @@ func TestBuildRequest(t *testing.T) { func TestOutputResult(t *testing.T) { type args struct { - outputFormat string - networkRanges []iaas.NetworkRange + outputFormat string + networkAreaLabel string + networkRanges []iaas.NetworkRange } tests := []struct { name string @@ -214,7 +215,7 @@ func TestOutputResult(t *testing.T) { params := testparams.NewTestParams() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.networkRanges); (err != nil) != tt.wantErr { + if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.networkAreaLabel, tt.args.networkRanges); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) From b663d3d619db59135194bd9536231e359ca759e8 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 15 Apr 2026 17:22:42 +0200 Subject: [PATCH 24/39] adapted network area routes list command to align to expectations --- internal/cmd/network-area/route/list/list.go | 25 ++++++++++--------- .../cmd/network-area/route/list/list_test.go | 7 +++--- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/internal/cmd/network-area/route/list/list.go b/internal/cmd/network-area/route/list/list.go index 8cadbdef7..4506c38a7 100644 --- a/internal/cmd/network-area/route/list/list.go +++ b/internal/cmd/network-area/route/list/list.go @@ -74,24 +74,21 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return fmt.Errorf("list static routes: %w", err) } - if resp.Items == nil || len(*resp.Items) == 0 { - var networkAreaLabel string - networkAreaLabel, err = iaasUtils.GetNetworkAreaName(ctx, apiClient, *model.OrganizationId, *model.NetworkAreaId) - if err != nil { - params.Printer.Debug(print.ErrorLevel, "get network area name: %v", err) - networkAreaLabel = *model.NetworkAreaId - } - params.Printer.Info("No static routes found for STACKIT Network Area %q\n", networkAreaLabel) - return nil + items := resp.GetItems() + + var networkAreaLabel string + networkAreaLabel, err = iaasUtils.GetNetworkAreaName(ctx, apiClient, *model.OrganizationId, *model.NetworkAreaId) + if err != nil { + params.Printer.Debug(print.ErrorLevel, "get network area name: %v", err) + networkAreaLabel = *model.NetworkAreaId } // 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, networkAreaLabel, items) }, } configureFlags(cmd) @@ -132,8 +129,12 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return apiClient.ListNetworkAreaRoutes(ctx, *model.OrganizationId, *model.NetworkAreaId, model.Region) } -func outputResult(p *print.Printer, outputFormat string, routes []iaas.Route) error { +func outputResult(p *print.Printer, outputFormat, networkAreaLabel string, routes []iaas.Route) error { return p.OutputResult(outputFormat, routes, func() error { + if len(routes) == 0 { + p.Outputf("No static routes found for STACKIT Network Area %q\n", networkAreaLabel) + return nil + } table := tables.NewTable() table.SetHeader("Static Route ID", "Next Hop", "Next Hop Type", "Destination") diff --git a/internal/cmd/network-area/route/list/list_test.go b/internal/cmd/network-area/route/list/list_test.go index 2d6998b89..88e8db79d 100644 --- a/internal/cmd/network-area/route/list/list_test.go +++ b/internal/cmd/network-area/route/list/list_test.go @@ -183,8 +183,9 @@ func TestBuildRequest(t *testing.T) { func TestOutputResult(t *testing.T) { type args struct { - outputFormat string - routes []iaas.Route + outputFormat string + networkAreaLabel string + routes []iaas.Route } tests := []struct { name string @@ -232,7 +233,7 @@ func TestOutputResult(t *testing.T) { params := testparams.NewTestParams() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.routes); (err != nil) != tt.wantErr { + if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.networkAreaLabel, tt.args.routes); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) From 777630a1cb66815722de60086ce4b84996badd38 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 15 Apr 2026 17:43:25 +0200 Subject: [PATCH 25/39] adapted security group rules list command to align to expectations --- internal/cmd/security-group/rule/list/list.go | 33 ++++++++++--------- .../cmd/security-group/rule/list/list_test.go | 4 ++- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/internal/cmd/security-group/rule/list/list.go b/internal/cmd/security-group/rule/list/list.go index 1d39e5ed8..b552a1e73 100644 --- a/internal/cmd/security-group/rule/list/list.go +++ b/internal/cmd/security-group/rule/list/list.go @@ -74,29 +74,26 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return fmt.Errorf("list security group rules: %w", err) } - if resp.Items == nil || len(*resp.Items) == 0 { - securityGroupLabel, err := iaasUtils.GetSecurityGroupName(ctx, apiClient, model.ProjectId, model.Region, model.SecurityGroupId) - if err != nil { - params.Printer.Debug(print.ErrorLevel, "get security group name: %v", err) - securityGroupLabel = model.SecurityGroupId - } + 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 - } - params.Printer.Info("No rules found in security group %q for project %q\n", securityGroupLabel, projectLabel) - return nil + securityGroupLabel, err := iaasUtils.GetSecurityGroupName(ctx, apiClient, model.ProjectId, model.Region, model.SecurityGroupId) + if err != nil { + params.Printer.Debug(print.ErrorLevel, "get security group name: %v", err) + securityGroupLabel = model.SecurityGroupId + } + + 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, securityGroupLabel, items) }, } configureFlags(cmd) @@ -139,8 +136,12 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return apiClient.ListSecurityGroupRules(ctx, model.ProjectId, model.Region, model.SecurityGroupId) } -func outputResult(p *print.Printer, outputFormat string, securityGroupRules []iaas.SecurityGroupRule) error { +func outputResult(p *print.Printer, outputFormat, projectLabel, securityGroupLabel string, securityGroupRules []iaas.SecurityGroupRule) error { return p.OutputResult(outputFormat, securityGroupRules, func() error { + if len(securityGroupRules) == 0 { + p.Outputf("No rules found in security group %q for project %q\n", securityGroupLabel, projectLabel) + return nil + } table := tables.NewTable() table.SetHeader("ID", "ETHER TYPE", "DIRECTION", "PROTOCOL", "REMOTE SECURITY GROUP ID") diff --git a/internal/cmd/security-group/rule/list/list_test.go b/internal/cmd/security-group/rule/list/list_test.go index d5c3abd0b..8833b4ae7 100644 --- a/internal/cmd/security-group/rule/list/list_test.go +++ b/internal/cmd/security-group/rule/list/list_test.go @@ -184,6 +184,8 @@ func TestBuildRequest(t *testing.T) { func TestOutputResult(t *testing.T) { type args struct { outputFormat string + projectLabel string + securityGroupLabel string securityGroupRules []iaas.SecurityGroupRule } tests := []struct { @@ -200,7 +202,7 @@ func TestOutputResult(t *testing.T) { params := testparams.NewTestParams() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.securityGroupRules); (err != nil) != tt.wantErr { + if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.projectLabel, tt.args.securityGroupLabel, tt.args.securityGroupRules); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) From 8885e051d592b9ba31d7a0c4f92075c7793419a0 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Mon, 20 Apr 2026 11:13:05 +0200 Subject: [PATCH 26/39] adapted server machine-types list command to align to expectations --- internal/cmd/server/machine-type/list/list.go | 20 +++++++++---------- .../cmd/server/machine-type/list/list_test.go | 3 ++- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/internal/cmd/server/machine-type/list/list.go b/internal/cmd/server/machine-type/list/list.go index c134edd55..1ead9fea7 100644 --- a/internal/cmd/server/machine-type/list/list.go +++ b/internal/cmd/server/machine-type/list/list.go @@ -80,14 +80,10 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return fmt.Errorf("read machine-types: %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 machine-types found for project %q\n", projectLabel) - return nil + 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 } // limit output @@ -95,7 +91,7 @@ func NewCmd(params *types.CmdParams) *cobra.Command { *resp.Items = (*resp.Items)[:*model.Limit] } - return outputResult(params.Printer, model.OutputFormat, *resp) + return outputResult(params.Printer, model.OutputFormat, projectLabel, *resp) }, } @@ -140,8 +136,12 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return req } -func outputResult(p *print.Printer, outputFormat string, machineTypes iaas.MachineTypeListResponse) error { +func outputResult(p *print.Printer, outputFormat, projectLabel string, machineTypes iaas.MachineTypeListResponse) error { return p.OutputResult(outputFormat, machineTypes, func() error { + if machineTypes.Items == nil || len(*machineTypes.Items) == 0 { + p.Outputf("No machine-types found for project %q\n", projectLabel) + return nil + } table := tables.NewTable() table.SetTitle("Machine-Types") table.SetHeader("NAME", "VCPUS", "RAM (GB)", "DESCRIPTION", "EXTRA SPECS") diff --git a/internal/cmd/server/machine-type/list/list_test.go b/internal/cmd/server/machine-type/list/list_test.go index ec1f2094a..23913272f 100644 --- a/internal/cmd/server/machine-type/list/list_test.go +++ b/internal/cmd/server/machine-type/list/list_test.go @@ -179,6 +179,7 @@ func TestBuildRequest(t *testing.T) { func TestOutputResult(t *testing.T) { type args struct { outputFormat string + projectLabel string machineTypes iaas.MachineTypeListResponse } tests := []struct { @@ -222,7 +223,7 @@ func TestOutputResult(t *testing.T) { params := testparams.NewTestParams() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.machineTypes); (err != nil) != tt.wantErr { + if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.projectLabel, tt.args.machineTypes); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) From e72a115dc51eed12eccbafe8b51c0d32541b12d4 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Mon, 20 Apr 2026 12:09:39 +0200 Subject: [PATCH 27/39] adapted server network-interfaces list command to align to expectations --- .../cmd/server/network-interface/list/list.go | 27 ++++++++++--------- .../network-interface/list/list_test.go | 3 ++- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/internal/cmd/server/network-interface/list/list.go b/internal/cmd/server/network-interface/list/list.go index c154f89b3..012a359f0 100644 --- a/internal/cmd/server/network-interface/list/list.go +++ b/internal/cmd/server/network-interface/list/list.go @@ -72,25 +72,22 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return fmt.Errorf("list attached network interfaces: %w", err) } - if resp.Items == nil || len(*resp.Items) == 0 { - serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) - if err != nil { - params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) - serverLabel = model.ServerId - } else if serverLabel == "" { - serverLabel = model.ServerId - } - params.Printer.Info("No attached network interfaces found for server %q\n", serverLabel) - return nil + items := resp.GetItems() + + serverLabel, err := iaasUtils.GetServerName(ctx, apiClient, model.ProjectId, model.Region, model.ServerId) + if err != nil { + params.Printer.Debug(print.ErrorLevel, "get server name: %v", err) + serverLabel = model.ServerId + } else if serverLabel == "" { + serverLabel = model.ServerId } // Truncate output - items := *resp.Items if model.Limit != nil && len(items) > int(*model.Limit) { items = items[:*model.Limit] } - return outputResult(params.Printer, model.OutputFormat, model.ServerId, items) + return outputResult(params.Printer, model.OutputFormat, model.ServerId, serverLabel, items) }, } configureFlags(cmd) @@ -133,8 +130,12 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return apiClient.ListServerNICs(ctx, model.ProjectId, model.Region, model.ServerId) } -func outputResult(p *print.Printer, outputFormat, serverId string, serverNics []iaas.NIC) error { +func outputResult(p *print.Printer, outputFormat, serverId, serverLabel string, serverNics []iaas.NIC) error { return p.OutputResult(outputFormat, serverNics, func() error { + if len(serverNics) == 0 { + p.Outputf("No attached network interfaces found for server %q\n", serverLabel) + return nil + } table := tables.NewTable() table.SetHeader("NIC ID", "SERVER ID") diff --git a/internal/cmd/server/network-interface/list/list_test.go b/internal/cmd/server/network-interface/list/list_test.go index 5ce9f8995..471f19681 100644 --- a/internal/cmd/server/network-interface/list/list_test.go +++ b/internal/cmd/server/network-interface/list/list_test.go @@ -180,6 +180,7 @@ func TestOutputResult(t *testing.T) { type args struct { outputFormat string serverId string + serverLabel string serverNics []iaas.NIC } tests := []struct { @@ -205,7 +206,7 @@ func TestOutputResult(t *testing.T) { params := testparams.NewTestParams() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.serverId, tt.args.serverNics); (err != nil) != tt.wantErr { + if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.serverId, tt.args.serverLabel, tt.args.serverNics); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) From 4083b93766bc501a00f173873cf67a4f65b87683 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Mon, 20 Apr 2026 12:38:56 +0200 Subject: [PATCH 28/39] adapted server service accounts list command to align to expectations --- internal/cmd/server/service-account/list/list.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/cmd/server/service-account/list/list.go b/internal/cmd/server/service-account/list/list.go index a8188b65b..28c2e701a 100644 --- a/internal/cmd/server/service-account/list/list.go +++ b/internal/cmd/server/service-account/list/list.go @@ -78,10 +78,6 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return fmt.Errorf("list service accounts: %w", err) } serviceAccounts := *resp.Items - if len(serviceAccounts) == 0 { - params.Printer.Info("No service accounts found for server %s\n", serverName) - return nil - } if model.Limit != nil && len(serviceAccounts) > int(*model.Limit) { serviceAccounts = serviceAccounts[:int(*model.Limit)] @@ -133,6 +129,10 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli func outputResult(p *print.Printer, outputFormat, serverId, serverName string, serviceAccounts []string) error { return p.OutputResult(outputFormat, serviceAccounts, func() error { + if len(serviceAccounts) == 0 { + p.Info("No service accounts found for server %s\n", serverName) + return nil + } table := tables.NewTable() table.SetHeader("SERVER ID", "SERVER NAME", "SERVICE ACCOUNT") for i := range serviceAccounts { @@ -140,7 +140,7 @@ func outputResult(p *print.Printer, outputFormat, serverId, serverName string, s } err := table.Display(p) if err != nil { - return fmt.Errorf("rednder table: %w", err) + return fmt.Errorf("render table: %w", err) } return nil }) From ee1b411fbb2bf374df6efdfc55b2ecba532aa599 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Mon, 20 Apr 2026 12:49:38 +0200 Subject: [PATCH 29/39] adapted server volumes list command to align to expectations --- internal/cmd/server/volume/list/list.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/internal/cmd/server/volume/list/list.go b/internal/cmd/server/volume/list/list.go index 995303bd7..2cd23fd02 100644 --- a/internal/cmd/server/volume/list/list.go +++ b/internal/cmd/server/volume/list/list.go @@ -71,11 +71,8 @@ func NewCmd(params *types.CmdParams) *cobra.Command { if err != nil { return fmt.Errorf("list server volumes: %w", err) } - volumes := *resp.Items - if len(volumes) == 0 { - params.Printer.Info("No volumes found for server %s\n", serverLabel) - return nil - } + + volumes := resp.GetItems() // get volume names var volumeNames []string @@ -124,6 +121,10 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli func outputResult(p *print.Printer, outputFormat, serverLabel string, volumeNames []string, volumes []iaas.VolumeAttachment) error { return p.OutputResult(outputFormat, volumes, func() error { + if len(volumes) == 0 { + p.Outputf("No volumes found for server %s\n", serverLabel) + return nil + } table := tables.NewTable() table.SetHeader("SERVER ID", "SERVER NAME", "VOLUME ID", "VOLUME NAME") for i := range volumes { From 9b8c40dd2156edbf0c62d7900d9676a05fbb9c64 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 22 Apr 2026 10:45:04 +0200 Subject: [PATCH 30/39] removed unnecessary check in public ip --- internal/cmd/public-ip/list/list.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/cmd/public-ip/list/list.go b/internal/cmd/public-ip/list/list.go index a75d94f40..8a9e102db 100644 --- a/internal/cmd/public-ip/list/list.go +++ b/internal/cmd/public-ip/list/list.go @@ -83,8 +83,6 @@ func NewCmd(params *types.CmdParams) *cobra.Command { if err != nil { params.Printer.Debug(print.ErrorLevel, "get project name: %v", err) projectLabel = model.ProjectId - } else if projectLabel == "" { - projectLabel = model.ProjectId } // Truncate output From de440de6f962e85cd2fc4c1e8714b8f45f7609c9 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 22 Apr 2026 13:39:23 +0200 Subject: [PATCH 31/39] regenerate docs --- docs/stackit_security-group_list.md | 11 +++++++++-- internal/cmd/quota/list/list.go | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/stackit_security-group_list.md b/docs/stackit_security-group_list.md index 990f01364..20f86bf88 100644 --- a/docs/stackit_security-group_list.md +++ b/docs/stackit_security-group_list.md @@ -13,11 +13,17 @@ stackit security-group list [flags] ### Examples ``` - List all groups + Lists all security groups $ stackit security-group list - List groups with labels + Lists security groups with labels $ stackit security-group list --label-selector label1=value1,label2=value2 + + Lists all security groups in JSON format + $ stackit security-group list --output-format json + + Lists up to 10 security groups + $ stackit security-group list --limit 10 ``` ### Options @@ -25,6 +31,7 @@ stackit security-group list [flags] ``` -h, --help Help for "stackit security-group list" --label-selector string Filter by label + --limit int Maximum number of entries to list ``` ### Options inherited from parent commands diff --git a/internal/cmd/quota/list/list.go b/internal/cmd/quota/list/list.go index ebb1ca353..099fc9c2f 100644 --- a/internal/cmd/quota/list/list.go +++ b/internal/cmd/quota/list/list.go @@ -64,7 +64,7 @@ func NewCmd(params *types.CmdParams) *cobra.Command { if err != nil { return fmt.Errorf("list quotas: %w", err) } - + response.Quotas = nil if items := response.Quotas; items == nil { params.Printer.Info("No quotas found for project %q", projectLabel) } else { From f25cdc0747edc883e46d88016c7a031fd79079bd Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 22 Apr 2026 13:45:50 +0200 Subject: [PATCH 32/39] fixed linter issue --- internal/cmd/security-group/list/list.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/cmd/security-group/list/list.go b/internal/cmd/security-group/list/list.go index 6613a3864..32e71ec48 100644 --- a/internal/cmd/security-group/list/list.go +++ b/internal/cmd/security-group/list/list.go @@ -86,7 +86,6 @@ func NewCmd(params *types.CmdParams) *cobra.Command { } return outputResult(params.Printer, model.OutputFormat, projectLabel, items) - }, } From 2a3e7ee93fa4d9388e4ef4f632b08f16e94dbf7a Mon Sep 17 00:00:00 2001 From: Jan Obernberger <52105660+j1n-o9r@users.noreply.github.com> Date: Wed, 22 Apr 2026 16:11:53 +0200 Subject: [PATCH 33/39] Update internal/cmd/key-pair/list/list.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ruben Hönle --- internal/cmd/key-pair/list/list.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/cmd/key-pair/list/list.go b/internal/cmd/key-pair/list/list.go index 6abc21158..0fdd1e1bb 100644 --- a/internal/cmd/key-pair/list/list.go +++ b/internal/cmd/key-pair/list/list.go @@ -135,7 +135,7 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli 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) + p.Outputf("No key pairs found\n") return nil } From 884f8c7248bcac10c2f159052ffd084be1440381 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 22 Apr 2026 16:45:28 +0200 Subject: [PATCH 34/39] (fix): remove mistakenly added project label from key pairs list command --- internal/cmd/key-pair/list/list.go | 11 ++--------- internal/cmd/key-pair/list/list_test.go | 3 +-- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/internal/cmd/key-pair/list/list.go b/internal/cmd/key-pair/list/list.go index 0fdd1e1bb..5aaf4d508 100644 --- a/internal/cmd/key-pair/list/list.go +++ b/internal/cmd/key-pair/list/list.go @@ -5,7 +5,6 @@ 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" @@ -80,18 +79,12 @@ func NewCmd(params *types.CmdParams) *cobra.Command { 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 if model.Limit != nil && len(items) > int(*model.Limit) { items = items[:*model.Limit] } - return outputResult(params.Printer, model.OutputFormat, projectLabel, items) + return outputResult(params.Printer, model.OutputFormat, items) }, } configureFlags(cmd) @@ -132,7 +125,7 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli return req } -func outputResult(p *print.Printer, outputFormat, projectLabel string, keyPairs []iaas.Keypair) error { +func outputResult(p *print.Printer, outputFormat string, keyPairs []iaas.Keypair) error { return p.OutputResult(outputFormat, keyPairs, func() error { if len(keyPairs) == 0 { p.Outputf("No key pairs found\n") diff --git a/internal/cmd/key-pair/list/list_test.go b/internal/cmd/key-pair/list/list_test.go index 665e1cfad..779b57d49 100644 --- a/internal/cmd/key-pair/list/list_test.go +++ b/internal/cmd/key-pair/list/list_test.go @@ -153,7 +153,6 @@ func TestBuildRequest(t *testing.T) { func Test_outputResult(t *testing.T) { type args struct { outputFormat string - projectLabel string keyPairs []iaas.Keypair } tests := []struct { @@ -177,7 +176,7 @@ func Test_outputResult(t *testing.T) { t.Run(tt.name, func(t *testing.T) { params := testparams.NewTestParams() - if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.projectLabel, tt.args.keyPairs); (err != nil) != tt.wantErr { + if err := outputResult(params.Printer, tt.args.outputFormat, tt.args.keyPairs); (err != nil) != tt.wantErr { t.Errorf("outputResult() error = %v, wantErr %v", err, tt.wantErr) } }) From d24108d1ad82cbb51da640c2e80a9c1e1b2a4bfa Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 22 Apr 2026 17:09:13 +0200 Subject: [PATCH 35/39] (fix): made orgLabel in model from pointer to string for not having to deal with nil values since it is required anyways --- internal/cmd/network-area/list/list.go | 12 ++++++------ internal/cmd/network-area/list/list_test.go | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/internal/cmd/network-area/list/list.go b/internal/cmd/network-area/list/list.go index 93f9163d7..f473fc981 100644 --- a/internal/cmd/network-area/list/list.go +++ b/internal/cmd/network-area/list/list.go @@ -32,7 +32,7 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel Limit *int64 - OrganizationId *string + OrganizationId string LabelSelector *string } @@ -85,17 +85,17 @@ func NewCmd(params *types.CmdParams) *cobra.Command { var orgLabel string rmApiClient, err := rmClient.ConfigureClient(params.Printer, params.CliVersion) if err == nil { - orgLabel, err = rmUtils.GetOrganizationName(ctx, rmApiClient, *model.OrganizationId) + orgLabel, err = rmUtils.GetOrganizationName(ctx, rmApiClient, model.OrganizationId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get organization name: %v", err) - orgLabel = *model.OrganizationId + orgLabel = model.OrganizationId } } else { params.Printer.Debug(print.ErrorLevel, "configure resource manager client: %v", err) } if orgLabel == "" { - orgLabel = *model.OrganizationId + orgLabel = model.OrganizationId } // Truncate output @@ -132,7 +132,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, model := inputModel{ GlobalFlagModel: globalFlags, Limit: limit, - OrganizationId: flags.FlagToStringPointer(p, cmd, organizationIdFlag), + OrganizationId: flags.FlagToStringValue(p, cmd, organizationIdFlag), LabelSelector: flags.FlagToStringPointer(p, cmd, labelSelectorFlag), } @@ -141,7 +141,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListNetworkAreasRequest { - req := apiClient.ListNetworkAreas(ctx, *model.OrganizationId) + req := apiClient.ListNetworkAreas(ctx, model.OrganizationId) if model.LabelSelector != nil { req = req.LabelSelector(*model.LabelSelector) } diff --git a/internal/cmd/network-area/list/list_test.go b/internal/cmd/network-area/list/list_test.go index 2cd2be0ac..096ac43eb 100644 --- a/internal/cmd/network-area/list/list_test.go +++ b/internal/cmd/network-area/list/list_test.go @@ -39,7 +39,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { GlobalFlagModel: &globalflags.GlobalFlagModel{ Verbosity: globalflags.VerbosityDefault, }, - OrganizationId: &testOrganizationId, + OrganizationId: testOrganizationId, Limit: utils.Ptr(int64(10)), LabelSelector: utils.Ptr(testLabelSelector), } From dac4b2a0e496dd5edf1e3b37354da1cbe8a73558 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 22 Apr 2026 17:18:40 +0200 Subject: [PATCH 36/39] (fix): remove unnecessarily declaring variable with explicit statement --- internal/cmd/network-area/network-range/list/list.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/cmd/network-area/network-range/list/list.go b/internal/cmd/network-area/network-range/list/list.go index 593c3de66..fd52c3768 100644 --- a/internal/cmd/network-area/network-range/list/list.go +++ b/internal/cmd/network-area/network-range/list/list.go @@ -77,8 +77,7 @@ func NewCmd(params *types.CmdParams) *cobra.Command { items := resp.GetItems() - var networkAreaLabel string - networkAreaLabel, err = iaasUtils.GetNetworkAreaName(ctx, apiClient, *model.OrganizationId, *model.NetworkAreaId) + networkAreaLabel, err := iaasUtils.GetNetworkAreaName(ctx, apiClient, *model.OrganizationId, *model.NetworkAreaId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get organization name: %v", err) networkAreaLabel = *model.NetworkAreaId From 3e80ea67d8a17ca1a2b6d5bd2eff7d96b5ebda36 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 22 Apr 2026 17:44:11 +0200 Subject: [PATCH 37/39] (fix): made OrganizationId and NetworkAreaId in model from pointer to string for not having to deal with nil values since it is required anyways --- .../cmd/network-area/network-range/list/list.go | 14 +++++++------- .../network-area/network-range/list/list_test.go | 4 ++-- internal/cmd/network-area/route/list/list.go | 14 +++++++------- internal/cmd/network-area/route/list/list_test.go | 4 ++-- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/internal/cmd/network-area/network-range/list/list.go b/internal/cmd/network-area/network-range/list/list.go index fd52c3768..cfda99ad3 100644 --- a/internal/cmd/network-area/network-range/list/list.go +++ b/internal/cmd/network-area/network-range/list/list.go @@ -31,8 +31,8 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel Limit *int64 - OrganizationId *string - NetworkAreaId *string + OrganizationId string + NetworkAreaId string } func NewCmd(params *types.CmdParams) *cobra.Command { @@ -77,10 +77,10 @@ func NewCmd(params *types.CmdParams) *cobra.Command { items := resp.GetItems() - networkAreaLabel, err := iaasUtils.GetNetworkAreaName(ctx, apiClient, *model.OrganizationId, *model.NetworkAreaId) + networkAreaLabel, err := iaasUtils.GetNetworkAreaName(ctx, apiClient, model.OrganizationId, model.NetworkAreaId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get organization name: %v", err) - networkAreaLabel = *model.NetworkAreaId + networkAreaLabel = model.NetworkAreaId } // Truncate output @@ -117,8 +117,8 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, model := inputModel{ GlobalFlagModel: globalFlags, Limit: limit, - OrganizationId: flags.FlagToStringPointer(p, cmd, organizationIdFlag), - NetworkAreaId: flags.FlagToStringPointer(p, cmd, networkAreaIdFlag), + OrganizationId: flags.FlagToStringValue(p, cmd, organizationIdFlag), + NetworkAreaId: flags.FlagToStringValue(p, cmd, networkAreaIdFlag), } p.DebugInputModel(model) @@ -126,7 +126,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListNetworkAreaRangesRequest { - return apiClient.ListNetworkAreaRanges(ctx, *model.OrganizationId, *model.NetworkAreaId, model.Region) + return apiClient.ListNetworkAreaRanges(ctx, model.OrganizationId, model.NetworkAreaId, model.Region) } func outputResult(p *print.Printer, outputFormat, networkAreaLabel string, networkRanges []iaas.NetworkRange) error { diff --git a/internal/cmd/network-area/network-range/list/list_test.go b/internal/cmd/network-area/network-range/list/list_test.go index 1bf8f1094..e0848648b 100644 --- a/internal/cmd/network-area/network-range/list/list_test.go +++ b/internal/cmd/network-area/network-range/list/list_test.go @@ -46,8 +46,8 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { Region: testRegion, Verbosity: globalflags.VerbosityDefault, }, - OrganizationId: &testOrganizationId, - NetworkAreaId: &testNetworkAreaId, + OrganizationId: testOrganizationId, + NetworkAreaId: testNetworkAreaId, Limit: utils.Ptr(int64(10)), } for _, mod := range mods { diff --git a/internal/cmd/network-area/route/list/list.go b/internal/cmd/network-area/route/list/list.go index 4506c38a7..813f09c10 100644 --- a/internal/cmd/network-area/route/list/list.go +++ b/internal/cmd/network-area/route/list/list.go @@ -30,8 +30,8 @@ const ( type inputModel struct { *globalflags.GlobalFlagModel Limit *int64 - OrganizationId *string - NetworkAreaId *string + OrganizationId string + NetworkAreaId string } func NewCmd(params *types.CmdParams) *cobra.Command { @@ -77,10 +77,10 @@ func NewCmd(params *types.CmdParams) *cobra.Command { items := resp.GetItems() var networkAreaLabel string - networkAreaLabel, err = iaasUtils.GetNetworkAreaName(ctx, apiClient, *model.OrganizationId, *model.NetworkAreaId) + networkAreaLabel, err = iaasUtils.GetNetworkAreaName(ctx, apiClient, model.OrganizationId, model.NetworkAreaId) if err != nil { params.Printer.Debug(print.ErrorLevel, "get network area name: %v", err) - networkAreaLabel = *model.NetworkAreaId + networkAreaLabel = model.NetworkAreaId } // Truncate output @@ -117,8 +117,8 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, model := inputModel{ GlobalFlagModel: globalFlags, Limit: limit, - OrganizationId: flags.FlagToStringPointer(p, cmd, organizationIdFlag), - NetworkAreaId: flags.FlagToStringPointer(p, cmd, networkAreaIdFlag), + OrganizationId: flags.FlagToStringValue(p, cmd, organizationIdFlag), + NetworkAreaId: flags.FlagToStringValue(p, cmd, networkAreaIdFlag), } p.DebugInputModel(model) @@ -126,7 +126,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, } func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiListNetworkAreaRoutesRequest { - return apiClient.ListNetworkAreaRoutes(ctx, *model.OrganizationId, *model.NetworkAreaId, model.Region) + return apiClient.ListNetworkAreaRoutes(ctx, model.OrganizationId, model.NetworkAreaId, model.Region) } func outputResult(p *print.Printer, outputFormat, networkAreaLabel string, routes []iaas.Route) error { diff --git a/internal/cmd/network-area/route/list/list_test.go b/internal/cmd/network-area/route/list/list_test.go index 88e8db79d..bcd79bf00 100644 --- a/internal/cmd/network-area/route/list/list_test.go +++ b/internal/cmd/network-area/route/list/list_test.go @@ -46,8 +46,8 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { Verbosity: globalflags.VerbosityDefault, Region: testRegion, }, - OrganizationId: &testOrganizationId, - NetworkAreaId: &testNetworkAreaId, + OrganizationId: testOrganizationId, + NetworkAreaId: testNetworkAreaId, Limit: utils.Ptr(int64(10)), } for _, mod := range mods { From 68c108c0bc3ed7b56f22387b36f482cf2d906cf5 Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 22 Apr 2026 17:47:40 +0200 Subject: [PATCH 38/39] (fix): changed print statement to not contain abbreviation --- internal/cmd/network-area/network-range/list/list.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/cmd/network-area/network-range/list/list.go b/internal/cmd/network-area/network-range/list/list.go index cfda99ad3..ebc1e0faa 100644 --- a/internal/cmd/network-area/network-range/list/list.go +++ b/internal/cmd/network-area/network-range/list/list.go @@ -132,7 +132,7 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APICli func outputResult(p *print.Printer, outputFormat, networkAreaLabel string, networkRanges []iaas.NetworkRange) error { return p.OutputResult(outputFormat, networkRanges, func() error { if len(networkRanges) == 0 { - p.Outputf("No network ranges found for SNA %q\n", networkAreaLabel) + p.Outputf("No network ranges found for STACKIT network area %q\n", networkAreaLabel) return nil } table := tables.NewTable() From 81e4c72e48028c9a85f21262badbba259d5e1e4e Mon Sep 17 00:00:00 2001 From: Jan Obernberger Date: Wed, 22 Apr 2026 18:03:31 +0200 Subject: [PATCH 39/39] (fix): added test suggestion --- internal/cmd/affinity-groups/list/list_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/internal/cmd/affinity-groups/list/list_test.go b/internal/cmd/affinity-groups/list/list_test.go index b1141d13c..88f5ca635 100644 --- a/internal/cmd/affinity-groups/list/list_test.go +++ b/internal/cmd/affinity-groups/list/list_test.go @@ -156,6 +156,20 @@ func TestOutputResult(t *testing.T) { args: args{}, isValid: true, }, + { + description: "empty slice", + args: args{ + instances: []iaas.AffinityGroup{}, + }, + isValid: true, + }, + { + description: "empty affinity group in slice", + args: args{ + instances: []iaas.AffinityGroup{{}}, + }, + isValid: true, + }, } params := testparams.NewTestParams() for _, tt := range tests {