Skip to content

Commit b711e87

Browse files
authored
Don't complete --help flag when flag parsing disabled (#2061)
Fixes #2060 When a command sets `DisableFlagParsing = true` it requests the responsibility of doing all the flag parsing. Therefore even the `--help/-f/--version/-v` flags should not be automatically completed by Cobra in such a case. Without this change the `--help/-h/--version/-v` flags can end up being completed twice for plugins: one time from cobra and one time from the plugin (which has set `DisableFlagParsing = true`). Signed-off-by: Marc Khouzam <marc.khouzam@gmail.com>
1 parent 8b1eba4 commit b711e87

File tree

2 files changed

+55
-6
lines changed

2 files changed

+55
-6
lines changed

completions.go

+12-3
Original file line numberDiff line numberDiff line change
@@ -302,9 +302,13 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
302302

303303
// These flags are normally added when `execute()` is called on `finalCmd`,
304304
// however, when doing completion, we don't call `finalCmd.execute()`.
305-
// Let's add the --help and --version flag ourselves.
306-
finalCmd.InitDefaultHelpFlag()
307-
finalCmd.InitDefaultVersionFlag()
305+
// Let's add the --help and --version flag ourselves but only if the finalCmd
306+
// has not disabled flag parsing; if flag parsing is disabled, it is up to the
307+
// finalCmd itself to handle the completion of *all* flags.
308+
if !finalCmd.DisableFlagParsing {
309+
finalCmd.InitDefaultHelpFlag()
310+
finalCmd.InitDefaultVersionFlag()
311+
}
308312

309313
// Check if we are doing flag value completion before parsing the flags.
310314
// This is important because if we are completing a flag value, we need to also
@@ -408,6 +412,11 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
408412
finalCmd.InheritedFlags().VisitAll(func(flag *pflag.Flag) {
409413
doCompleteFlags(flag)
410414
})
415+
// Try to complete non-inherited flags even if DisableFlagParsing==true.
416+
// This allows programs to tell Cobra about flags for completion even
417+
// if the actual parsing of flags is not done by Cobra.
418+
// For instance, Helm uses this to provide flag name completion for
419+
// some of its plugins.
411420
finalCmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) {
412421
doCompleteFlags(flag)
413422
})

completions_test.go

+43-3
Original file line numberDiff line numberDiff line change
@@ -2622,8 +2622,6 @@ func TestCompleteWithDisableFlagParsing(t *testing.T) {
26222622
expected := strings.Join([]string{
26232623
"--persistent",
26242624
"-p",
2625-
"--help",
2626-
"-h",
26272625
"--nonPersistent",
26282626
"-n",
26292627
"--flag",
@@ -3053,8 +3051,26 @@ func TestCompletionCobraFlags(t *testing.T) {
30533051
return []string{"extra3"}, ShellCompDirectiveNoFileComp
30543052
},
30553053
}
3054+
childCmd4 := &Command{
3055+
Use: "child4",
3056+
Version: "1.1.1",
3057+
Run: emptyRun,
3058+
ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
3059+
return []string{"extra4"}, ShellCompDirectiveNoFileComp
3060+
},
3061+
DisableFlagParsing: true,
3062+
}
3063+
childCmd5 := &Command{
3064+
Use: "child5",
3065+
Version: "1.1.1",
3066+
Run: emptyRun,
3067+
ValidArgsFunction: func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
3068+
return []string{"extra5"}, ShellCompDirectiveNoFileComp
3069+
},
3070+
DisableFlagParsing: true,
3071+
}
30563072

3057-
rootCmd.AddCommand(childCmd, childCmd2, childCmd3)
3073+
rootCmd.AddCommand(childCmd, childCmd2, childCmd3, childCmd4, childCmd5)
30583074

30593075
_ = childCmd.Flags().Bool("bool", false, "A bool flag")
30603076
_ = childCmd.MarkFlagRequired("bool")
@@ -3066,6 +3082,10 @@ func TestCompletionCobraFlags(t *testing.T) {
30663082
// Have a command that only adds its own -v flag
30673083
_ = childCmd3.Flags().BoolP("verbose", "v", false, "Not a version flag")
30683084

3085+
// Have a command that DisablesFlagParsing but that also adds its own help and version flags
3086+
_ = childCmd5.Flags().BoolP("help", "h", false, "My own help")
3087+
_ = childCmd5.Flags().BoolP("version", "v", false, "My own version")
3088+
30693089
return rootCmd
30703090
}
30713091

@@ -3196,6 +3216,26 @@ func TestCompletionCobraFlags(t *testing.T) {
31963216
":4",
31973217
"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
31983218
},
3219+
{
3220+
desc: "no completion for --help/-h and --version/-v flags when DisableFlagParsing=true",
3221+
args: []string{"child4", "-"},
3222+
expectedOutput: strings.Join([]string{
3223+
"extra4",
3224+
":4",
3225+
"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3226+
},
3227+
{
3228+
desc: "completions for program-defined --help/-h and --version/-v flags even when DisableFlagParsing=true",
3229+
args: []string{"child5", "-"},
3230+
expectedOutput: strings.Join([]string{
3231+
"--help",
3232+
"-h",
3233+
"--version",
3234+
"-v",
3235+
"extra5",
3236+
":4",
3237+
"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n"),
3238+
},
31993239
}
32003240

32013241
for _, tc := range testcases {

0 commit comments

Comments
 (0)