Skip to content

Commit 5af9500

Browse files
committed
fix: parse flags for help subcommand (urfave#2271)
PR urfave#2245 introduced a regression by short-circuiting pre-parse for any command named "help", which silently dropped flags and arguments on user-supplied help commands. Keep the pre-parse path intact and instead skip the required-flag enforcement for the help and completion commands, which was the actual goal of urfave#2245. Fixes urfave#2271
1 parent b79d768 commit 5af9500

3 files changed

Lines changed: 37 additions & 2 deletions

File tree

command.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,12 @@ func (cmd *Command) checkRequiredFlag(f Flag) (bool, string) {
408408
}
409409

410410
func (cmd *Command) checkAllRequiredFlags() requiredFlagsErr {
411+
// The help and completion commands are allowed to run without
412+
// enforcement of required flags, since they do not invoke user
413+
// actions that depend on those flag values.
414+
if cmd.Name == helpName || cmd.isCompletionCommand {
415+
return nil
416+
}
411417
for pCmd := cmd; pCmd != nil; pCmd = pCmd.parent {
412418
if err := pCmd.checkRequiredFlags(); err != nil {
413419
return err

command_run.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,8 @@ func (cmd *Command) run(ctx context.Context, osArgs []string) (_ context.Context
141141
var rargs Args = &stringSliceArgs{v: osArgs}
142142
var args Args = &stringSliceArgs{rargs.Tail()}
143143

144-
if cmd.isCompletionCommand || cmd.Name == helpName {
145-
tracef("special command detected, skipping pre-parse (cmd=%[1]q)", cmd.Name)
144+
if cmd.isCompletionCommand {
145+
tracef("completion command detected, skipping pre-parse (cmd=%[1]q)", cmd.Name)
146146
cmd.parsedArgs = args
147147
return ctx, cmd.Action(ctx, cmd)
148148
}

help_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,35 @@ GLOBAL OPTIONS:
164164
"expected output to include usage text")
165165
}
166166

167+
// Test_HelpCommand_ParsesFlags is a regression test for #2271: flags
168+
// declared on a user-supplied command named "help" must still be parsed.
169+
// Previously in v3.6.2 flag pre-parsing was skipped for any command named
170+
// "help", causing such flags to be silently dropped.
171+
func Test_HelpCommand_ParsesFlags(t *testing.T) {
172+
var parsed string
173+
174+
cmd := &Command{
175+
Name: "app",
176+
Commands: []*Command{
177+
{
178+
Name: "help",
179+
Flags: []Flag{
180+
&StringFlag{Name: "topic", Aliases: []string{"t"}},
181+
},
182+
Action: func(_ context.Context, c *Command) error {
183+
parsed = c.String("topic")
184+
return nil
185+
},
186+
},
187+
},
188+
}
189+
190+
err := cmd.Run(buildTestContext(t), []string{"app", "help", "--topic", "foo"})
191+
require.NoError(t, err)
192+
assert.Equal(t, "foo", parsed,
193+
"expected --topic flag on help subcommand to be parsed")
194+
}
195+
167196
func Test_Help_Custom_Flags(t *testing.T) {
168197
oldFlag := HelpFlag
169198
defer func() {

0 commit comments

Comments
 (0)