From 62f10fbdf820c09753d395e102f62ca83a9f0bac Mon Sep 17 00:00:00 2001 From: Shirong Lu <73147033+happysnaker@users.noreply.github.com> Date: Thu, 2 Jul 2026 12:47:05 +0800 Subject: [PATCH 1/3] fix: error on legacy v1-style flag alias syntax --- app_test.go | 26 +++++++++++++++++++++++++- flag.go | 15 +++++++++++++++ flag_bool.go | 4 ++++ flag_duration.go | 4 ++++ flag_float64.go | 4 ++++ flag_float64_slice.go | 4 ++++ flag_generic.go | 4 ++++ flag_int.go | 4 ++++ flag_int64.go | 4 ++++ flag_int64_slice.go | 4 ++++ flag_int_slice.go | 4 ++++ flag_path.go | 4 ++++ flag_string.go | 4 ++++ flag_string_slice.go | 4 ++++ flag_timestamp.go | 4 ++++ flag_uint.go | 4 ++++ flag_uint64.go | 4 ++++ flag_uint64_slice.go | 4 ++++ flag_uint_slice.go | 4 ++++ 19 files changed, 108 insertions(+), 1 deletion(-) diff --git a/app_test.go b/app_test.go index f6f9158b05..3e25718442 100644 --- a/app_test.go +++ b/app_test.go @@ -283,7 +283,8 @@ func ExampleApp_Run_bashComplete_withLongFlag() { Aliases: []string{"x"}, }, &StringFlag{ - Name: "some-flag,s", + Name: "some-flag", + Aliases: []string{"s"}, }, &StringFlag{ Name: "similar-flag", @@ -295,6 +296,29 @@ func ExampleApp_Run_bashComplete_withLongFlag() { // --some-flag // --similar-flag } + +func TestApp_Run_ErrorsOnLegacyV1FlagAliasSyntax(t *testing.T) { + app := &App{ + Name: "greet", + Flags: []Flag{ + &StringFlag{ + Name: "config, cfg", + }, + }, + } + + err := app.Run([]string{"greet"}) + if err == nil { + t.Fatalf("expected an error for legacy alias syntax, got nil") + } + + if !strings.Contains(err.Error(), "invalid flag name") { + t.Fatalf("expected invalid flag name error, got %q", err) + } + if !strings.Contains(err.Error(), "Aliases") { + t.Fatalf("expected alias migration hint in error, got %q", err) + } +} func ExampleApp_Run_bashComplete_withMultipleLongFlag() { os.Setenv("SHELL", "bash") os.Args = []string{"greet", "--st", "--generate-bash-completion"} diff --git a/flag.go b/flag.go index 4d04de3da8..5762143f51 100644 --- a/flag.go +++ b/flag.go @@ -26,6 +26,21 @@ var ( commaWhitespace = regexp.MustCompile("[, ]+.*") ) +func validateFlagNames(name string, aliases []string) error { + if name != "" && (strings.Contains(name, ",") || strings.Contains(name, " ")) { + return fmt.Errorf("invalid flag name %q: use Name for the primary flag and Aliases for alternate names", name) + } + for _, alias := range aliases { + if alias == "" { + continue + } + if strings.Contains(alias, ",") || strings.Contains(alias, " ") { + return fmt.Errorf("invalid flag alias %q: aliases must be individual names without commas or spaces", alias) + } + } + return nil +} + // BashCompletionFlag enables bash-completion for all commands and subcommands var BashCompletionFlag Flag = &BoolFlag{ Name: "generate-bash-completion", diff --git a/flag_bool.go b/flag_bool.go index 01862ea764..3319740003 100644 --- a/flag_bool.go +++ b/flag_bool.go @@ -106,6 +106,10 @@ func (f *BoolFlag) RunAction(c *Context) error { // Apply populates the flag given the flag set and environment func (f *BoolFlag) Apply(set *flag.FlagSet) error { + if err := validateFlagNames(f.Name, f.Aliases); err != nil { + return err + } + // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value f.defaultValueSet = true diff --git a/flag_duration.go b/flag_duration.go index e600cc30ad..3fafd890c5 100644 --- a/flag_duration.go +++ b/flag_duration.go @@ -45,6 +45,10 @@ func (f *DurationFlag) GetEnvVars() []string { // Apply populates the flag given the flag set and environment func (f *DurationFlag) Apply(set *flag.FlagSet) error { + if err := validateFlagNames(f.Name, f.Aliases); err != nil { + return err + } + // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value f.defaultValueSet = true diff --git a/flag_float64.go b/flag_float64.go index 6a4de5c88b..d07f508fd4 100644 --- a/flag_float64.go +++ b/flag_float64.go @@ -45,6 +45,10 @@ func (f *Float64Flag) GetEnvVars() []string { // Apply populates the flag given the flag set and environment func (f *Float64Flag) Apply(set *flag.FlagSet) error { + if err := validateFlagNames(f.Name, f.Aliases); err != nil { + return err + } + f.defaultValue = f.Value f.defaultValueSet = true diff --git a/flag_float64_slice.go b/flag_float64_slice.go index 0bc4612c82..8d88175644 100644 --- a/flag_float64_slice.go +++ b/flag_float64_slice.go @@ -138,6 +138,10 @@ func (f *Float64SliceFlag) IsSliceFlag() bool { // Apply populates the flag given the flag set and environment func (f *Float64SliceFlag) Apply(set *flag.FlagSet) error { + if err := validateFlagNames(f.Name, f.Aliases); err != nil { + return err + } + // apply any default if f.Destination != nil && f.Value != nil { f.Destination.slice = make([]float64, len(f.Value.slice)) diff --git a/flag_generic.go b/flag_generic.go index 7528c934cd..92402c3faa 100644 --- a/flag_generic.go +++ b/flag_generic.go @@ -73,6 +73,10 @@ func (f *GenericFlag) GetEnvVars() []string { // Apply takes the flagset and calls Set on the generic flag with the value // provided by the user for parsing by the flag func (f *GenericFlag) Apply(set *flag.FlagSet) error { + if err := validateFlagNames(f.Name, f.Aliases); err != nil { + return err + } + // set default value so that environment wont be able to overwrite it if f.Value != nil { f.defaultValue = &stringGeneric{value: f.Value.String()} diff --git a/flag_int.go b/flag_int.go index 750e7ebfc8..2934706faa 100644 --- a/flag_int.go +++ b/flag_int.go @@ -45,6 +45,10 @@ func (f *IntFlag) GetEnvVars() []string { // Apply populates the flag given the flag set and environment func (f *IntFlag) Apply(set *flag.FlagSet) error { + if err := validateFlagNames(f.Name, f.Aliases); err != nil { + return err + } + // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value f.defaultValueSet = true diff --git a/flag_int64.go b/flag_int64.go index 688c267162..7683422743 100644 --- a/flag_int64.go +++ b/flag_int64.go @@ -45,6 +45,10 @@ func (f *Int64Flag) GetEnvVars() []string { // Apply populates the flag given the flag set and environment func (f *Int64Flag) Apply(set *flag.FlagSet) error { + if err := validateFlagNames(f.Name, f.Aliases); err != nil { + return err + } + // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value f.defaultValueSet = true diff --git a/flag_int64_slice.go b/flag_int64_slice.go index d45c2dd440..ad489929fa 100644 --- a/flag_int64_slice.go +++ b/flag_int64_slice.go @@ -139,6 +139,10 @@ func (f *Int64SliceFlag) IsSliceFlag() bool { // Apply populates the flag given the flag set and environment func (f *Int64SliceFlag) Apply(set *flag.FlagSet) error { + if err := validateFlagNames(f.Name, f.Aliases); err != nil { + return err + } + // apply any default if f.Destination != nil && f.Value != nil { f.Destination.slice = make([]int64, len(f.Value.slice)) diff --git a/flag_int_slice.go b/flag_int_slice.go index da9c09bc73..25d1e6c9d5 100644 --- a/flag_int_slice.go +++ b/flag_int_slice.go @@ -150,6 +150,10 @@ func (f *IntSliceFlag) IsSliceFlag() bool { // Apply populates the flag given the flag set and environment func (f *IntSliceFlag) Apply(set *flag.FlagSet) error { + if err := validateFlagNames(f.Name, f.Aliases); err != nil { + return err + } + // apply any default if f.Destination != nil && f.Value != nil { f.Destination.slice = make([]int, len(f.Value.slice)) diff --git a/flag_path.go b/flag_path.go index 76cb35248c..64c81ea4f3 100644 --- a/flag_path.go +++ b/flag_path.go @@ -50,6 +50,10 @@ func (f *PathFlag) GetEnvVars() []string { // Apply populates the flag given the flag set and environment func (f *PathFlag) Apply(set *flag.FlagSet) error { + if err := validateFlagNames(f.Name, f.Aliases); err != nil { + return err + } + // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value f.defaultValueSet = true diff --git a/flag_string.go b/flag_string.go index 0f73e06215..5464635ab1 100644 --- a/flag_string.go +++ b/flag_string.go @@ -49,6 +49,10 @@ func (f *StringFlag) GetEnvVars() []string { // Apply populates the flag given the flag set and environment func (f *StringFlag) Apply(set *flag.FlagSet) error { + if err := validateFlagNames(f.Name, f.Aliases); err != nil { + return err + } + // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value f.defaultValueSet = true diff --git a/flag_string_slice.go b/flag_string_slice.go index 66bdf1afcd..8fba4c9f7f 100644 --- a/flag_string_slice.go +++ b/flag_string_slice.go @@ -135,6 +135,10 @@ func (f *StringSliceFlag) IsSliceFlag() bool { // Apply populates the flag given the flag set and environment func (f *StringSliceFlag) Apply(set *flag.FlagSet) error { + if err := validateFlagNames(f.Name, f.Aliases); err != nil { + return err + } + // apply any default if f.Destination != nil && f.Value != nil { f.Destination.slice = make([]string, len(f.Value.slice)) diff --git a/flag_timestamp.go b/flag_timestamp.go index b90123087c..f515b87ae4 100644 --- a/flag_timestamp.go +++ b/flag_timestamp.go @@ -139,6 +139,10 @@ func (f *TimestampFlag) GetEnvVars() []string { // Apply populates the flag given the flag set and environment func (f *TimestampFlag) Apply(set *flag.FlagSet) error { + if err := validateFlagNames(f.Name, f.Aliases); err != nil { + return err + } + if f.Layout == "" { return fmt.Errorf("timestamp Layout is required") } diff --git a/flag_uint.go b/flag_uint.go index 8d5b85458c..be0bc01c95 100644 --- a/flag_uint.go +++ b/flag_uint.go @@ -23,6 +23,10 @@ func (f *UintFlag) GetCategory() string { // Apply populates the flag given the flag set and environment func (f *UintFlag) Apply(set *flag.FlagSet) error { + if err := validateFlagNames(f.Name, f.Aliases); err != nil { + return err + } + // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value f.defaultValueSet = true diff --git a/flag_uint64.go b/flag_uint64.go index c356e533ba..58a2c9af21 100644 --- a/flag_uint64.go +++ b/flag_uint64.go @@ -23,6 +23,10 @@ func (f *Uint64Flag) GetCategory() string { // Apply populates the flag given the flag set and environment func (f *Uint64Flag) Apply(set *flag.FlagSet) error { + if err := validateFlagNames(f.Name, f.Aliases); err != nil { + return err + } + // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value f.defaultValueSet = true diff --git a/flag_uint64_slice.go b/flag_uint64_slice.go index d342018686..c4d11bb226 100644 --- a/flag_uint64_slice.go +++ b/flag_uint64_slice.go @@ -143,6 +143,10 @@ func (f *Uint64SliceFlag) IsSliceFlag() bool { // Apply populates the flag given the flag set and environment func (f *Uint64SliceFlag) Apply(set *flag.FlagSet) error { + if err := validateFlagNames(f.Name, f.Aliases); err != nil { + return err + } + // apply any default if f.Destination != nil && f.Value != nil { f.Destination.slice = make([]uint64, len(f.Value.slice)) diff --git a/flag_uint_slice.go b/flag_uint_slice.go index 4dc13e126a..074eaaca15 100644 --- a/flag_uint_slice.go +++ b/flag_uint_slice.go @@ -154,6 +154,10 @@ func (f *UintSliceFlag) IsSliceFlag() bool { // Apply populates the flag given the flag set and environment func (f *UintSliceFlag) Apply(set *flag.FlagSet) error { + if err := validateFlagNames(f.Name, f.Aliases); err != nil { + return err + } + // apply any default if f.Destination != nil && f.Value != nil { f.Destination.slice = make([]uint, len(f.Value.slice)) From 5698d33939abc056bf8113765652117e84c93dca Mon Sep 17 00:00:00 2001 From: Shirong Lu <73147033+happysnaker@users.noreply.github.com> Date: Thu, 2 Jul 2026 13:11:51 +0800 Subject: [PATCH 2/3] refactor: validate legacy alias syntax during flag setup --- flag.go | 46 +++++++++++++++++++++++++++++++++++++++++++ flag_bool.go | 4 ---- flag_duration.go | 4 ---- flag_float64.go | 4 ---- flag_float64_slice.go | 4 ---- flag_generic.go | 4 ---- flag_int.go | 4 ---- flag_int64.go | 4 ---- flag_int64_slice.go | 4 ---- flag_int_slice.go | 4 ---- flag_path.go | 4 ---- flag_string.go | 4 ---- flag_string_slice.go | 4 ---- flag_timestamp.go | 4 ---- flag_uint.go | 4 ---- flag_uint64.go | 4 ---- flag_uint64_slice.go | 4 ---- flag_uint_slice.go | 4 ---- 18 files changed, 46 insertions(+), 68 deletions(-) diff --git a/flag.go b/flag.go index 5762143f51..74a4c041c1 100644 --- a/flag.go +++ b/flag.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "os" + "reflect" "regexp" "runtime" "strings" @@ -182,10 +183,55 @@ type Countable interface { Count() int } +func rawFlagNames(f any) (string, []string, bool) { + if f == nil { + return "", nil, false + } + + rv := reflect.ValueOf(f) + for rv.Kind() == reflect.Pointer { + if rv.IsNil() { + return "", nil, false + } + rv = rv.Elem() + } + + if rv.Kind() != reflect.Struct { + return "", nil, false + } + + if target := rv.FieldByName("Target"); target.IsValid() { + if name, aliases, ok := rawFlagNames(target.Interface()); ok { + return name, aliases, true + } + } + + nameField := rv.FieldByName("Name") + if !nameField.IsValid() || nameField.Kind() != reflect.String { + return "", nil, false + } + + aliasesField := rv.FieldByName("Aliases") + var aliases []string + if aliasesField.IsValid() && aliasesField.Kind() == reflect.Slice && aliasesField.Type().Elem().Kind() == reflect.String { + aliases = make([]string, aliasesField.Len()) + for i := 0; i < aliasesField.Len(); i++ { + aliases[i] = aliasesField.Index(i).String() + } + } + + return nameField.String(), aliases, true +} + func flagSet(name string, flags []Flag, spec separatorSpec) (*flag.FlagSet, error) { set := flag.NewFlagSet(name, flag.ContinueOnError) for _, f := range flags { + if name, aliases, ok := rawFlagNames(f); ok { + if err := validateFlagNames(name, aliases); err != nil { + return nil, err + } + } if c, ok := f.(customizedSeparator); ok { c.WithSeparatorSpec(spec) } diff --git a/flag_bool.go b/flag_bool.go index 3319740003..01862ea764 100644 --- a/flag_bool.go +++ b/flag_bool.go @@ -106,10 +106,6 @@ func (f *BoolFlag) RunAction(c *Context) error { // Apply populates the flag given the flag set and environment func (f *BoolFlag) Apply(set *flag.FlagSet) error { - if err := validateFlagNames(f.Name, f.Aliases); err != nil { - return err - } - // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value f.defaultValueSet = true diff --git a/flag_duration.go b/flag_duration.go index 3fafd890c5..e600cc30ad 100644 --- a/flag_duration.go +++ b/flag_duration.go @@ -45,10 +45,6 @@ func (f *DurationFlag) GetEnvVars() []string { // Apply populates the flag given the flag set and environment func (f *DurationFlag) Apply(set *flag.FlagSet) error { - if err := validateFlagNames(f.Name, f.Aliases); err != nil { - return err - } - // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value f.defaultValueSet = true diff --git a/flag_float64.go b/flag_float64.go index d07f508fd4..6a4de5c88b 100644 --- a/flag_float64.go +++ b/flag_float64.go @@ -45,10 +45,6 @@ func (f *Float64Flag) GetEnvVars() []string { // Apply populates the flag given the flag set and environment func (f *Float64Flag) Apply(set *flag.FlagSet) error { - if err := validateFlagNames(f.Name, f.Aliases); err != nil { - return err - } - f.defaultValue = f.Value f.defaultValueSet = true diff --git a/flag_float64_slice.go b/flag_float64_slice.go index 8d88175644..0bc4612c82 100644 --- a/flag_float64_slice.go +++ b/flag_float64_slice.go @@ -138,10 +138,6 @@ func (f *Float64SliceFlag) IsSliceFlag() bool { // Apply populates the flag given the flag set and environment func (f *Float64SliceFlag) Apply(set *flag.FlagSet) error { - if err := validateFlagNames(f.Name, f.Aliases); err != nil { - return err - } - // apply any default if f.Destination != nil && f.Value != nil { f.Destination.slice = make([]float64, len(f.Value.slice)) diff --git a/flag_generic.go b/flag_generic.go index 92402c3faa..7528c934cd 100644 --- a/flag_generic.go +++ b/flag_generic.go @@ -73,10 +73,6 @@ func (f *GenericFlag) GetEnvVars() []string { // Apply takes the flagset and calls Set on the generic flag with the value // provided by the user for parsing by the flag func (f *GenericFlag) Apply(set *flag.FlagSet) error { - if err := validateFlagNames(f.Name, f.Aliases); err != nil { - return err - } - // set default value so that environment wont be able to overwrite it if f.Value != nil { f.defaultValue = &stringGeneric{value: f.Value.String()} diff --git a/flag_int.go b/flag_int.go index 2934706faa..750e7ebfc8 100644 --- a/flag_int.go +++ b/flag_int.go @@ -45,10 +45,6 @@ func (f *IntFlag) GetEnvVars() []string { // Apply populates the flag given the flag set and environment func (f *IntFlag) Apply(set *flag.FlagSet) error { - if err := validateFlagNames(f.Name, f.Aliases); err != nil { - return err - } - // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value f.defaultValueSet = true diff --git a/flag_int64.go b/flag_int64.go index 7683422743..688c267162 100644 --- a/flag_int64.go +++ b/flag_int64.go @@ -45,10 +45,6 @@ func (f *Int64Flag) GetEnvVars() []string { // Apply populates the flag given the flag set and environment func (f *Int64Flag) Apply(set *flag.FlagSet) error { - if err := validateFlagNames(f.Name, f.Aliases); err != nil { - return err - } - // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value f.defaultValueSet = true diff --git a/flag_int64_slice.go b/flag_int64_slice.go index ad489929fa..d45c2dd440 100644 --- a/flag_int64_slice.go +++ b/flag_int64_slice.go @@ -139,10 +139,6 @@ func (f *Int64SliceFlag) IsSliceFlag() bool { // Apply populates the flag given the flag set and environment func (f *Int64SliceFlag) Apply(set *flag.FlagSet) error { - if err := validateFlagNames(f.Name, f.Aliases); err != nil { - return err - } - // apply any default if f.Destination != nil && f.Value != nil { f.Destination.slice = make([]int64, len(f.Value.slice)) diff --git a/flag_int_slice.go b/flag_int_slice.go index 25d1e6c9d5..da9c09bc73 100644 --- a/flag_int_slice.go +++ b/flag_int_slice.go @@ -150,10 +150,6 @@ func (f *IntSliceFlag) IsSliceFlag() bool { // Apply populates the flag given the flag set and environment func (f *IntSliceFlag) Apply(set *flag.FlagSet) error { - if err := validateFlagNames(f.Name, f.Aliases); err != nil { - return err - } - // apply any default if f.Destination != nil && f.Value != nil { f.Destination.slice = make([]int, len(f.Value.slice)) diff --git a/flag_path.go b/flag_path.go index 64c81ea4f3..76cb35248c 100644 --- a/flag_path.go +++ b/flag_path.go @@ -50,10 +50,6 @@ func (f *PathFlag) GetEnvVars() []string { // Apply populates the flag given the flag set and environment func (f *PathFlag) Apply(set *flag.FlagSet) error { - if err := validateFlagNames(f.Name, f.Aliases); err != nil { - return err - } - // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value f.defaultValueSet = true diff --git a/flag_string.go b/flag_string.go index 5464635ab1..0f73e06215 100644 --- a/flag_string.go +++ b/flag_string.go @@ -49,10 +49,6 @@ func (f *StringFlag) GetEnvVars() []string { // Apply populates the flag given the flag set and environment func (f *StringFlag) Apply(set *flag.FlagSet) error { - if err := validateFlagNames(f.Name, f.Aliases); err != nil { - return err - } - // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value f.defaultValueSet = true diff --git a/flag_string_slice.go b/flag_string_slice.go index 8fba4c9f7f..66bdf1afcd 100644 --- a/flag_string_slice.go +++ b/flag_string_slice.go @@ -135,10 +135,6 @@ func (f *StringSliceFlag) IsSliceFlag() bool { // Apply populates the flag given the flag set and environment func (f *StringSliceFlag) Apply(set *flag.FlagSet) error { - if err := validateFlagNames(f.Name, f.Aliases); err != nil { - return err - } - // apply any default if f.Destination != nil && f.Value != nil { f.Destination.slice = make([]string, len(f.Value.slice)) diff --git a/flag_timestamp.go b/flag_timestamp.go index f515b87ae4..b90123087c 100644 --- a/flag_timestamp.go +++ b/flag_timestamp.go @@ -139,10 +139,6 @@ func (f *TimestampFlag) GetEnvVars() []string { // Apply populates the flag given the flag set and environment func (f *TimestampFlag) Apply(set *flag.FlagSet) error { - if err := validateFlagNames(f.Name, f.Aliases); err != nil { - return err - } - if f.Layout == "" { return fmt.Errorf("timestamp Layout is required") } diff --git a/flag_uint.go b/flag_uint.go index be0bc01c95..8d5b85458c 100644 --- a/flag_uint.go +++ b/flag_uint.go @@ -23,10 +23,6 @@ func (f *UintFlag) GetCategory() string { // Apply populates the flag given the flag set and environment func (f *UintFlag) Apply(set *flag.FlagSet) error { - if err := validateFlagNames(f.Name, f.Aliases); err != nil { - return err - } - // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value f.defaultValueSet = true diff --git a/flag_uint64.go b/flag_uint64.go index 58a2c9af21..c356e533ba 100644 --- a/flag_uint64.go +++ b/flag_uint64.go @@ -23,10 +23,6 @@ func (f *Uint64Flag) GetCategory() string { // Apply populates the flag given the flag set and environment func (f *Uint64Flag) Apply(set *flag.FlagSet) error { - if err := validateFlagNames(f.Name, f.Aliases); err != nil { - return err - } - // set default value so that environment wont be able to overwrite it f.defaultValue = f.Value f.defaultValueSet = true diff --git a/flag_uint64_slice.go b/flag_uint64_slice.go index c4d11bb226..d342018686 100644 --- a/flag_uint64_slice.go +++ b/flag_uint64_slice.go @@ -143,10 +143,6 @@ func (f *Uint64SliceFlag) IsSliceFlag() bool { // Apply populates the flag given the flag set and environment func (f *Uint64SliceFlag) Apply(set *flag.FlagSet) error { - if err := validateFlagNames(f.Name, f.Aliases); err != nil { - return err - } - // apply any default if f.Destination != nil && f.Value != nil { f.Destination.slice = make([]uint64, len(f.Value.slice)) diff --git a/flag_uint_slice.go b/flag_uint_slice.go index 074eaaca15..4dc13e126a 100644 --- a/flag_uint_slice.go +++ b/flag_uint_slice.go @@ -154,10 +154,6 @@ func (f *UintSliceFlag) IsSliceFlag() bool { // Apply populates the flag given the flag set and environment func (f *UintSliceFlag) Apply(set *flag.FlagSet) error { - if err := validateFlagNames(f.Name, f.Aliases); err != nil { - return err - } - // apply any default if f.Destination != nil && f.Value != nil { f.Destination.slice = make([]uint, len(f.Value.slice)) From da35cf81d4ef845876606212547db1c3f2f275ee Mon Sep 17 00:00:00 2001 From: Shirong Lu <73147033+happysnaker@users.noreply.github.com> Date: Thu, 2 Jul 2026 13:16:01 +0800 Subject: [PATCH 3/3] refactor: narrow legacy alias validation to Name field --- flag.go | 41 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/flag.go b/flag.go index 74a4c041c1..6368bccf06 100644 --- a/flag.go +++ b/flag.go @@ -27,17 +27,9 @@ var ( commaWhitespace = regexp.MustCompile("[, ]+.*") ) -func validateFlagNames(name string, aliases []string) error { +func validateFlagName(name string) error { if name != "" && (strings.Contains(name, ",") || strings.Contains(name, " ")) { - return fmt.Errorf("invalid flag name %q: use Name for the primary flag and Aliases for alternate names", name) - } - for _, alias := range aliases { - if alias == "" { - continue - } - if strings.Contains(alias, ",") || strings.Contains(alias, " ") { - return fmt.Errorf("invalid flag alias %q: aliases must be individual names without commas or spaces", alias) - } + return fmt.Errorf("invalid flag name %q: move alternate names to Aliases", name) } return nil } @@ -183,52 +175,43 @@ type Countable interface { Count() int } -func rawFlagNames(f any) (string, []string, bool) { +func rawFlagName(f any) (string, bool) { if f == nil { - return "", nil, false + return "", false } rv := reflect.ValueOf(f) for rv.Kind() == reflect.Pointer { if rv.IsNil() { - return "", nil, false + return "", false } rv = rv.Elem() } if rv.Kind() != reflect.Struct { - return "", nil, false + return "", false } if target := rv.FieldByName("Target"); target.IsValid() { - if name, aliases, ok := rawFlagNames(target.Interface()); ok { - return name, aliases, true + if name, ok := rawFlagName(target.Interface()); ok { + return name, true } } nameField := rv.FieldByName("Name") if !nameField.IsValid() || nameField.Kind() != reflect.String { - return "", nil, false - } - - aliasesField := rv.FieldByName("Aliases") - var aliases []string - if aliasesField.IsValid() && aliasesField.Kind() == reflect.Slice && aliasesField.Type().Elem().Kind() == reflect.String { - aliases = make([]string, aliasesField.Len()) - for i := 0; i < aliasesField.Len(); i++ { - aliases[i] = aliasesField.Index(i).String() - } + return "", false } - return nameField.String(), aliases, true + return nameField.String(), true } func flagSet(name string, flags []Flag, spec separatorSpec) (*flag.FlagSet, error) { set := flag.NewFlagSet(name, flag.ContinueOnError) for _, f := range flags { - if name, aliases, ok := rawFlagNames(f); ok { - if err := validateFlagNames(name, aliases); err != nil { + if name, ok := rawFlagName(f); ok { + if err := validateFlagName(name); err != nil { return nil, err } }