Add completion for policy delete command (#1098)

This commit is contained in:
Enrico Candino
2026-07-31 16:39:25 +02:00
committed by GitHub
parent 15c4843fa6
commit f7a51524e9
4 changed files with 87 additions and 5 deletions
+1
View File
@@ -37,6 +37,7 @@ func createFlags(cmd *cobra.Command, cfg *CreateConfig) {
mustRegisterFlagCompletion(cmd, "mode", completeClusterMode)
mustRegisterFlagCompletion(cmd, "persistence-type", completePersistenceMode)
mustRegisterFlagCompletion(cmd, "policy", completePolicyNames)
if err := cmd.MarkFlagDirname("custom-certs"); err != nil {
logrus.Fatal(err)
+38
View File
@@ -18,6 +18,7 @@ var completeClusterMode = cobra.FixedCompletions(
[]string{
string(v1beta1.SharedClusterMode),
string(v1beta1.VirtualClusterMode),
string(v1beta1.HCPClusterMode),
},
cobra.ShellCompDirectiveNoFileComp,
)
@@ -73,6 +74,28 @@ func completeClusterNames(cmd *cobra.Command, args []string, toComplete string)
return clusterNameCompletions(cmd.Context(), cl, namespace)
}
// completePolicyNameArg is a cobra.CompletionFunc that completes a single policy name argument.
// It is the positional counterpart of completePolicyNames, which stays unguarded so that it can
// also be used as a flag completion, where args holds the positional arguments parsed so far.
func completePolicyNameArg(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// only the first positional argument is a policy name
if len(args) != 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
return completePolicyNames(cmd, args, toComplete)
}
// completePolicyNames is a cobra.CompletionFunc that completes with the k3k policy names.
func completePolicyNames(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
cl, err := completionClient(cmd)
if err != nil {
return nil, cobra.ShellCompDirectiveError
}
return policyNameCompletions(cmd.Context(), cl)
}
// namespaceCompletions lists every namespace in the host cluster, excluding any
// already provided to the command's "namespace" flag.
func namespaceCompletions(cmd *cobra.Command, cl client.Client) ([]string, cobra.ShellCompDirective) {
@@ -133,6 +156,21 @@ func clusterNameCompletions(ctx context.Context, cl client.Client, namespace str
return names, cobra.ShellCompDirectiveNoFileComp
}
// policyNameCompletions lists the k3k VirtualClusterPolicies by name.
func policyNameCompletions(ctx context.Context, cl client.Client) ([]string, cobra.ShellCompDirective) {
var policies v1beta1.VirtualClusterPolicyList
if err := cl.List(ctx, &policies); err != nil {
return nil, cobra.ShellCompDirectiveError
}
names := make([]string, 0, len(policies.Items))
for _, policy := range policies.Items {
names = append(names, policy.Name)
}
return names, cobra.ShellCompDirectiveNoFileComp
}
// mustRegisterFlagCompletion registers a completion function for a flag and
// aborts if the flag does not exist. This only fails on programmer error, so
// there is no reason to bubble it up to the caller.
+42
View File
@@ -36,6 +36,10 @@ func cluster(name, ns string) *v1beta1.Cluster {
return &v1beta1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: ns}}
}
func virtualClusterPolicy(name string) *v1beta1.VirtualClusterPolicy {
return &v1beta1.VirtualClusterPolicy{ObjectMeta: metav1.ObjectMeta{Name: name}}
}
func Test_completeNamespaces(t *testing.T) {
fakeClient := fake.NewClientBuilder().
WithScheme(completionTestScheme(t)).
@@ -127,3 +131,41 @@ func Test_completeClusterNames_filtersNamespace(t *testing.T) {
// only the clusters in the requested namespace
assert.ElementsMatch(t, []string{"k3k-bar/bar", "k3k-bar/bar-2"}, names)
}
func Test_completePolicyNames(t *testing.T) {
fakeClient := fake.NewClientBuilder().
WithScheme(completionTestScheme(t)).
WithObjects(
virtualClusterPolicy("foo"),
virtualClusterPolicy("bar"),
// policies are cluster scoped, so clusters and namespaces are not completed
namespace("k3k-foo"),
cluster("foo", "k3k-foo"),
).
Build()
names, directive := policyNameCompletions(t.Context(), fakeClient)
assert.Equal(t, cobra.ShellCompDirectiveNoFileComp, directive)
assert.ElementsMatch(t, []string{"foo", "bar"}, names)
}
func Test_completePolicyNames_empty(t *testing.T) {
fakeClient := fake.NewClientBuilder().
WithScheme(completionTestScheme(t)).
Build()
names, directive := policyNameCompletions(t.Context(), fakeClient)
// no policies is not an error
assert.Equal(t, cobra.ShellCompDirectiveNoFileComp, directive)
assert.Empty(t, names)
}
func Test_completeClusterMode(t *testing.T) {
modes, directive := completeClusterMode(&cobra.Command{}, nil, "")
assert.Equal(t, cobra.ShellCompDirectiveNoFileComp, directive)
// every mode accepted by validClusterModes must be completed
assert.ElementsMatch(t, []string{"shared", "virtual", "hcp"}, modes)
}
+6 -5
View File
@@ -11,11 +11,12 @@ import (
func NewPolicyDeleteCmd(appCtx *AppContext) *cobra.Command {
return &cobra.Command{
Use: "delete",
Short: "Delete an existing policy.",
Example: "k3kcli policy delete [command options] NAME",
RunE: policyDeleteAction(appCtx),
Args: cobra.ExactArgs(1),
Use: "delete",
Short: "Delete an existing policy.",
Example: "k3kcli policy delete [command options] NAME",
RunE: policyDeleteAction(appCtx),
Args: cobra.ExactArgs(1),
ValidArgsFunction: completePolicyNameArg,
}
}