From d9163548660bd6ce3e6276ee5370c69857fabc96 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 01:56:05 +0000 Subject: [PATCH 1/6] Initial plan From f3a972878488d8370fc7bda8826bc6f96a16bd31 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 02:01:10 +0000 Subject: [PATCH 2/6] Improve unsupported format error message to list supported formats without plain-text Co-authored-by: brooke-hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- pkg/cli/output/formatter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cli/output/formatter.go b/pkg/cli/output/formatter.go index 4777b1b9c4..af0c5764b5 100644 --- a/pkg/cli/output/formatter.go +++ b/pkg/cli/output/formatter.go @@ -54,7 +54,7 @@ func NewFormatter(format string) (Formatter, error) { case FormatTable: return &TableFormatter{}, nil default: - return nil, fmt.Errorf("unsupported format %s", format) + return nil, fmt.Errorf("unsupported format %q, supported formats are: %s", format, strings.Join(SupportedFormats(), ", ")) } } From a924a54ab9b93289103f641896ffbea67cff4011 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 20:19:13 +0000 Subject: [PATCH 3/6] Fix RequireOutput to use SupportedFormats instead of AllFormats for consistent error messages Co-authored-by: brooke-hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- pkg/cli/clivalidation.go | 16 +++++++++++++--- pkg/cli/cmd/recipepack/show/show.go | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/pkg/cli/clivalidation.go b/pkg/cli/clivalidation.go index 8f59d57a92..03ee68753f 100644 --- a/pkg/cli/clivalidation.go +++ b/pkg/cli/clivalidation.go @@ -355,6 +355,17 @@ func RequireAzureSubscriptionId(cmd *cobra.Command) (string, error) { // RequireOutput reads the output format flag, normalizes it (trim and lowercase), and validates // it against the supported formats. Returns an error if the format is not supported. func RequireOutput(cmd *cobra.Command) (string, error) { + return requireOutputFromFormats(cmd, output.SupportedFormats()) +} + +// RequireOutputAllowPlainText reads the output format flag and validates it against +// all recognized formats including plain-text. Use this for commands that support +// the plain-text output format. +func RequireOutputAllowPlainText(cmd *cobra.Command) (string, error) { + return requireOutputFromFormats(cmd, output.AllFormats()) +} + +func requireOutputFromFormats(cmd *cobra.Command, formats []string) (string, error) { format, err := cmd.Flags().GetString("output") if err != nil { return "", err @@ -366,14 +377,13 @@ func RequireOutput(cmd *cobra.Command) (string, error) { return output.DefaultFormat, nil } - allFormats := output.AllFormats() - for _, f := range allFormats { + for _, f := range formats { if format == f { return format, nil } } - return "", clierrors.Message("unsupported output format %q, supported formats are: %s", format, strings.Join(allFormats, ", ")) + return "", clierrors.Message("unsupported output format %q, supported formats are: %s", format, strings.Join(formats, ", ")) } // RequireWorkspace is used by commands that require an existing workspace either set as the default, diff --git a/pkg/cli/cmd/recipepack/show/show.go b/pkg/cli/cmd/recipepack/show/show.go index 5c498a26cf..8db4fd8f3f 100644 --- a/pkg/cli/cmd/recipepack/show/show.go +++ b/pkg/cli/cmd/recipepack/show/show.go @@ -102,7 +102,7 @@ func (r *Runner) Validate(cmd *cobra.Command, args []string) error { } r.RecipePackName = recipePackName - format, err := cli.RequireOutput(cmd) + format, err := cli.RequireOutputAllowPlainText(cmd) if err != nil { return err } From ff8d6165ebdc15fd0271455f560797b54e5d762f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 19:39:36 +0000 Subject: [PATCH 4/6] Tighten RequireOutputAllowPlainText to accept only plain-text and json, add unit tests, remove unused AllFormats Co-authored-by: brooke-hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- pkg/cli/clivalidation.go | 4 +- pkg/cli/clivalidation_test.go | 129 ++++++++++++++++++++++++++++++++++ pkg/cli/output/formats.go | 10 --- 3 files changed, 131 insertions(+), 12 deletions(-) diff --git a/pkg/cli/clivalidation.go b/pkg/cli/clivalidation.go index 03ee68753f..9ea78ea39e 100644 --- a/pkg/cli/clivalidation.go +++ b/pkg/cli/clivalidation.go @@ -359,10 +359,10 @@ func RequireOutput(cmd *cobra.Command) (string, error) { } // RequireOutputAllowPlainText reads the output format flag and validates it against -// all recognized formats including plain-text. Use this for commands that support +// plain-text and json formats. Use this for commands that support // the plain-text output format. func RequireOutputAllowPlainText(cmd *cobra.Command) (string, error) { - return requireOutputFromFormats(cmd, output.AllFormats()) + return requireOutputFromFormats(cmd, []string{output.FormatPlainText, output.FormatJson}) } func requireOutputFromFormats(cmd *cobra.Command, formats []string) (string, error) { diff --git a/pkg/cli/clivalidation_test.go b/pkg/cli/clivalidation_test.go index cb3384bb04..9646437f30 100644 --- a/pkg/cli/clivalidation_test.go +++ b/pkg/cli/clivalidation_test.go @@ -21,6 +21,8 @@ import ( "fmt" "testing" + "github.com/radius-project/radius/pkg/cli/output" + "github.com/spf13/cobra" "github.com/stretchr/testify/require" ) @@ -168,3 +170,130 @@ func Test_ReadResourceTypeNameArgs(t *testing.T) { }) } } + +// newCmdWithOutputFlag creates a cobra command with a string flag named "output" set to the given value. +func newCmdWithOutputFlag(value string) *cobra.Command { + cmd := &cobra.Command{Use: "test"} + cmd.Flags().StringP("output", "o", "", "output format") + err := cmd.Flags().Set("output", value) + if err != nil { + panic(err) + } + return cmd +} + +func Test_RequireOutput(t *testing.T) { + tests := []struct { + name string + format string + want string + wantErr bool + errSubstr string + }{ + { + name: "json is accepted", + format: "json", + want: "json", + }, + { + name: "table is accepted", + format: "table", + want: "table", + }, + { + name: "empty defaults to table", + format: "", + want: output.DefaultFormat, + }, + { + name: "plain-text is rejected", + format: "plain-text", + wantErr: true, + errSubstr: `unsupported output format "plain-text", supported formats are: json, table`, + }, + { + name: "text is rejected", + format: "text", + wantErr: true, + errSubstr: `unsupported output format "text", supported formats are: json, table`, + }, + { + name: "unknown format is rejected", + format: "xml", + wantErr: true, + errSubstr: `unsupported output format "xml", supported formats are: json, table`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cmd := newCmdWithOutputFlag(tt.format) + got, err := RequireOutput(cmd) + if tt.wantErr { + require.Error(t, err) + require.Contains(t, err.Error(), tt.errSubstr) + } else { + require.NoError(t, err) + require.Equal(t, tt.want, got) + } + }) + } +} + +func Test_RequireOutputAllowPlainText(t *testing.T) { + tests := []struct { + name string + format string + want string + wantErr bool + errSubstr string + }{ + { + name: "json is accepted", + format: "json", + want: "json", + }, + { + name: "plain-text is accepted", + format: "plain-text", + want: "plain-text", + }, + { + name: "empty defaults to table", + format: "", + want: output.DefaultFormat, + }, + { + name: "table is rejected", + format: "table", + wantErr: true, + errSubstr: `unsupported output format "table", supported formats are: plain-text, json`, + }, + { + name: "text is rejected", + format: "text", + wantErr: true, + errSubstr: `unsupported output format "text", supported formats are: plain-text, json`, + }, + { + name: "unknown format is rejected", + format: "xml", + wantErr: true, + errSubstr: `unsupported output format "xml", supported formats are: plain-text, json`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cmd := newCmdWithOutputFlag(tt.format) + got, err := RequireOutputAllowPlainText(cmd) + if tt.wantErr { + require.Error(t, err) + require.Contains(t, err.Error(), tt.errSubstr) + } else { + require.NoError(t, err) + require.Equal(t, tt.want, got) + } + }) + } +} diff --git a/pkg/cli/output/formats.go b/pkg/cli/output/formats.go index 9565c87155..07b7ca12fe 100644 --- a/pkg/cli/output/formats.go +++ b/pkg/cli/output/formats.go @@ -30,13 +30,3 @@ func SupportedFormats() []string { FormatTable, } } - -// AllFormats returns all recognized output format strings, including formats -// that are only available for specific commands (e.g., plain-text). -func AllFormats() []string { - return []string{ - FormatJson, - FormatTable, - FormatPlainText, - } -} From cc45871f20d2225bb67b9267d5fe846205d04f90 Mon Sep 17 00:00:00 2001 From: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> Date: Thu, 19 Feb 2026 14:31:48 -0500 Subject: [PATCH 5/6] Remove plain-text as advertised output format; normalize to table for backwards compat - Add NormalizeFormat() in output/formats.go to map plain-text -> table - Add plain-text case in NewFormatter() as defense in depth - Rewrite RequireOutput() to normalize plain-text silently to table - Delete RequireOutputAllowPlainText() and requireOutputFromFormats() - Delete AddOutputFlagWithPlainText() from commonflags - Switch recipe-pack show to use standard AddOutputFlag + RequireOutput - Switch version command to use RequireOutput for consistency - Add tests for NormalizeFormat, NewFormatter(plain-text), and updated RequireOutput behavior - Add table format test case for recipe-pack show Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- pkg/cli/clivalidation.go | 20 ++--- pkg/cli/clivalidation_test.go | 63 +------------ pkg/cli/cmd/commonflags/flags.go | 4 - pkg/cli/cmd/recipepack/show/show.go | 6 +- pkg/cli/cmd/recipepack/show/show_test.go | 109 ++++++++++++++++------- pkg/cli/cmd/version/version.go | 6 +- pkg/cli/output/formats.go | 10 +++ pkg/cli/output/formats_test.go | 59 ++++++++++++ pkg/cli/output/formatter.go | 2 +- pkg/cli/output/formatter_test.go | 78 ++++++++++++++++ 10 files changed, 238 insertions(+), 119 deletions(-) create mode 100644 pkg/cli/output/formats_test.go create mode 100644 pkg/cli/output/formatter_test.go diff --git a/pkg/cli/clivalidation.go b/pkg/cli/clivalidation.go index 9ea78ea39e..66c4dc9df2 100644 --- a/pkg/cli/clivalidation.go +++ b/pkg/cli/clivalidation.go @@ -354,18 +354,9 @@ func RequireAzureSubscriptionId(cmd *cobra.Command) (string, error) { // RequireOutput reads the output format flag, normalizes it (trim and lowercase), and validates // it against the supported formats. Returns an error if the format is not supported. +// +// For backwards compatibility, "plain-text" is silently normalized to "table". func RequireOutput(cmd *cobra.Command) (string, error) { - return requireOutputFromFormats(cmd, output.SupportedFormats()) -} - -// RequireOutputAllowPlainText reads the output format flag and validates it against -// plain-text and json formats. Use this for commands that support -// the plain-text output format. -func RequireOutputAllowPlainText(cmd *cobra.Command) (string, error) { - return requireOutputFromFormats(cmd, []string{output.FormatPlainText, output.FormatJson}) -} - -func requireOutputFromFormats(cmd *cobra.Command, formats []string) (string, error) { format, err := cmd.Flags().GetString("output") if err != nil { return "", err @@ -377,13 +368,16 @@ func requireOutputFromFormats(cmd *cobra.Command, formats []string) (string, err return output.DefaultFormat, nil } - for _, f := range formats { + // Backwards compatibility: accept deprecated aliases silently. + format = output.NormalizeFormat(format) + + for _, f := range output.SupportedFormats() { if format == f { return format, nil } } - return "", clierrors.Message("unsupported output format %q, supported formats are: %s", format, strings.Join(formats, ", ")) + return "", clierrors.Message("unsupported output format %q, supported formats are: %s", format, strings.Join(output.SupportedFormats(), ", ")) } // RequireWorkspace is used by commands that require an existing workspace either set as the default, diff --git a/pkg/cli/clivalidation_test.go b/pkg/cli/clivalidation_test.go index 9646437f30..af9ac4d6fd 100644 --- a/pkg/cli/clivalidation_test.go +++ b/pkg/cli/clivalidation_test.go @@ -206,10 +206,9 @@ func Test_RequireOutput(t *testing.T) { want: output.DefaultFormat, }, { - name: "plain-text is rejected", - format: "plain-text", - wantErr: true, - errSubstr: `unsupported output format "plain-text", supported formats are: json, table`, + name: "plain-text is normalized to table", + format: "plain-text", + want: "table", }, { name: "text is rejected", @@ -240,60 +239,4 @@ func Test_RequireOutput(t *testing.T) { } } -func Test_RequireOutputAllowPlainText(t *testing.T) { - tests := []struct { - name string - format string - want string - wantErr bool - errSubstr string - }{ - { - name: "json is accepted", - format: "json", - want: "json", - }, - { - name: "plain-text is accepted", - format: "plain-text", - want: "plain-text", - }, - { - name: "empty defaults to table", - format: "", - want: output.DefaultFormat, - }, - { - name: "table is rejected", - format: "table", - wantErr: true, - errSubstr: `unsupported output format "table", supported formats are: plain-text, json`, - }, - { - name: "text is rejected", - format: "text", - wantErr: true, - errSubstr: `unsupported output format "text", supported formats are: plain-text, json`, - }, - { - name: "unknown format is rejected", - format: "xml", - wantErr: true, - errSubstr: `unsupported output format "xml", supported formats are: plain-text, json`, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - cmd := newCmdWithOutputFlag(tt.format) - got, err := RequireOutputAllowPlainText(cmd) - if tt.wantErr { - require.Error(t, err) - require.Contains(t, err.Error(), tt.errSubstr) - } else { - require.NoError(t, err) - require.Equal(t, tt.want, got) - } - }) - } -} diff --git a/pkg/cli/cmd/commonflags/flags.go b/pkg/cli/cmd/commonflags/flags.go index be46fd1799..0b45c34a69 100644 --- a/pkg/cli/cmd/commonflags/flags.go +++ b/pkg/cli/cmd/commonflags/flags.go @@ -49,10 +49,6 @@ func AddOutputFlag(cmd *cobra.Command) { cmd.Flags().StringP("output", "o", output.DefaultFormat, description) } -func AddOutputFlagWithPlainText(cmd *cobra.Command) { - description := fmt.Sprintf("output format (supported formats are %s)", strings.Join([]string{output.FormatPlainText, output.FormatJson}, ", ")) - cmd.Flags().StringP("output", "o", output.FormatPlainText, description) -} // AddWorkspaceFlag adds a flag to the given command that allows the user to specify a workspace name. func AddWorkspaceFlag(cmd *cobra.Command) { diff --git a/pkg/cli/cmd/recipepack/show/show.go b/pkg/cli/cmd/recipepack/show/show.go index 8db4fd8f3f..c55c291c8d 100644 --- a/pkg/cli/cmd/recipepack/show/show.go +++ b/pkg/cli/cmd/recipepack/show/show.go @@ -52,7 +52,7 @@ rad recipe-show show my-recipe-pack --group my-group RunE: framework.RunCommand(runner), } - commonflags.AddOutputFlagWithPlainText(cmd) + commonflags.AddOutputFlag(cmd) commonflags.AddResourceGroupFlag(cmd) commonflags.AddWorkspaceFlag(cmd) @@ -102,7 +102,7 @@ func (r *Runner) Validate(cmd *cobra.Command, args []string) error { } r.RecipePackName = recipePackName - format, err := cli.RequireOutputAllowPlainText(cmd) + format, err := cli.RequireOutput(cmd) if err != nil { return err } @@ -130,7 +130,7 @@ func (r *Runner) Run(ctx context.Context) error { return err } - if r.Format != "json" { + if r.Format != output.FormatJson { err = r.Output.WriteFormatted(output.FormatTable, recipePack, objectformats.GetRecipePackTableFormat()) if err != nil { return err diff --git a/pkg/cli/cmd/recipepack/show/show_test.go b/pkg/cli/cmd/recipepack/show/show_test.go index c992be240c..16602e366c 100644 --- a/pkg/cli/cmd/recipepack/show/show_test.go +++ b/pkg/cli/cmd/recipepack/show/show_test.go @@ -83,9 +83,6 @@ func Test_Validate(t *testing.T) { } func Test_Run(t *testing.T) { - ctrl := gomock.NewController(t) - defer ctrl.Finish() - recipePack := corerpv20250801preview.RecipePackResource{ Name: to.Ptr("sample-pack"), Properties: &corerpv20250801preview.RecipePackProperties{ @@ -101,40 +98,84 @@ func Test_Run(t *testing.T) { }, } - appMgmtClient := clients.NewMockApplicationsManagementClient(ctrl) - appMgmtClient.EXPECT(). - GetRecipePack(gomock.Any(), "sample-pack"). - Return(recipePack, nil). - Times(1) + t.Run("json format", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() - workspace := &workspaces.Workspace{ - Connection: map[string]any{ - "kind": "kubernetes", - "context": "kind-kind", - }, - Name: "kind-kind", - Scope: "/planes/radius/local/resourceGroups/test-group", - } + appMgmtClient := clients.NewMockApplicationsManagementClient(ctrl) + appMgmtClient.EXPECT(). + GetRecipePack(gomock.Any(), "sample-pack"). + Return(recipePack, nil). + Times(1) - outputSink := &output.MockOutput{} - runner := &Runner{ - ConnectionFactory: &connections.MockFactory{ApplicationsManagementClient: appMgmtClient}, - Workspace: workspace, - Output: outputSink, - RecipePackName: "sample-pack", - Format: "json", - } + workspace := &workspaces.Workspace{ + Connection: map[string]any{ + "kind": "kubernetes", + "context": "kind-kind", + }, + Name: "kind-kind", + Scope: "/planes/radius/local/resourceGroups/test-group", + } + + outputSink := &output.MockOutput{} + runner := &Runner{ + ConnectionFactory: &connections.MockFactory{ApplicationsManagementClient: appMgmtClient}, + Workspace: workspace, + Output: outputSink, + RecipePackName: "sample-pack", + Format: "json", + } + + err := runner.Run(context.Background()) + require.NoError(t, err) + + expected := []any{ + output.FormattedOutput{ + Format: "json", + Obj: recipePack, + Options: objectformats.GetRecipePackTableFormat(), + }, + } - err := runner.Run(context.Background()) - require.NoError(t, err) + require.Equal(t, expected, outputSink.Writes) + }) - expected := []any{ - output.FormattedOutput{ - Format: "json", - Obj: recipePack, - Options: objectformats.GetRecipePackTableFormat(), - }, - } + t.Run("table format", func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() - require.Equal(t, expected, outputSink.Writes) + appMgmtClient := clients.NewMockApplicationsManagementClient(ctrl) + appMgmtClient.EXPECT(). + GetRecipePack(gomock.Any(), "sample-pack"). + Return(recipePack, nil). + Times(1) + + workspace := &workspaces.Workspace{ + Connection: map[string]any{ + "kind": "kubernetes", + "context": "kind-kind", + }, + Name: "kind-kind", + Scope: "/planes/radius/local/resourceGroups/test-group", + } + + outputSink := &output.MockOutput{} + runner := &Runner{ + ConnectionFactory: &connections.MockFactory{ApplicationsManagementClient: appMgmtClient}, + Workspace: workspace, + Output: outputSink, + RecipePackName: "sample-pack", + Format: "table", + } + + err := runner.Run(context.Background()) + require.NoError(t, err) + + // Table format produces a table write followed by display (LogInfo) output + require.NotEmpty(t, outputSink.Writes) + firstWrite, ok := outputSink.Writes[0].(output.FormattedOutput) + require.True(t, ok) + require.Equal(t, "table", firstWrite.Format) + require.Equal(t, recipePack, firstWrite.Obj) + }) } diff --git a/pkg/cli/cmd/version/version.go b/pkg/cli/cmd/version/version.go index 3e5fe2c8fa..3a5ee5293e 100644 --- a/pkg/cli/cmd/version/version.go +++ b/pkg/cli/cmd/version/version.go @@ -3,6 +3,7 @@ package version import ( "context" + "github.com/radius-project/radius/pkg/cli" "github.com/radius-project/radius/pkg/cli/bicep" "github.com/radius-project/radius/pkg/cli/framework" "github.com/radius-project/radius/pkg/cli/helm" @@ -102,13 +103,10 @@ func NewRunner(factory framework.Factory) *Runner { // Validate validates the command arguments func (r *Runner) Validate(cmd *cobra.Command, args []string) error { - format, err := cmd.Flags().GetString("output") + format, err := cli.RequireOutput(cmd) if err != nil { return err } - if format == "" { - format = "table" - } r.Format = format cliOnly, err := cmd.Flags().GetBool("cli") diff --git a/pkg/cli/output/formats.go b/pkg/cli/output/formats.go index 07b7ca12fe..459b91f30c 100644 --- a/pkg/cli/output/formats.go +++ b/pkg/cli/output/formats.go @@ -30,3 +30,13 @@ func SupportedFormats() []string { FormatTable, } } + +// NormalizeFormat maps deprecated format aliases to their canonical form. +// Currently maps "plain-text" → "table" for backwards compatibility. +// Returns the input unchanged if it is not an alias. +func NormalizeFormat(format string) string { + if format == FormatPlainText { + return FormatTable + } + return format +} diff --git a/pkg/cli/output/formats_test.go b/pkg/cli/output/formats_test.go new file mode 100644 index 0000000000..685bf5e37f --- /dev/null +++ b/pkg/cli/output/formats_test.go @@ -0,0 +1,59 @@ +/* +Copyright 2023 The Radius Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package output + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_NormalizeFormat(t *testing.T) { + tests := []struct { + name string + input string + expect string + }{ + { + name: "plain-text maps to table", + input: "plain-text", + expect: "table", + }, + { + name: "json is unchanged", + input: "json", + expect: "json", + }, + { + name: "table is unchanged", + input: "table", + expect: "table", + }, + { + name: "unknown values pass through unchanged", + input: "xml", + expect: "xml", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := NormalizeFormat(tt.input) + require.Equal(t, tt.expect, got) + }) + } +} diff --git a/pkg/cli/output/formatter.go b/pkg/cli/output/formatter.go index af0c5764b5..8962144911 100644 --- a/pkg/cli/output/formatter.go +++ b/pkg/cli/output/formatter.go @@ -51,7 +51,7 @@ func NewFormatter(format string) (Formatter, error) { switch normalized { case FormatJson: return &JSONFormatter{}, nil - case FormatTable: + case FormatTable, FormatPlainText: return &TableFormatter{}, nil default: return nil, fmt.Errorf("unsupported format %q, supported formats are: %s", format, strings.Join(SupportedFormats(), ", ")) diff --git a/pkg/cli/output/formatter_test.go b/pkg/cli/output/formatter_test.go new file mode 100644 index 0000000000..e4c8102f9b --- /dev/null +++ b/pkg/cli/output/formatter_test.go @@ -0,0 +1,78 @@ +/* +Copyright 2023 The Radius Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package output + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_NewFormatter(t *testing.T) { + tests := []struct { + name string + format string + expectType string + expectError bool + }{ + { + name: "json returns JSONFormatter", + format: "json", + expectType: "*output.JSONFormatter", + }, + { + name: "table returns TableFormatter", + format: "table", + expectType: "*output.TableFormatter", + }, + { + name: "plain-text returns TableFormatter", + format: "plain-text", + expectType: "*output.TableFormatter", + }, + { + name: "unsupported format returns error", + format: "xml", + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + formatter, err := NewFormatter(tt.format) + if tt.expectError { + require.Error(t, err) + require.Nil(t, formatter) + } else { + require.NoError(t, err) + require.IsType(t, getFormatterForType(tt.expectType), formatter) + } + }) + } +} + +// getFormatterForType returns a zero-value instance of the given type name for type assertion. +func getFormatterForType(typeName string) Formatter { + switch typeName { + case "*output.JSONFormatter": + return &JSONFormatter{} + case "*output.TableFormatter": + return &TableFormatter{} + default: + return nil + } +} From 6f65972308ed10ead3b2528edabdf71b187886ea Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 21:05:49 +0000 Subject: [PATCH 6/6] Register output flag in version command; remove trailing blank line in test file Co-authored-by: brooke-hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- pkg/cli/clivalidation_test.go | 2 -- pkg/cli/cmd/version/version.go | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/cli/clivalidation_test.go b/pkg/cli/clivalidation_test.go index af9ac4d6fd..ab264caf7f 100644 --- a/pkg/cli/clivalidation_test.go +++ b/pkg/cli/clivalidation_test.go @@ -238,5 +238,3 @@ func Test_RequireOutput(t *testing.T) { }) } } - - diff --git a/pkg/cli/cmd/version/version.go b/pkg/cli/cmd/version/version.go index 3a5ee5293e..f7b6de0f1c 100644 --- a/pkg/cli/cmd/version/version.go +++ b/pkg/cli/cmd/version/version.go @@ -5,6 +5,7 @@ import ( "github.com/radius-project/radius/pkg/cli" "github.com/radius-project/radius/pkg/cli/bicep" + "github.com/radius-project/radius/pkg/cli/cmd/commonflags" "github.com/radius-project/radius/pkg/cli/framework" "github.com/radius-project/radius/pkg/cli/helm" "github.com/radius-project/radius/pkg/cli/output" @@ -80,6 +81,7 @@ rad version --cli`, RunE: framework.RunCommand(runner), } + commonflags.AddOutputFlag(cmd) cmd.Flags().Bool("cli", false, "Use this flag to only show the rad CLI version") return cmd, runner }