Support completion for the <type>/<name> form
This commit teaches the shell completion logic how to handle the <type>/<name> form for resource specification. It also teaches the 'exec' command how to complete its '--container/-c' flag using container names. Also, for commands that work on pods, kubectl will now also suggest completion choices of the form <type>/<name> for resource types that contain pods (see below for more details). The following commands can now have completion of the <type>/<name> form. Commands that accept any resource type: annotate apply edit-last-applied apply view-last-applied delete describe edit get label patch Commands that accept a subset of resource types: autoscale expose rollout history rollout pause rollout restart rollout resume rollout status rollout undo scale taint Commands that apply to resource types that contain pods: attach exec logs port-foward For these last four commands, the possible resource types are now included in the completion choices. For example: kubectl exec d<TAB> will suggest daemonsets/ deployments/ Signed-off-by: Marc Khouzam <marc.khouzam@montreal.ca> Kubernetes-commit: cf66f5c3cbd0a0e2f223af438ee4c6bc7e4a907c
This commit is contained in:
parent
a1f04cb16d
commit
cd245d2e22
|
@ -105,7 +105,7 @@ func NewCmdAttach(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra
|
|||
Short: i18n.T("Attach to a running container"),
|
||||
Long: i18n.T("Attach to a process that is already running inside an existing container."),
|
||||
Example: attachExample,
|
||||
ValidArgsFunction: util.ResourceNameCompletionFunc(f, "pod"),
|
||||
ValidArgsFunction: util.PodResourceNameCompletionFunc(f),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
|
|
|
@ -89,7 +89,7 @@ func NewCmdExec(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.C
|
|||
Short: i18n.T("Execute a command in a container"),
|
||||
Long: i18n.T("Execute a command in a container."),
|
||||
Example: execExample,
|
||||
ValidArgsFunction: util.ResourceNameCompletionFunc(f, "pod"),
|
||||
ValidArgsFunction: util.PodResourceNameCompletionFunc(f),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
argsLenAtDash := cmd.ArgsLenAtDash()
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args, argsLenAtDash))
|
||||
|
@ -101,6 +101,8 @@ func NewCmdExec(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.C
|
|||
cmdutil.AddJsonFilenameFlag(cmd.Flags(), &options.FilenameOptions.Filenames, "to use to exec into the resource")
|
||||
// TODO support UID
|
||||
cmdutil.AddContainerVarFlags(cmd, &options.ContainerName, options.ContainerName)
|
||||
cmdutil.CheckErr(cmd.RegisterFlagCompletionFunc("container", util.ContainerCompletionFunc(f)))
|
||||
|
||||
cmd.Flags().BoolVarP(&options.Stdin, "stdin", "i", options.Stdin, "Pass stdin to the container")
|
||||
cmd.Flags().BoolVarP(&options.TTY, "tty", "t", options.TTY, "Stdin is a TTY")
|
||||
cmd.Flags().BoolVarP(&options.Quiet, "quiet", "q", options.Quiet, "Only print output from the remote session")
|
||||
|
|
|
@ -170,18 +170,7 @@ func NewCmdGet(parent string, f cmdutil.Factory, streams genericclioptions.IOStr
|
|||
Short: i18n.T("Display one or many resources"),
|
||||
Long: getLong + "\n\n" + cmdutil.SuggestAPIResources(parent),
|
||||
Example: getExample,
|
||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
var comps []string
|
||||
if len(args) == 0 {
|
||||
comps = apiresources.CompGetResourceList(f, cmd, toComplete)
|
||||
} else {
|
||||
comps = CompGetResource(f, cmd, args[0], toComplete)
|
||||
if len(args) > 1 {
|
||||
comps = cmdutil.Difference(comps, args[1:])
|
||||
}
|
||||
}
|
||||
return comps, cobra.ShellCompDirectiveNoFileComp
|
||||
},
|
||||
ValidArgsFunction: ResourceTypeAndNameCompletionFunc(f, nil, true),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Validate(cmd))
|
||||
|
@ -932,3 +921,82 @@ func CompGetFromTemplate(template *string, f cmdutil.Factory, namespace string,
|
|||
}
|
||||
return comps
|
||||
}
|
||||
|
||||
// ResourceTypeAndNameCompletionFunc Returns a completion function that completes resource types
|
||||
// and resource names that match the toComplete prefix. It supports the <type>/<name> form.
|
||||
func ResourceTypeAndNameCompletionFunc(f cmdutil.Factory, allowedTypes []string, allowRepeat bool) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
var comps []string
|
||||
directive := cobra.ShellCompDirectiveNoFileComp
|
||||
|
||||
if len(args) > 0 && !strings.Contains(args[0], "/") {
|
||||
// The first argument is of the form <type> (e.g., pods)
|
||||
// All following arguments should be a resource name.
|
||||
if allowRepeat || len(args) == 1 {
|
||||
comps = CompGetResource(f, cmd, args[0], toComplete)
|
||||
|
||||
// Remove choices already on the command-line
|
||||
if len(args) > 1 {
|
||||
comps = cmdutil.Difference(comps, args[1:])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
slashIdx := strings.Index(toComplete, "/")
|
||||
if slashIdx == -1 {
|
||||
if len(args) == 0 {
|
||||
// We are completing the first argument. We default to the normal
|
||||
// <type> form (not the form <type>/<name>).
|
||||
// So we suggest resource types and let the shell add a space after
|
||||
// the completion.
|
||||
if len(allowedTypes) == 0 {
|
||||
comps = apiresources.CompGetResourceList(f, cmd, toComplete)
|
||||
} else {
|
||||
for _, c := range allowedTypes {
|
||||
if strings.HasPrefix(c, toComplete) {
|
||||
comps = append(comps, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Here we know the first argument contains a / (<type>/<name>).
|
||||
// All other arguments must also use that form.
|
||||
if allowRepeat {
|
||||
// Since toComplete does not already contain a / we know we are completing a
|
||||
// resource type. Disable adding a space after the completion, and add the /
|
||||
directive |= cobra.ShellCompDirectiveNoSpace
|
||||
|
||||
if len(allowedTypes) == 0 {
|
||||
typeComps := apiresources.CompGetResourceList(f, cmd, toComplete)
|
||||
for _, c := range typeComps {
|
||||
comps = append(comps, fmt.Sprintf("%s/", c))
|
||||
}
|
||||
} else {
|
||||
for _, c := range allowedTypes {
|
||||
if strings.HasPrefix(c, toComplete) {
|
||||
comps = append(comps, fmt.Sprintf("%s/", c))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We are completing an argument of the form <type>/<name>
|
||||
// and since the / is already present, we are completing the resource name.
|
||||
if allowRepeat || len(args) == 0 {
|
||||
resourceType := toComplete[:slashIdx]
|
||||
toComplete = toComplete[slashIdx+1:]
|
||||
nameComps := CompGetResource(f, cmd, resourceType, toComplete)
|
||||
for _, c := range nameComps {
|
||||
comps = append(comps, fmt.Sprintf("%s/%s", resourceType, c))
|
||||
}
|
||||
|
||||
// Remove choices already on the command-line.
|
||||
if len(args) > 0 {
|
||||
comps = cmdutil.Difference(comps, args[0:])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return comps, directive
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ func NewCmdPortForward(f cmdutil.Factory, streams genericclioptions.IOStreams) *
|
|||
Short: i18n.T("Forward one or more local ports to a pod"),
|
||||
Long: portforwardLong,
|
||||
Example: portforwardExample,
|
||||
ValidArgsFunction: util.ResourceNameCompletionFunc(f, "pod"),
|
||||
ValidArgsFunction: util.PodResourceNameCompletionFunc(f),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(opts.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(opts.Validate())
|
||||
|
|
|
@ -17,12 +17,15 @@ limitations under the License.
|
|||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/kubectl/pkg/cmd/apiresources"
|
||||
"k8s.io/kubectl/pkg/cmd/get"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
"k8s.io/kubectl/pkg/polymorphichelpers"
|
||||
"k8s.io/kubectl/pkg/scheme"
|
||||
)
|
||||
|
||||
var factory cmdutil.Factory
|
||||
|
@ -33,61 +36,32 @@ func SetFactoryForCompletion(f cmdutil.Factory) {
|
|||
factory = f
|
||||
}
|
||||
|
||||
// ResourceTypeAndNameCompletionFunc Returns a completion function that completes as a first argument
|
||||
// the resource types that match the toComplete prefix, and all following arguments as resource names that match
|
||||
// the toComplete prefix.
|
||||
// ResourceTypeAndNameCompletionFunc Returns a completion function that completes resource types
|
||||
// and resource names that match the toComplete prefix. It supports the <type>/<name> form.
|
||||
func ResourceTypeAndNameCompletionFunc(f cmdutil.Factory) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
var comps []string
|
||||
if len(args) == 0 {
|
||||
comps = apiresources.CompGetResourceList(f, cmd, toComplete)
|
||||
} else {
|
||||
comps = get.CompGetResource(f, cmd, args[0], toComplete)
|
||||
if len(args) > 1 {
|
||||
comps = cmdutil.Difference(comps, args[1:])
|
||||
}
|
||||
}
|
||||
return comps, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
// The logic is in the 'get' package because the 'get' command must be able to call it also
|
||||
return get.ResourceTypeAndNameCompletionFunc(f, nil, true)
|
||||
}
|
||||
|
||||
// SpecifiedResourceTypeAndNameCompletionFunc Returns a completion function that completes as a first
|
||||
// argument the resource types that match the toComplete prefix and are limited to the allowedTypes,
|
||||
// and all following arguments as resource names that match the toComplete prefix.
|
||||
// SpecifiedResourceTypeAndNameCompletionFunc Returns a completion function that completes resource
|
||||
// types limited to the specified allowedTypes, and resource names that match the toComplete prefix.
|
||||
// It allows for multiple resources. It supports the <type>/<name> form.
|
||||
func SpecifiedResourceTypeAndNameCompletionFunc(f cmdutil.Factory, allowedTypes []string) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
|
||||
return doSpecifiedResourceTypeAndNameComp(f, allowedTypes, true)
|
||||
return get.ResourceTypeAndNameCompletionFunc(f, allowedTypes, true)
|
||||
}
|
||||
|
||||
// SpecifiedResourceTypeAndNameNoRepeatCompletionFunc Returns a completion function that completes as a first
|
||||
// argument the resource types that match the toComplete prefix and are limited to the allowedTypes, and as
|
||||
// a second argument a resource name that match the toComplete prefix.
|
||||
// SpecifiedResourceTypeAndNameNoRepeatCompletionFunc Returns a completion function that completes resource
|
||||
// types limited to the specified allowedTypes, and resource names that match the toComplete prefix.
|
||||
// It only allows for one resource. It supports the <type>/<name> form.
|
||||
func SpecifiedResourceTypeAndNameNoRepeatCompletionFunc(f cmdutil.Factory, allowedTypes []string) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
|
||||
return doSpecifiedResourceTypeAndNameComp(f, allowedTypes, false)
|
||||
}
|
||||
|
||||
func doSpecifiedResourceTypeAndNameComp(f cmdutil.Factory, allowedTypes []string, repeat bool) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
var comps []string
|
||||
if len(args) == 0 {
|
||||
for _, comp := range allowedTypes {
|
||||
if strings.HasPrefix(comp, toComplete) {
|
||||
comps = append(comps, comp)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if repeat || len(args) == 1 {
|
||||
comps = get.CompGetResource(f, cmd, args[0], toComplete)
|
||||
if repeat && len(args) > 1 {
|
||||
comps = cmdutil.Difference(comps, args[1:])
|
||||
}
|
||||
}
|
||||
}
|
||||
return comps, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
return get.ResourceTypeAndNameCompletionFunc(f, allowedTypes, false)
|
||||
}
|
||||
|
||||
// ResourceNameCompletionFunc Returns a completion function that completes as a first argument
|
||||
// the resource names specified by the resourceType parameter, and which match the toComplete prefix.
|
||||
// This function does NOT support the <type>/<name> form: it is meant to be used by commands
|
||||
// that don't support that form. For commands that apply to pods and that support the <type>/<name>
|
||||
// form, please use PodResourceNameCompletionFunc()
|
||||
func ResourceNameCompletionFunc(f cmdutil.Factory, resourceType string) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
var comps []string
|
||||
|
@ -98,16 +72,49 @@ func ResourceNameCompletionFunc(f cmdutil.Factory, resourceType string) func(*co
|
|||
}
|
||||
}
|
||||
|
||||
// PodResourceNameAndContainerCompletionFunc Returns a completion function that completes as a first
|
||||
// argument pod names that match the toComplete prefix, and as a second argument the containers
|
||||
// within the specified pod.
|
||||
// PodResourceNameCompletionFunc Returns a completion function that completes:
|
||||
// 1- pod names that match the toComplete prefix
|
||||
// 2- resource types containing pods which match the toComplete prefix
|
||||
func PodResourceNameCompletionFunc(f cmdutil.Factory) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
var comps []string
|
||||
directive := cobra.ShellCompDirectiveNoFileComp
|
||||
if len(args) == 0 {
|
||||
comps, directive = doPodResourceCompletion(f, cmd, toComplete)
|
||||
}
|
||||
return comps, directive
|
||||
}
|
||||
}
|
||||
|
||||
// PodResourceNameAndContainerCompletionFunc Returns a completion function that completes, as a first argument:
|
||||
// 1- pod names that match the toComplete prefix
|
||||
// 2- resource types containing pods which match the toComplete prefix
|
||||
// and as a second argument the containers within the specified pod.
|
||||
func PodResourceNameAndContainerCompletionFunc(f cmdutil.Factory) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
var comps []string
|
||||
directive := cobra.ShellCompDirectiveNoFileComp
|
||||
if len(args) == 0 {
|
||||
comps = get.CompGetResource(f, cmd, "pod", toComplete)
|
||||
comps, directive = doPodResourceCompletion(f, cmd, toComplete)
|
||||
} else if len(args) == 1 {
|
||||
comps = get.CompGetContainers(f, cmd, args[0], toComplete)
|
||||
podName := convertResourceNameToPodName(f, args[0])
|
||||
comps = get.CompGetContainers(f, cmd, podName, toComplete)
|
||||
}
|
||||
return comps, directive
|
||||
}
|
||||
}
|
||||
|
||||
// ContainerCompletionFunc Returns a completion function that completes the containers within the
|
||||
// pod specified by the first argument. The resource containing the pod can be specified in
|
||||
// the <type>/<name> form.
|
||||
func ContainerCompletionFunc(f cmdutil.Factory) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
|
||||
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
var comps []string
|
||||
// We need the pod name to be able to complete the container names, it must be in args[0].
|
||||
// That first argument can also be of the form <type>/<name> so we need to convert it.
|
||||
if len(args) > 0 {
|
||||
podName := convertResourceNameToPodName(f, args[0])
|
||||
comps = get.CompGetContainers(f, cmd, podName, toComplete)
|
||||
}
|
||||
return comps, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
@ -184,3 +191,85 @@ func ListUsersInConfig(toComplete string) []string {
|
|||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// doPodResourceCompletion Returns completions of:
|
||||
// 1- pod names that match the toComplete prefix
|
||||
// 2- resource types containing pods which match the toComplete prefix
|
||||
func doPodResourceCompletion(f cmdutil.Factory, cmd *cobra.Command, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
var comps []string
|
||||
directive := cobra.ShellCompDirectiveNoFileComp
|
||||
slashIdx := strings.Index(toComplete, "/")
|
||||
if slashIdx == -1 {
|
||||
// Standard case, complete pod names
|
||||
comps = get.CompGetResource(f, cmd, "pod", toComplete)
|
||||
|
||||
// Also include resource choices for the <type>/<name> form,
|
||||
// but only for resources that contain pods
|
||||
resourcesWithPods := []string{
|
||||
"daemonsets",
|
||||
"deployments",
|
||||
"pods",
|
||||
"jobs",
|
||||
"replicasets",
|
||||
"replicationcontrollers",
|
||||
"services",
|
||||
"statefulsets"}
|
||||
|
||||
if len(comps) == 0 {
|
||||
// If there are no pods to complete, we will only be completing
|
||||
// <type>/. We should disable adding a space after the /.
|
||||
directive |= cobra.ShellCompDirectiveNoSpace
|
||||
}
|
||||
|
||||
for _, resource := range resourcesWithPods {
|
||||
if strings.HasPrefix(resource, toComplete) {
|
||||
comps = append(comps, fmt.Sprintf("%s/", resource))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Dealing with the <type>/<name> form, use the specified resource type
|
||||
resourceType := toComplete[:slashIdx]
|
||||
toComplete = toComplete[slashIdx+1:]
|
||||
nameComps := get.CompGetResource(f, cmd, resourceType, toComplete)
|
||||
for _, c := range nameComps {
|
||||
comps = append(comps, fmt.Sprintf("%s/%s", resourceType, c))
|
||||
}
|
||||
}
|
||||
return comps, directive
|
||||
}
|
||||
|
||||
// convertResourceNameToPodName Converts a resource name to a pod name.
|
||||
// If the resource name is of the form <type>/<name>, we use
|
||||
// polymorphichelpers.AttachablePodForObjectFn(), if not, the resource name
|
||||
// is already a pod name.
|
||||
func convertResourceNameToPodName(f cmdutil.Factory, resourceName string) string {
|
||||
var podName string
|
||||
if !strings.Contains(resourceName, "/") {
|
||||
// When we don't have the <type>/<name> form, the resource name is the pod name
|
||||
podName = resourceName
|
||||
} else {
|
||||
// if the resource name is of the form <type>/<name>, we need to convert it to a pod name
|
||||
ns, _, err := f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
resourceWithPod, err := f.NewBuilder().
|
||||
WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
|
||||
ContinueOnError().
|
||||
NamespaceParam(ns).DefaultNamespace().
|
||||
ResourceNames("pods", resourceName).
|
||||
Do().Object()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
// For shell completion, use a short timeout
|
||||
forwardablePod, err := polymorphichelpers.AttachablePodForObjectFn(f, resourceWithPod, 100*time.Millisecond)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
podName = forwardablePod.Name
|
||||
}
|
||||
return podName
|
||||
}
|
||||
|
|
|
@ -127,6 +127,25 @@ func TestResourceTypeAndNameCompletionFuncRepeating(t *testing.T) {
|
|||
checkCompletion(t, comps, []string{"foo"}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
|
||||
func TestResourceTypeAndNameCompletionFuncJointForm(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
||||
compFunc := ResourceTypeAndNameCompletionFunc(tf)
|
||||
comps, directive := compFunc(cmd, []string{}, "pod/b")
|
||||
checkCompletion(t, comps, []string{"pod/bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
|
||||
func TestResourceTypeAndNameCompletionFuncJointFormRepeating(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
||||
compFunc := ResourceTypeAndNameCompletionFunc(tf)
|
||||
comps, directive := compFunc(cmd, []string{"pod/bar"}, "pod/")
|
||||
// The other pods should be completed, but not the already specified ones
|
||||
checkCompletion(t, comps, []string{"pod/foo"}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
|
||||
func TestSpecifiedResourceTypeAndNameCompletionFuncNoArgs(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
@ -155,6 +174,24 @@ func TestSpecifiedResourceTypeAndNameCompletionFuncRepeating(t *testing.T) {
|
|||
checkCompletion(t, comps, []string{"foo"}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
|
||||
func TestSpecifiedResourceTypeAndNameCompletionFuncJointFormOneArg(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
||||
compFunc := SpecifiedResourceTypeAndNameCompletionFunc(tf, []string{"pod"})
|
||||
comps, directive := compFunc(cmd, []string{}, "pod/b")
|
||||
checkCompletion(t, comps, []string{"pod/bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
|
||||
func TestSpecifiedResourceTypeAndNameCompletionFuncJointFormRepeating(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
||||
compFunc := SpecifiedResourceTypeAndNameCompletionFunc(tf, []string{"pod"})
|
||||
comps, directive := compFunc(cmd, []string{"pod/bar"}, "pod/")
|
||||
// The other pods should be completed, but not the already specified ones
|
||||
checkCompletion(t, comps, []string{"pod/foo"}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
func TestSpecifiedResourceTypeAndNameCompletionNoRepeatFuncOneArg(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
@ -174,6 +211,25 @@ func TestSpecifiedResourceTypeAndNameCompletionNoRepeatFuncMultiArg(t *testing.T
|
|||
checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
|
||||
func TestSpecifiedResourceTypeAndNameCompletionNoRepeatFuncJointFormOneArg(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
||||
compFunc := SpecifiedResourceTypeAndNameNoRepeatCompletionFunc(tf, []string{"pod"})
|
||||
comps, directive := compFunc(cmd, []string{}, "pod/b")
|
||||
checkCompletion(t, comps, []string{"pod/bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
|
||||
func TestSpecifiedResourceTypeAndNameCompletionNoRepeatFuncJointFormMultiArg(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
||||
compFunc := SpecifiedResourceTypeAndNameNoRepeatCompletionFunc(tf, []string{"pod"})
|
||||
comps, directive := compFunc(cmd, []string{"pod/bar"}, "pod/")
|
||||
// There should not be any more pods shown as this function should not repeat the completion
|
||||
checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
|
||||
func TestResourceNameCompletionFuncNoArgs(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
@ -192,7 +248,65 @@ func TestResourceNameCompletionFuncTooManyArgs(t *testing.T) {
|
|||
checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
|
||||
func TestPodResourceNameAndContainerCompletionFuncNoArgs(t *testing.T) {
|
||||
func TestResourceNameCompletionFuncJointFormNoArgs(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
||||
compFunc := ResourceNameCompletionFunc(tf, "pod")
|
||||
comps, directive := compFunc(cmd, []string{}, "pod/b")
|
||||
// The <type>/<name> should NOT be supported by this function
|
||||
checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
|
||||
func TestPodResourceNameCompletionFuncNoArgsPodName(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
||||
compFunc := PodResourceNameCompletionFunc(tf)
|
||||
comps, directive := compFunc(cmd, []string{}, "b")
|
||||
checkCompletion(t, comps, []string{"bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
|
||||
func TestPodResourceNameCompletionFuncNoArgsResources(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
||||
compFunc := PodResourceNameCompletionFunc(tf)
|
||||
comps, directive := compFunc(cmd, []string{}, "d")
|
||||
checkCompletion(
|
||||
t, comps, []string{"daemonsets/", "deployments/"},
|
||||
directive, cobra.ShellCompDirectiveNoFileComp|cobra.ShellCompDirectiveNoSpace)
|
||||
}
|
||||
|
||||
func TestPodResourceNameCompletionFuncTooManyArgs(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
||||
compFunc := PodResourceNameCompletionFunc(tf)
|
||||
comps, directive := compFunc(cmd, []string{"pod-name"}, "")
|
||||
checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
|
||||
func TestPodResourceNameCompletionFuncJointFormNoArgs(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
||||
compFunc := PodResourceNameCompletionFunc(tf)
|
||||
comps, directive := compFunc(cmd, []string{}, "pod/b")
|
||||
// The <type>/<name> SHOULD be supported by this function
|
||||
checkCompletion(t, comps, []string{"pod/bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
|
||||
func TestPodResourceNameCompletionFuncJointFormTooManyArgs(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
||||
compFunc := PodResourceNameCompletionFunc(tf)
|
||||
comps, directive := compFunc(cmd, []string{"pod/name"}, "pod/b")
|
||||
checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
|
||||
func TestPodResourceNameAndContainerCompletionFuncNoArgsPodName(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
||||
|
@ -201,6 +315,18 @@ func TestPodResourceNameAndContainerCompletionFuncNoArgs(t *testing.T) {
|
|||
checkCompletion(t, comps, []string{"bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
|
||||
func TestPodResourceNameAndContainerCompletionFuncNoArgsResources(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
||||
compFunc := PodResourceNameAndContainerCompletionFunc(tf)
|
||||
comps, directive := compFunc(cmd, []string{}, "s")
|
||||
checkCompletion(
|
||||
t, comps, []string{"services/", "statefulsets/"},
|
||||
directive, cobra.ShellCompDirectiveNoFileComp|cobra.ShellCompDirectiveNoSpace)
|
||||
|
||||
}
|
||||
|
||||
func TestPodResourceNameAndContainerCompletionFuncTooManyArgs(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
@ -210,6 +336,24 @@ func TestPodResourceNameAndContainerCompletionFuncTooManyArgs(t *testing.T) {
|
|||
checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
|
||||
func TestPodResourceNameAndContainerCompletionFuncJointFormNoArgs(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
||||
compFunc := PodResourceNameAndContainerCompletionFunc(tf)
|
||||
comps, directive := compFunc(cmd, []string{}, "pod/b")
|
||||
checkCompletion(t, comps, []string{"pod/bar"}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
|
||||
func TestPodResourceNameAndContainerCompletionFuncJointFormTooManyArgs(t *testing.T) {
|
||||
tf, cmd := prepareCompletionTest()
|
||||
addPodsToFactory(tf)
|
||||
|
||||
compFunc := PodResourceNameAndContainerCompletionFunc(tf)
|
||||
comps, directive := compFunc(cmd, []string{"pod/pod-name", "container-name"}, "")
|
||||
checkCompletion(t, comps, []string{}, directive, cobra.ShellCompDirectiveNoFileComp)
|
||||
}
|
||||
|
||||
func setMockFactory(config api.Config) {
|
||||
clientConfig := clientcmd.NewDefaultClientConfig(config, nil)
|
||||
testFactory := cmdtesting.NewTestFactory().WithClientConfig(clientConfig)
|
||||
|
|
Loading…
Reference in New Issue