diff --git a/pkg/cmd/auth/status/status.go b/pkg/cmd/auth/status/status.go index 11aad6baa..47d4106fb 100644 --- a/pkg/cmd/auth/status/status.go +++ b/pkg/cmd/auth/status/status.go @@ -17,7 +17,6 @@ import ( "github.com/cli/cli/v2/pkg/cmdutil" "github.com/cli/cli/v2/pkg/iostreams" "github.com/spf13/cobra" - "github.com/spf13/pflag" ) type authEntry struct { @@ -172,15 +171,7 @@ func NewCmdStatus(f *cmdutil.Factory, runF func(*StatusOptions) error) *cobra.Co cmd.Flags().BoolVarP(&opts.ShowToken, "show-token", "t", false, "Display the auth token") cmd.Flags().BoolVarP(&opts.Active, "active", "a", false, "Display the active account only") - // Add JSON flags for exporting, but ignore the default `-t` abbreviation that conflicts with show-token. - tmpCmd := &cobra.Command{} - cmdutil.AddJSONFlags(tmpCmd, &opts.Exporter, authFields) - tmpCmd.Flags().VisitAll(func(f *pflag.Flag) { - if f.Name == "template" { - f.Shorthand = "" - } - cmd.Flags().AddFlag(f) - }) + cmdutil.AddJSONFlags(cmd, &opts.Exporter, authFields) cmd.MarkFlagsMutuallyExclusive("show-token", "json") diff --git a/pkg/cmdutil/json_flags.go b/pkg/cmdutil/json_flags.go index 596c2f216..29bb8c002 100644 --- a/pkg/cmdutil/json_flags.go +++ b/pkg/cmdutil/json_flags.go @@ -26,8 +26,8 @@ type JSONFlagError struct { func AddJSONFlags(cmd *cobra.Command, exportTarget *Exporter, fields []string) { f := cmd.Flags() f.StringSlice("json", nil, "Output JSON with the specified `fields`") - f.StringP("jq", "q", "", "Filter JSON output using a jq `expression`") - f.StringP("template", "t", "", "Format JSON output using a Go template; see \"gh help formatting\"") + addStringFlagWithSafeShorthand(f, "jq", "q", "", "Filter JSON output using a jq `expression`") + addStringFlagWithSafeShorthand(f, "template", "t", "", "Format JSON output using a Go template; see \"gh help formatting\"") _ = cmd.RegisterFlagCompletionFunc("json", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { var results []string @@ -94,6 +94,15 @@ func AddJSONFlags(cmd *cobra.Command, exportTarget *Exporter, fields []string) { cmd.Annotations["help:json-fields"] = strings.Join(fields, ",") } +// addStringFlagWithSafeShorthand only adds the flag with shorthand if the shorthand is not already used by another flag. +func addStringFlagWithSafeShorthand(f *pflag.FlagSet, name, shorthand, value, usage string) { + if f.ShorthandLookup(shorthand) != nil { + f.String(name, value, usage) + } else { + f.StringP(name, shorthand, value, usage) + } +} + func checkJSONFlags(cmd *cobra.Command) (*jsonExporter, error) { f := cmd.Flags() jsonFlag := f.Lookup("json") diff --git a/pkg/cmdutil/json_flags_test.go b/pkg/cmdutil/json_flags_test.go index 63c63aa00..15f0b7642 100644 --- a/pkg/cmdutil/json_flags_test.go +++ b/pkg/cmdutil/json_flags_test.go @@ -119,6 +119,54 @@ func TestAddJSONFlags(t *testing.T) { } } +func TestAddJSONFlagsNoDuplicateShorthand(t *testing.T) { + tests := []struct { + name string + setFlags func(cmd *cobra.Command) + wantFlags map[string]string + }{ + { + name: "no conflicting flags", + setFlags: func(cmd *cobra.Command) { + cmd.Flags().StringP("web", "w", "", "") + }, + wantFlags: map[string]string{ + "web": "w", + "jq": "q", + "template": "t", + "json": "", + }, + }, + { + name: "conflicting flags", + setFlags: func(cmd *cobra.Command) { + cmd.Flags().StringP("token", "t", "", "") + }, + wantFlags: map[string]string{ + "token": "t", + "jq": "q", + "template": "", // no shorthand + "json": "", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + cmd := &cobra.Command{Run: func(*cobra.Command, []string) {}} + tt.setFlags(cmd) + + AddJSONFlags(cmd, nil, []string{}) + + for f, shorthand := range tt.wantFlags { + flag := cmd.Flags().Lookup(f) + require.NotNil(t, flag) + require.Equal(t, shorthand, flag.Shorthand) + } + }) + } +} + // TestAddJSONFlagsSetsAnnotations asserts that `AddJSONFlags` function adds the // appropriate annotation to the command, which could later be used by doc // generator functions.