From c92cc07c1b9aca45a986ca3ce424e7be6b2ddee7 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Sat, 17 Aug 2024 10:00:23 -0400 Subject: [PATCH] ActiveHelp for cmds that don't take any more args The result is that when doing shell completion (bash and zsh only), instead of getting no suggestions for commands that take no more arguments, the user will instead be shown an informative message: $ helm list This command does not take any more arguments (but may accept flags). Signed-off-by: Marc Khouzam --- cmd/helm/completion.go | 22 +++++++++++++------ cmd/helm/create.go | 2 +- cmd/helm/docs.go | 2 +- cmd/helm/env.go | 2 +- cmd/helm/get_all.go | 2 +- cmd/helm/get_hooks.go | 2 +- cmd/helm/get_manifest.go | 2 +- cmd/helm/get_metadata.go | 2 +- cmd/helm/get_notes.go | 2 +- cmd/helm/get_values.go | 2 +- cmd/helm/history.go | 2 +- cmd/helm/list.go | 2 +- cmd/helm/plugin_install.go | 2 +- cmd/helm/plugin_list.go | 2 +- cmd/helm/push.go | 2 +- cmd/helm/registry_login.go | 2 +- cmd/helm/registry_logout.go | 2 +- cmd/helm/release_testing.go | 2 +- cmd/helm/repo_add.go | 13 +++++++---- cmd/helm/repo_index.go | 2 +- cmd/helm/repo_list.go | 2 +- cmd/helm/rollback.go | 2 +- cmd/helm/show.go | 13 +++++------ cmd/helm/status.go | 2 +- .../testdata/output/empty_nofile_comp.txt | 1 + .../output/rollback-wrong-args-comp.txt | 1 + .../output/status-wrong-args-comp.txt | 1 + cmd/helm/upgrade.go | 2 +- cmd/helm/verify.go | 2 +- cmd/helm/version.go | 2 +- 30 files changed, 57 insertions(+), 42 deletions(-) diff --git a/cmd/helm/completion.go b/cmd/helm/completion.go index 9f31ea741..3dc4bb916 100644 --- a/cmd/helm/completion.go +++ b/cmd/helm/completion.go @@ -102,7 +102,7 @@ func newCompletionCmd(out io.Writer) *cobra.Command { Short: "generate autocompletion script for bash", Long: bashCompDesc, Args: require.NoArgs, - ValidArgsFunction: noCompletions, + ValidArgsFunction: noMoreArgsCompFunc, RunE: func(cmd *cobra.Command, _ []string) error { return runCompletionBash(out, cmd) }, @@ -114,7 +114,7 @@ func newCompletionCmd(out io.Writer) *cobra.Command { Short: "generate autocompletion script for zsh", Long: zshCompDesc, Args: require.NoArgs, - ValidArgsFunction: noCompletions, + ValidArgsFunction: noMoreArgsCompFunc, RunE: func(cmd *cobra.Command, _ []string) error { return runCompletionZsh(out, cmd) }, @@ -126,7 +126,7 @@ func newCompletionCmd(out io.Writer) *cobra.Command { Short: "generate autocompletion script for fish", Long: fishCompDesc, Args: require.NoArgs, - ValidArgsFunction: noCompletions, + ValidArgsFunction: noMoreArgsCompFunc, RunE: func(cmd *cobra.Command, _ []string) error { return runCompletionFish(out, cmd) }, @@ -138,7 +138,7 @@ func newCompletionCmd(out io.Writer) *cobra.Command { Short: "generate autocompletion script for powershell", Long: powershellCompDesc, Args: require.NoArgs, - ValidArgsFunction: noCompletions, + ValidArgsFunction: noMoreArgsCompFunc, RunE: func(cmd *cobra.Command, _ []string) error { return runCompletionPowershell(out, cmd) }, @@ -209,7 +209,15 @@ func runCompletionPowershell(out io.Writer, cmd *cobra.Command) error { return cmd.Root().GenPowerShellCompletionWithDesc(out) } -// Function to disable file completion -func noCompletions(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) { - return nil, cobra.ShellCompDirectiveNoFileComp +// noMoreArgsCompFunc deactivates file completion when doing argument shell completion. +// It also provides some ActiveHelp to indicate no more arguments are accepted. +func noMoreArgsCompFunc(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) { + return noMoreArgsComp() +} + +// noMoreArgsComp deactivates file completion when doing argument shell completion. +// It also provides some ActiveHelp to indicate no more arguments are accepted. +func noMoreArgsComp() ([]string, cobra.ShellCompDirective) { + activeHelpMsg := "This command does not take any more arguments (but may accept flags)." + return cobra.AppendActiveHelp(nil, activeHelpMsg), cobra.ShellCompDirectiveNoFileComp } diff --git a/cmd/helm/create.go b/cmd/helm/create.go index b79752efb..576d8a70f 100644 --- a/cmd/helm/create.go +++ b/cmd/helm/create.go @@ -71,7 +71,7 @@ func newCreateCmd(out io.Writer) *cobra.Command { return nil, cobra.ShellCompDirectiveDefault } // No more completions, so disable file completion - return nil, cobra.ShellCompDirectiveNoFileComp + return noMoreArgsComp() }, RunE: func(_ *cobra.Command, args []string) error { o.name = args[0] diff --git a/cmd/helm/docs.go b/cmd/helm/docs.go index 182aeb9f6..dd0cf60c7 100644 --- a/cmd/helm/docs.go +++ b/cmd/helm/docs.go @@ -58,7 +58,7 @@ func newDocsCmd(out io.Writer) *cobra.Command { Long: docsDesc, Hidden: true, Args: require.NoArgs, - ValidArgsFunction: noCompletions, + ValidArgsFunction: noMoreArgsCompFunc, RunE: func(cmd *cobra.Command, _ []string) error { o.topCmd = cmd.Root() return o.run(out) diff --git a/cmd/helm/env.go b/cmd/helm/env.go index 83ee32895..d9c7f4565 100644 --- a/cmd/helm/env.go +++ b/cmd/helm/env.go @@ -42,7 +42,7 @@ func newEnvCmd(out io.Writer) *cobra.Command { return keys, cobra.ShellCompDirectiveNoFileComp } - return nil, cobra.ShellCompDirectiveNoFileComp + return noMoreArgsComp() }, Run: func(_ *cobra.Command, args []string) { envVars := settings.EnvVars() diff --git a/cmd/helm/get_all.go b/cmd/helm/get_all.go index 6c3f2c98c..f7af68213 100644 --- a/cmd/helm/get_all.go +++ b/cmd/helm/get_all.go @@ -43,7 +43,7 @@ func newGetAllCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Args: require.ExactArgs(1), ValidArgsFunction: func(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp + return noMoreArgsComp() } return compListReleases(toComplete, args, cfg) }, diff --git a/cmd/helm/get_hooks.go b/cmd/helm/get_hooks.go index 6ba5094e4..1fe7f0a25 100644 --- a/cmd/helm/get_hooks.go +++ b/cmd/helm/get_hooks.go @@ -43,7 +43,7 @@ func newGetHooksCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Args: require.ExactArgs(1), ValidArgsFunction: func(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp + return noMoreArgsComp() } return compListReleases(toComplete, args, cfg) }, diff --git a/cmd/helm/get_manifest.go b/cmd/helm/get_manifest.go index 0df100259..6431b4252 100644 --- a/cmd/helm/get_manifest.go +++ b/cmd/helm/get_manifest.go @@ -45,7 +45,7 @@ func newGetManifestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command Args: require.ExactArgs(1), ValidArgsFunction: func(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp + return noMoreArgsComp() } return compListReleases(toComplete, args, cfg) }, diff --git a/cmd/helm/get_metadata.go b/cmd/helm/get_metadata.go index 084323275..dbc7b6eff 100644 --- a/cmd/helm/get_metadata.go +++ b/cmd/helm/get_metadata.go @@ -42,7 +42,7 @@ func newGetMetadataCmd(cfg *action.Configuration, out io.Writer) *cobra.Command Args: require.ExactArgs(1), ValidArgsFunction: func(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp + return noMoreArgsComp() } return compListReleases(toComplete, args, cfg) }, diff --git a/cmd/helm/get_notes.go b/cmd/helm/get_notes.go index 6ac2a0450..b4c7ceddf 100644 --- a/cmd/helm/get_notes.go +++ b/cmd/helm/get_notes.go @@ -41,7 +41,7 @@ func newGetNotesCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Args: require.ExactArgs(1), ValidArgsFunction: func(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp + return noMoreArgsComp() } return compListReleases(toComplete, args, cfg) }, diff --git a/cmd/helm/get_values.go b/cmd/helm/get_values.go index c3fb8c252..54a15eda9 100644 --- a/cmd/helm/get_values.go +++ b/cmd/helm/get_values.go @@ -48,7 +48,7 @@ func newGetValuesCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Args: require.ExactArgs(1), ValidArgsFunction: func(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp + return noMoreArgsComp() } return compListReleases(toComplete, args, cfg) }, diff --git a/cmd/helm/history.go b/cmd/helm/history.go index 42796fab8..7edb4767c 100644 --- a/cmd/helm/history.go +++ b/cmd/helm/history.go @@ -62,7 +62,7 @@ func newHistoryCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Args: require.ExactArgs(1), ValidArgsFunction: func(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp + return noMoreArgsComp() } return compListReleases(toComplete, args, cfg) }, diff --git a/cmd/helm/list.go b/cmd/helm/list.go index 91922a66d..7e828c2b2 100644 --- a/cmd/helm/list.go +++ b/cmd/helm/list.go @@ -68,7 +68,7 @@ func newListCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Long: listHelp, Aliases: []string{"ls"}, Args: require.NoArgs, - ValidArgsFunction: noCompletions, + ValidArgsFunction: noMoreArgsCompFunc, RunE: func(cmd *cobra.Command, _ []string) error { if client.AllNamespaces { if err := cfg.Init(settings.RESTClientGetter(), "", os.Getenv("HELM_DRIVER"), debug); err != nil { diff --git a/cmd/helm/plugin_install.go b/cmd/helm/plugin_install.go index 9e3c399b5..0a96954f9 100644 --- a/cmd/helm/plugin_install.go +++ b/cmd/helm/plugin_install.go @@ -50,7 +50,7 @@ func newPluginInstallCmd(out io.Writer) *cobra.Command { return nil, cobra.ShellCompDirectiveDefault } // No more completion once the plugin path has been specified - return nil, cobra.ShellCompDirectiveNoFileComp + return noMoreArgsComp() }, PreRunE: func(_ *cobra.Command, args []string) error { return o.complete(args) diff --git a/cmd/helm/plugin_list.go b/cmd/helm/plugin_list.go index ed17d9e6b..8c73be500 100644 --- a/cmd/helm/plugin_list.go +++ b/cmd/helm/plugin_list.go @@ -30,7 +30,7 @@ func newPluginListCmd(out io.Writer) *cobra.Command { Use: "list", Aliases: []string{"ls"}, Short: "list installed Helm plugins", - ValidArgsFunction: noCompletions, + ValidArgsFunction: noMoreArgsCompFunc, RunE: func(_ *cobra.Command, _ []string) error { debug("pluginDirs: %s", settings.PluginsDirectory) plugins, err := plugin.FindPlugins(settings.PluginsDirectory) diff --git a/cmd/helm/push.go b/cmd/helm/push.go index f865c96bb..6ec26441d 100644 --- a/cmd/helm/push.go +++ b/cmd/helm/push.go @@ -65,7 +65,7 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { } return comps, cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace } - return nil, cobra.ShellCompDirectiveNoFileComp + return noMoreArgsComp() }, RunE: func(_ *cobra.Command, args []string) error { registryClient, err := newRegistryClient(o.certFile, o.keyFile, o.caFile, o.insecureSkipTLSverify, o.plainHTTP) diff --git a/cmd/helm/registry_login.go b/cmd/helm/registry_login.go index bfb163786..96020a530 100644 --- a/cmd/helm/registry_login.go +++ b/cmd/helm/registry_login.go @@ -53,7 +53,7 @@ func newRegistryLoginCmd(cfg *action.Configuration, out io.Writer) *cobra.Comman Short: "login to a registry", Long: registryLoginDesc, Args: require.MinimumNArgs(1), - ValidArgsFunction: noCompletions, + ValidArgsFunction: cobra.NoFileCompletions, RunE: func(_ *cobra.Command, args []string) error { hostname := args[0] diff --git a/cmd/helm/registry_logout.go b/cmd/helm/registry_logout.go index 61dae1da3..4ca4120c4 100644 --- a/cmd/helm/registry_logout.go +++ b/cmd/helm/registry_logout.go @@ -35,7 +35,7 @@ func newRegistryLogoutCmd(cfg *action.Configuration, out io.Writer) *cobra.Comma Short: "logout from a registry", Long: registryLogoutDesc, Args: require.MinimumNArgs(1), - ValidArgsFunction: noCompletions, + ValidArgsFunction: cobra.NoFileCompletions, RunE: func(_ *cobra.Command, args []string) error { hostname := args[0] return action.NewRegistryLogout(cfg).Run(out, hostname) diff --git a/cmd/helm/release_testing.go b/cmd/helm/release_testing.go index 7a4be5732..136d785d1 100644 --- a/cmd/helm/release_testing.go +++ b/cmd/helm/release_testing.go @@ -50,7 +50,7 @@ func newReleaseTestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command Args: require.ExactArgs(1), ValidArgsFunction: func(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp + return noMoreArgsComp() } return compListReleases(toComplete, args, cfg) }, diff --git a/cmd/helm/repo_add.go b/cmd/helm/repo_add.go index 83fcdf50c..6a8a70a0f 100644 --- a/cmd/helm/repo_add.go +++ b/cmd/helm/repo_add.go @@ -68,10 +68,15 @@ func newRepoAddCmd(out io.Writer) *cobra.Command { o := &repoAddOptions{} cmd := &cobra.Command{ - Use: "add [NAME] [URL]", - Short: "add a chart repository", - Args: require.ExactArgs(2), - ValidArgsFunction: noCompletions, + Use: "add [NAME] [URL]", + Short: "add a chart repository", + Args: require.ExactArgs(2), + ValidArgsFunction: func(_ *cobra.Command, args []string, _ string) ([]string, cobra.ShellCompDirective) { + if len(args) > 1 { + return noMoreArgsComp() + } + return nil, cobra.ShellCompDirectiveNoFileComp + }, RunE: func(_ *cobra.Command, args []string) error { o.name = args[0] o.url = args[1] diff --git a/cmd/helm/repo_index.go b/cmd/helm/repo_index.go index fb7ec811f..a2d72b771 100644 --- a/cmd/helm/repo_index.go +++ b/cmd/helm/repo_index.go @@ -60,7 +60,7 @@ func newRepoIndexCmd(out io.Writer) *cobra.Command { return nil, cobra.ShellCompDirectiveDefault } // No more completions, so disable file completion - return nil, cobra.ShellCompDirectiveNoFileComp + return noMoreArgsComp() }, RunE: func(_ *cobra.Command, args []string) error { o.dir = args[0] diff --git a/cmd/helm/repo_list.go b/cmd/helm/repo_list.go index 8abd20654..6c0b970be 100644 --- a/cmd/helm/repo_list.go +++ b/cmd/helm/repo_list.go @@ -36,7 +36,7 @@ func newRepoListCmd(out io.Writer) *cobra.Command { Aliases: []string{"ls"}, Short: "list chart repositories", Args: require.NoArgs, - ValidArgsFunction: noCompletions, + ValidArgsFunction: noMoreArgsCompFunc, RunE: func(_ *cobra.Command, _ []string) error { f, _ := repo.LoadFile(settings.RepositoryConfig) if len(f.Repositories) == 0 && !(outfmt == output.JSON || outfmt == output.YAML) { diff --git a/cmd/helm/rollback.go b/cmd/helm/rollback.go index 7e4c721f5..3dab4689f 100644 --- a/cmd/helm/rollback.go +++ b/cmd/helm/rollback.go @@ -55,7 +55,7 @@ func newRollbackCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { return compListRevisions(toComplete, cfg, args[0]) } - return nil, cobra.ShellCompDirectiveNoFileComp + return noMoreArgsComp() }, RunE: func(_ *cobra.Command, args []string) error { if len(args) > 1 { diff --git a/cmd/helm/show.go b/cmd/helm/show.go index 6b67dcdf4..7c06a2297 100644 --- a/cmd/helm/show.go +++ b/cmd/helm/show.go @@ -60,18 +60,17 @@ func newShowCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := action.NewShowWithConfig(action.ShowAll, cfg) showCommand := &cobra.Command{ - Use: "show", - Short: "show information of a chart", - Aliases: []string{"inspect"}, - Long: showDesc, - Args: require.NoArgs, - ValidArgsFunction: noCompletions, // Disable file completion + Use: "show", + Short: "show information of a chart", + Aliases: []string{"inspect"}, + Long: showDesc, + Args: require.NoArgs, } // Function providing dynamic auto-completion validArgsFunc := func(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp + return noMoreArgsComp() } return compListCharts(toComplete, true) } diff --git a/cmd/helm/status.go b/cmd/helm/status.go index 206c2d8cc..725b3f367 100644 --- a/cmd/helm/status.go +++ b/cmd/helm/status.go @@ -60,7 +60,7 @@ func newStatusCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { Args: require.ExactArgs(1), ValidArgsFunction: func(_ *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) != 0 { - return nil, cobra.ShellCompDirectiveNoFileComp + return noMoreArgsComp() } return compListReleases(toComplete, args, cfg) }, diff --git a/cmd/helm/testdata/output/empty_nofile_comp.txt b/cmd/helm/testdata/output/empty_nofile_comp.txt index 8d9fad576..3c537283e 100644 --- a/cmd/helm/testdata/output/empty_nofile_comp.txt +++ b/cmd/helm/testdata/output/empty_nofile_comp.txt @@ -1,2 +1,3 @@ +_activeHelp_ This command does not take any more arguments (but may accept flags). :4 Completion ended with directive: ShellCompDirectiveNoFileComp diff --git a/cmd/helm/testdata/output/rollback-wrong-args-comp.txt b/cmd/helm/testdata/output/rollback-wrong-args-comp.txt index 8d9fad576..3c537283e 100644 --- a/cmd/helm/testdata/output/rollback-wrong-args-comp.txt +++ b/cmd/helm/testdata/output/rollback-wrong-args-comp.txt @@ -1,2 +1,3 @@ +_activeHelp_ This command does not take any more arguments (but may accept flags). :4 Completion ended with directive: ShellCompDirectiveNoFileComp diff --git a/cmd/helm/testdata/output/status-wrong-args-comp.txt b/cmd/helm/testdata/output/status-wrong-args-comp.txt index 8d9fad576..3c537283e 100644 --- a/cmd/helm/testdata/output/status-wrong-args-comp.txt +++ b/cmd/helm/testdata/output/status-wrong-args-comp.txt @@ -1,2 +1,3 @@ +_activeHelp_ This command does not take any more arguments (but may accept flags). :4 Completion ended with directive: ShellCompDirectiveNoFileComp diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index e5dcd5b02..108550cbf 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -97,7 +97,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { if len(args) == 1 { return compListCharts(toComplete, true) } - return nil, cobra.ShellCompDirectiveNoFileComp + return noMoreArgsComp() }, RunE: func(_ *cobra.Command, args []string) error { client.Namespace = settings.Namespace() diff --git a/cmd/helm/verify.go b/cmd/helm/verify.go index f667a31e9..42d8bf8dc 100644 --- a/cmd/helm/verify.go +++ b/cmd/helm/verify.go @@ -50,7 +50,7 @@ func newVerifyCmd(out io.Writer) *cobra.Command { return nil, cobra.ShellCompDirectiveDefault } // No more completions, so disable file completion - return nil, cobra.ShellCompDirectiveNoFileComp + return noMoreArgsComp() }, RunE: func(_ *cobra.Command, args []string) error { err := client.Run(args[0]) diff --git a/cmd/helm/version.go b/cmd/helm/version.go index 409fc6fd9..12d0777f5 100644 --- a/cmd/helm/version.go +++ b/cmd/helm/version.go @@ -65,7 +65,7 @@ func newVersionCmd(out io.Writer) *cobra.Command { Short: "print the client version information", Long: versionDesc, Args: require.NoArgs, - ValidArgsFunction: noCompletions, + ValidArgsFunction: noMoreArgsCompFunc, RunE: func(_ *cobra.Command, _ []string) error { return o.run(out) },