From 4dec16803233a0cfd9a15a5635253e092072c0be Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Thu, 28 Aug 2025 21:06:02 -0700 Subject: [PATCH] Fix completion of resource names The output format is now used by the `Complete()` function, so it must be set before invoking said function. The commit also adds a unit tests for this scenario. Signed-off-by: Marc Khouzam Kubernetes-commit: f3d278e75d1137f1c91dde7415bc577af3c3be82 --- pkg/util/completion/completion.go | 4 +- pkg/util/completion/completion_test.go | 95 ++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/pkg/util/completion/completion.go b/pkg/util/completion/completion.go index 3c4d5a24c..dc62dad1f 100644 --- a/pkg/util/completion/completion.go +++ b/pkg/util/completion/completion.go @@ -319,14 +319,14 @@ func compGetResourceList(restClientGetter genericclioptions.RESTClientGetter, cm streams := genericiooptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: io.Discard} o := apiresources.NewAPIResourceOptions(streams) - o.Complete(restClientGetter, cmd, nil) - // Get the list of resources o.PrintFlags.OutputFormat = ptr.To("name") o.Cached = true o.Verbs = []string{"get"} // TODO:Should set --request-timeout=5s + o.Complete(restClientGetter, cmd, nil) + // Ignore errors as the output may still be valid o.RunAPIResources() diff --git a/pkg/util/completion/completion_test.go b/pkg/util/completion/completion_test.go index c1206f434..b1d8156f9 100644 --- a/pkg/util/completion/completion_test.go +++ b/pkg/util/completion/completion_test.go @@ -492,6 +492,101 @@ func TestResourceAndPortCompletionFunc(t *testing.T) { } } +func TestResourceTypeAndNameCompletionFuncResourceList(t *testing.T) { + // Set up a fake discovery client with some API resources + dc := cmdtesting.NewFakeCachedDiscoveryClient() + dc.PreferredResources = []*metav1.APIResourceList{ + { + GroupVersion: "v1", + APIResources: []metav1.APIResource{ + { + Name: "pods", + Namespaced: true, + Kind: "Pod", + Verbs: []string{"get", "list"}, + }, + { + Name: "services", + Namespaced: true, + Kind: "Service", + Verbs: []string{"get", "list"}, + }, + { + Name: "secrets", + Namespaced: true, + Kind: "Secret", + Verbs: []string{"get", "list"}, + }, + }, + }, + { + GroupVersion: "apps/v1", + APIResources: []metav1.APIResource{ + { + Name: "deployments", + Namespaced: true, + Kind: "Deployment", + Verbs: []string{"get", "list"}, + }, + }, + }, + } + + testCases := []struct { + name string + args []string + toComplete string + expectedComps []string + expectedDirective cobra.ShellCompDirective + }{ + { + name: "complete resources starting with 's'", + args: []string{}, + toComplete: "s", + expectedComps: []string{"secrets", "services"}, + expectedDirective: cobra.ShellCompDirectiveNoFileComp, + }, + { + name: "complete resources starting with 'p'", + args: []string{}, + toComplete: "p", + expectedComps: []string{"pods"}, + expectedDirective: cobra.ShellCompDirectiveNoFileComp, + }, + { + name: "complete resources starting with 'd'", + args: []string{}, + toComplete: "d", + expectedComps: []string{"deployments.apps"}, + expectedDirective: cobra.ShellCompDirectiveNoFileComp, + }, + { + name: "complete all resources with empty string", + args: []string{}, + toComplete: "", + expectedComps: []string{"deployments.apps", "pods", "secrets", "services"}, + expectedDirective: cobra.ShellCompDirectiveNoFileComp, + }, + { + name: "no matches", + args: []string{}, + toComplete: "xyz", + expectedComps: []string{}, + expectedDirective: cobra.ShellCompDirectiveNoFileComp, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + tf, cmd := prepareCompletionTest() + tf.WithDiscoveryClient(dc) + compFunc := ResourceTypeAndNameCompletionFunc(tf) + comps, directive := compFunc(cmd, tc.args, tc.toComplete) + checkCompletion(t, comps, tc.expectedComps, directive, tc.expectedDirective) + }) + } +} + func setMockFactory(config api.Config) { clientConfig := clientcmd.NewDefaultClientConfig(config, nil) testFactory := cmdtesting.NewTestFactory().WithClientConfig(clientConfig)