Repository navigation
Conversation
With MapFlagKeyValueSeparator set, help still showed map flags with "=", in the type name and in the default value. The flag only parses the configured separator, so following the help failed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
yxshee
left a comment
There was a problem hiding this comment.
I ran this locally. The new test fails on main in all three cases and passes here, and go test ./..., gofmt and go vet are clean.
I also tried a few other ways of getting help with MapFlagKeyValueSeparator: ":" set on the root. app --help, app help, app sub --help and app sub -h all show string:string now. app help sub doesn't, though: the subcommand's own map flag still prints as --labels string=string [ --labels string=string ] (default: env="prod"). That path goes through DefaultShowCommandHelp, which renders subCmd without run ever reaching its flags, so the new line in command_run.go doesn't cover it.
Setting the config there before printing fixed it for me, for help sub and for help sub deep:
for _, f := range subCmd.Flags {
subCmd.setMultiValueParsingConfig(f)
}Adding {"app", "help", "sub"} to the cases in TestCommandMapKeyValueFlagSeparatorHelp catches it.
`app help sub` prints the subcommand's help without running it, so its map flags still showed the default `=` separator. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
good catch, thanks for testing it that thoroughly. fixed in c4c9886, |
Juneezee
left a comment
There was a problem hiding this comment.
Thanks! The bug is real: every path in the description and test shows = on main and the separator here.
One path still shows =. A command's map flag shows up in its subcommands' help, and app help sub deep prints it with =, because help never runs sub and the new loop only covers deep's own flags:
Lines 337 to 340 in c4c9886
cmd := &cli.Command{
Name: "app",
MapFlagKeyValueSeparator: ":",
Commands: []*cli.Command{{
Name: "sub",
Flags: []cli.Flag{&cli.StringMapFlag{Name: "labels", Value: map[string]string{"env": "prod"}}},
Commands: []*cli.Command{{Name: "deep"}},
}},
}$ app sub deep --help
...
GLOBAL OPTIONS:
--labels string:string [ --labels string:string ] (default: env:"prod")
$ app help sub deep
...
GLOBAL OPTIONS:
--labels string=string [ --labels string=string ] (default: env="prod")
Setting the config for every command once, in setupCommandGraph, fixes this and can replace both the new line in run and the new loop in DefaultShowCommandHelp:
Lines 176 to 186 in 025d953
_ = cmd.Walk(func(sub *Command) error {
// help can show a command's flags before it runs, or without running
// it, and a map flag's help shows the key-value separator
for _, f := range sub.allFlags() {
sub.setMultiValueParsingConfig(f)
}
for _, subCmd := range sub.Commands {Walk visits a command before its subcommands, and their parent is set during that visit, so the inherited separator resolves. PreParse replaces a flag's value but keeps multiValueConfig, which TypeName and GetValue read.
This test change catches it. It fails on this branch and passes with the change above:
{"app", "help", "sub"},
+ {"app", "help", "sub", "deep"},
{"app", "--labels", "env=prod"},
...
- Commands: []*Command{{Name: "sub", Flags: []Flag{labels()}}},
+ Commands: []*Command{{Name: "sub", Flags: []Flag{labels()}, Commands: []*Command{{Name: "deep"}}}},With both changes on top of current main, go test -race ./..., the three build tags, go vet and golangci-lint pass.
Please also update the description: it doesn't mention the help sub fix from c4c9886, and its third bullet describes the line in run.
What type of PR is this?
What this PR does / why we need it:
With
MapFlagKeyValueSeparatorset, help still shows map flags with=:The flag only parses
env:prod, though.--labels env=prodfails withitem "env=prod" is missing separator ":", and the help printed after that error still saysstring=string.There were two causes.
TypeNameandMapBase.ToStringalways used the default=. And--help, or the help after a usage error, is shown before the post-parse loop that passes each flag the command's parsing config, so the flag didn't know the separator yet. Now:multiValueParsingConfig.mapKeyValueSeparator()returns the configured separator or=.MapBase.Set,MapBase.ToStringandTypeNameall use it.GetValuepasses the flag's parsing config to the value it formats the default with.runpasses each flag its parsing config right afterPreParse, so help sees it.setalready passes the same config before parsing a value, so parsing doesn't change.With the change, help shows
--labels string:string [ --labels string:string ] (default: env:"prod").Which issue(s) this PR fixes:
None, found while checking how map flags render in help.
Testing
TestCommandMapKeyValueFlagSeparatorHelpcovers--helpon the root,--helpon a subcommand that inherits the separator, and the help printed after a usage error. It fails onmain.make generate vet check-binary-sizeandmake v3diffpass, with no API change.go test -race ./...passes, as do the tests withurfave_cli_no_template,urfave_cli_no_docsandurfave_cli_no_suggest.The change and the test were written with Claude Code (AI).
Release Notes
🤖 Generated with Claude Code