Skip to content
Snippets Groups Projects
Unverified Commit 254cc131 authored by Kazuki Suda's avatar Kazuki Suda
Browse files

Add dynamic completion suppport


This commit adds dynamic completion support for the following commands
and flags:

- `flux delete ...` command
- `flux export ...` command
- `flux get ...` command
- `flux reconcile ...` command
- `flux resume ...` command
- `flux suspend ...` command
- `--namespace` flag
- `--context` flag

Signed-off-by: default avatarKazuki Suda <kazuki.suda@gmail.com>
parent 70509ffc
No related branches found
No related tags found
No related merge requests found
Showing
with 104 additions and 0 deletions
...@@ -17,7 +17,18 @@ limitations under the License. ...@@ -17,7 +17,18 @@ limitations under the License.
package main package main
import ( import (
"context"
"strings"
"github.com/fluxcd/flux2/internal/utils"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
memory "k8s.io/client-go/discovery/cached"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/restmapper"
) )
var completionCmd = &cobra.Command{ var completionCmd = &cobra.Command{
...@@ -29,3 +40,77 @@ var completionCmd = &cobra.Command{ ...@@ -29,3 +40,77 @@ var completionCmd = &cobra.Command{
func init() { func init() {
rootCmd.AddCommand(completionCmd) rootCmd.AddCommand(completionCmd)
} }
func contextsCompletionFunc(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
rawConfig, err := utils.ClientConfig(rootArgs.kubeconfig, rootArgs.kubecontext).RawConfig()
if err != nil {
return completionError(err)
}
var comps []string
for name := range rawConfig.Contexts {
if strings.HasPrefix(name, toComplete) {
comps = append(comps, name)
}
}
return comps, cobra.ShellCompDirectiveNoFileComp
}
func resourceNamesCompletionFunc(gvk schema.GroupVersionKind) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
defer cancel()
cfg, err := utils.KubeConfig(rootArgs.kubeconfig, rootArgs.kubecontext)
if err != nil {
return completionError(err)
}
dc, err := discovery.NewDiscoveryClientForConfig(cfg)
if err != nil {
return completionError(err)
}
mapper := restmapper.NewDeferredDiscoveryRESTMapper(memory.NewMemCacheClient(dc))
mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil {
return completionError(err)
}
client, err := dynamic.NewForConfig(cfg)
if err != nil {
return completionError(err)
}
var dr dynamic.ResourceInterface
if mapping.Scope.Name() == meta.RESTScopeNameNamespace {
dr = client.Resource(mapping.Resource).Namespace(rootArgs.namespace)
} else {
dr = client.Resource(mapping.Resource)
}
list, err := dr.List(ctx, metav1.ListOptions{})
if err != nil {
return completionError(err)
}
var comps []string
for _, item := range list.Items {
name := item.GetName()
if strings.HasPrefix(name, toComplete) {
comps = append(comps, name)
}
}
return comps, cobra.ShellCompDirectiveNoFileComp
}
}
func completionError(err error) ([]string, cobra.ShellCompDirective) {
cobra.CompError(err.Error())
return nil, cobra.ShellCompDirectiveError
}
...@@ -28,6 +28,7 @@ var deleteAlertCmd = &cobra.Command{ ...@@ -28,6 +28,7 @@ var deleteAlertCmd = &cobra.Command{
Long: "The delete alert command removes the given Alert from the cluster.", Long: "The delete alert command removes the given Alert from the cluster.",
Example: ` # Delete an Alert and the Kubernetes resources created by it Example: ` # Delete an Alert and the Kubernetes resources created by it
flux delete alert main`, flux delete alert main`,
ValidArgsFunction: resourceNamesCompletionFunc(notificationv1.GroupVersion.WithKind(notificationv1.AlertKind)),
RunE: deleteCommand{ RunE: deleteCommand{
apiType: alertType, apiType: alertType,
object: universalAdapter{&notificationv1.Alert{}}, object: universalAdapter{&notificationv1.Alert{}},
......
...@@ -28,6 +28,7 @@ var deleteAlertProviderCmd = &cobra.Command{ ...@@ -28,6 +28,7 @@ var deleteAlertProviderCmd = &cobra.Command{
Long: "The delete alert-provider command removes the given Provider from the cluster.", Long: "The delete alert-provider command removes the given Provider from the cluster.",
Example: ` # Delete a Provider and the Kubernetes resources created by it Example: ` # Delete a Provider and the Kubernetes resources created by it
flux delete alert-provider slack`, flux delete alert-provider slack`,
ValidArgsFunction: resourceNamesCompletionFunc(notificationv1.GroupVersion.WithKind(notificationv1.ProviderKind)),
RunE: deleteCommand{ RunE: deleteCommand{
apiType: alertProviderType, apiType: alertProviderType,
object: universalAdapter{&notificationv1.Provider{}}, object: universalAdapter{&notificationv1.Provider{}},
......
...@@ -29,6 +29,7 @@ var deleteHelmReleaseCmd = &cobra.Command{ ...@@ -29,6 +29,7 @@ var deleteHelmReleaseCmd = &cobra.Command{
Long: "The delete helmrelease command removes the given HelmRelease from the cluster.", Long: "The delete helmrelease command removes the given HelmRelease from the cluster.",
Example: ` # Delete a Helm release and the Kubernetes resources created by it Example: ` # Delete a Helm release and the Kubernetes resources created by it
flux delete hr podinfo`, flux delete hr podinfo`,
ValidArgsFunction: resourceNamesCompletionFunc(helmv2.GroupVersion.WithKind(helmv2.HelmReleaseKind)),
RunE: deleteCommand{ RunE: deleteCommand{
apiType: helmReleaseType, apiType: helmReleaseType,
object: universalAdapter{&helmv2.HelmRelease{}}, object: universalAdapter{&helmv2.HelmRelease{}},
......
...@@ -28,6 +28,7 @@ var deleteImagePolicyCmd = &cobra.Command{ ...@@ -28,6 +28,7 @@ var deleteImagePolicyCmd = &cobra.Command{
Long: "The delete image policy command deletes the given ImagePolicy from the cluster.", Long: "The delete image policy command deletes the given ImagePolicy from the cluster.",
Example: ` # Delete an image policy Example: ` # Delete an image policy
flux delete image policy alpine3.x`, flux delete image policy alpine3.x`,
ValidArgsFunction: resourceNamesCompletionFunc(imagev1.GroupVersion.WithKind(imagev1.ImagePolicyKind)),
RunE: deleteCommand{ RunE: deleteCommand{
apiType: imagePolicyType, apiType: imagePolicyType,
object: universalAdapter{&imagev1.ImagePolicy{}}, object: universalAdapter{&imagev1.ImagePolicy{}},
......
...@@ -28,6 +28,7 @@ var deleteImageRepositoryCmd = &cobra.Command{ ...@@ -28,6 +28,7 @@ var deleteImageRepositoryCmd = &cobra.Command{
Long: "The delete image repository command deletes the given ImageRepository from the cluster.", Long: "The delete image repository command deletes the given ImageRepository from the cluster.",
Example: ` # Delete an image repository Example: ` # Delete an image repository
flux delete image repository alpine`, flux delete image repository alpine`,
ValidArgsFunction: resourceNamesCompletionFunc(imagev1.GroupVersion.WithKind(imagev1.ImageRepositoryKind)),
RunE: deleteCommand{ RunE: deleteCommand{
apiType: imageRepositoryType, apiType: imageRepositoryType,
object: universalAdapter{&imagev1.ImageRepository{}}, object: universalAdapter{&imagev1.ImageRepository{}},
......
...@@ -28,6 +28,7 @@ var deleteImageUpdateCmd = &cobra.Command{ ...@@ -28,6 +28,7 @@ var deleteImageUpdateCmd = &cobra.Command{
Long: "The delete image update command deletes the given ImageUpdateAutomation from the cluster.", Long: "The delete image update command deletes the given ImageUpdateAutomation from the cluster.",
Example: ` # Delete an image update automation Example: ` # Delete an image update automation
flux delete image update latest-images`, flux delete image update latest-images`,
ValidArgsFunction: resourceNamesCompletionFunc(autov1.GroupVersion.WithKind(autov1.ImageUpdateAutomationKind)),
RunE: deleteCommand{ RunE: deleteCommand{
apiType: imageUpdateAutomationType, apiType: imageUpdateAutomationType,
object: universalAdapter{&autov1.ImageUpdateAutomation{}}, object: universalAdapter{&autov1.ImageUpdateAutomation{}},
......
...@@ -29,6 +29,7 @@ var deleteKsCmd = &cobra.Command{ ...@@ -29,6 +29,7 @@ var deleteKsCmd = &cobra.Command{
Long: "The delete kustomization command deletes the given Kustomization from the cluster.", Long: "The delete kustomization command deletes the given Kustomization from the cluster.",
Example: ` # Delete a kustomization and the Kubernetes resources created by it Example: ` # Delete a kustomization and the Kubernetes resources created by it
flux delete kustomization podinfo`, flux delete kustomization podinfo`,
ValidArgsFunction: resourceNamesCompletionFunc(kustomizev1.GroupVersion.WithKind(kustomizev1.KustomizationKind)),
RunE: deleteCommand{ RunE: deleteCommand{
apiType: kustomizationType, apiType: kustomizationType,
object: universalAdapter{&kustomizev1.Kustomization{}}, object: universalAdapter{&kustomizev1.Kustomization{}},
......
...@@ -28,6 +28,7 @@ var deleteReceiverCmd = &cobra.Command{ ...@@ -28,6 +28,7 @@ var deleteReceiverCmd = &cobra.Command{
Long: "The delete receiver command removes the given Receiver from the cluster.", Long: "The delete receiver command removes the given Receiver from the cluster.",
Example: ` # Delete an Receiver and the Kubernetes resources created by it Example: ` # Delete an Receiver and the Kubernetes resources created by it
flux delete receiver main`, flux delete receiver main`,
ValidArgsFunction: resourceNamesCompletionFunc(notificationv1.GroupVersion.WithKind(notificationv1.ReceiverKind)),
RunE: deleteCommand{ RunE: deleteCommand{
apiType: receiverType, apiType: receiverType,
object: universalAdapter{&notificationv1.Receiver{}}, object: universalAdapter{&notificationv1.Receiver{}},
......
...@@ -28,6 +28,7 @@ var deleteSourceBucketCmd = &cobra.Command{ ...@@ -28,6 +28,7 @@ var deleteSourceBucketCmd = &cobra.Command{
Long: "The delete source bucket command deletes the given Bucket from the cluster.", Long: "The delete source bucket command deletes the given Bucket from the cluster.",
Example: ` # Delete a Bucket source Example: ` # Delete a Bucket source
flux delete source bucket podinfo`, flux delete source bucket podinfo`,
ValidArgsFunction: resourceNamesCompletionFunc(sourcev1.GroupVersion.WithKind(sourcev1.BucketKind)),
RunE: deleteCommand{ RunE: deleteCommand{
apiType: bucketType, apiType: bucketType,
object: universalAdapter{&sourcev1.Bucket{}}, object: universalAdapter{&sourcev1.Bucket{}},
......
...@@ -28,6 +28,7 @@ var deleteSourceGitCmd = &cobra.Command{ ...@@ -28,6 +28,7 @@ var deleteSourceGitCmd = &cobra.Command{
Long: "The delete source git command deletes the given GitRepository from the cluster.", Long: "The delete source git command deletes the given GitRepository from the cluster.",
Example: ` # Delete a Git repository Example: ` # Delete a Git repository
flux delete source git podinfo`, flux delete source git podinfo`,
ValidArgsFunction: resourceNamesCompletionFunc(sourcev1.GroupVersion.WithKind(sourcev1.GitRepositoryKind)),
RunE: deleteCommand{ RunE: deleteCommand{
apiType: gitRepositoryType, apiType: gitRepositoryType,
object: universalAdapter{&sourcev1.GitRepository{}}, object: universalAdapter{&sourcev1.GitRepository{}},
......
...@@ -28,6 +28,7 @@ var deleteSourceHelmCmd = &cobra.Command{ ...@@ -28,6 +28,7 @@ var deleteSourceHelmCmd = &cobra.Command{
Long: "The delete source helm command deletes the given HelmRepository from the cluster.", Long: "The delete source helm command deletes the given HelmRepository from the cluster.",
Example: ` # Delete a Helm repository Example: ` # Delete a Helm repository
flux delete source helm podinfo`, flux delete source helm podinfo`,
ValidArgsFunction: resourceNamesCompletionFunc(sourcev1.GroupVersion.WithKind(sourcev1.HelmRepositoryKind)),
RunE: deleteCommand{ RunE: deleteCommand{
apiType: helmRepositoryType, apiType: helmRepositoryType,
object: universalAdapter{&sourcev1.HelmRepository{}}, object: universalAdapter{&sourcev1.HelmRepository{}},
......
...@@ -32,6 +32,7 @@ var exportAlertCmd = &cobra.Command{ ...@@ -32,6 +32,7 @@ var exportAlertCmd = &cobra.Command{
# Export a Alert # Export a Alert
flux export alert main > main.yaml`, flux export alert main > main.yaml`,
ValidArgsFunction: resourceNamesCompletionFunc(notificationv1.GroupVersion.WithKind(notificationv1.AlertKind)),
RunE: exportCommand{ RunE: exportCommand{
object: alertAdapter{&notificationv1.Alert{}}, object: alertAdapter{&notificationv1.Alert{}},
list: alertListAdapter{&notificationv1.AlertList{}}, list: alertListAdapter{&notificationv1.AlertList{}},
......
...@@ -32,6 +32,7 @@ var exportAlertProviderCmd = &cobra.Command{ ...@@ -32,6 +32,7 @@ var exportAlertProviderCmd = &cobra.Command{
# Export a Provider # Export a Provider
flux export alert-provider slack > slack.yaml`, flux export alert-provider slack > slack.yaml`,
ValidArgsFunction: resourceNamesCompletionFunc(notificationv1.GroupVersion.WithKind(notificationv1.ProviderKind)),
RunE: exportCommand{ RunE: exportCommand{
object: alertProviderAdapter{&notificationv1.Provider{}}, object: alertProviderAdapter{&notificationv1.Provider{}},
list: alertProviderListAdapter{&notificationv1.ProviderList{}}, list: alertProviderListAdapter{&notificationv1.ProviderList{}},
......
...@@ -33,6 +33,7 @@ var exportHelmReleaseCmd = &cobra.Command{ ...@@ -33,6 +33,7 @@ var exportHelmReleaseCmd = &cobra.Command{
# Export a HelmRelease # Export a HelmRelease
flux export hr my-app > app-release.yaml`, flux export hr my-app > app-release.yaml`,
ValidArgsFunction: resourceNamesCompletionFunc(helmv2.GroupVersion.WithKind(helmv2.HelmReleaseKind)),
RunE: exportCommand{ RunE: exportCommand{
object: helmReleaseAdapter{&helmv2.HelmRelease{}}, object: helmReleaseAdapter{&helmv2.HelmRelease{}},
list: helmReleaseListAdapter{&helmv2.HelmReleaseList{}}, list: helmReleaseListAdapter{&helmv2.HelmReleaseList{}},
......
...@@ -32,6 +32,7 @@ var exportImagePolicyCmd = &cobra.Command{ ...@@ -32,6 +32,7 @@ var exportImagePolicyCmd = &cobra.Command{
# Export a specific policy # Export a specific policy
flux export image policy alpine1x > alpine1x.yaml`, flux export image policy alpine1x > alpine1x.yaml`,
ValidArgsFunction: resourceNamesCompletionFunc(imagev1.GroupVersion.WithKind(imagev1.ImagePolicyKind)),
RunE: exportCommand{ RunE: exportCommand{
object: imagePolicyAdapter{&imagev1.ImagePolicy{}}, object: imagePolicyAdapter{&imagev1.ImagePolicy{}},
list: imagePolicyListAdapter{&imagev1.ImagePolicyList{}}, list: imagePolicyListAdapter{&imagev1.ImagePolicyList{}},
......
...@@ -32,6 +32,7 @@ var exportImageRepositoryCmd = &cobra.Command{ ...@@ -32,6 +32,7 @@ var exportImageRepositoryCmd = &cobra.Command{
# Export a specific ImageRepository resource # Export a specific ImageRepository resource
flux export image repository alpine > alpine.yaml`, flux export image repository alpine > alpine.yaml`,
ValidArgsFunction: resourceNamesCompletionFunc(imagev1.GroupVersion.WithKind(imagev1.ImageRepositoryKind)),
RunE: exportCommand{ RunE: exportCommand{
object: imageRepositoryAdapter{&imagev1.ImageRepository{}}, object: imageRepositoryAdapter{&imagev1.ImageRepository{}},
list: imageRepositoryListAdapter{&imagev1.ImageRepositoryList{}}, list: imageRepositoryListAdapter{&imagev1.ImageRepositoryList{}},
......
...@@ -32,6 +32,7 @@ var exportImageUpdateCmd = &cobra.Command{ ...@@ -32,6 +32,7 @@ var exportImageUpdateCmd = &cobra.Command{
# Export a specific automation # Export a specific automation
flux export image update latest-images > latest.yaml`, flux export image update latest-images > latest.yaml`,
ValidArgsFunction: resourceNamesCompletionFunc(autov1.GroupVersion.WithKind(autov1.ImageUpdateAutomationKind)),
RunE: exportCommand{ RunE: exportCommand{
object: imageUpdateAutomationAdapter{&autov1.ImageUpdateAutomation{}}, object: imageUpdateAutomationAdapter{&autov1.ImageUpdateAutomation{}},
list: imageUpdateAutomationListAdapter{&autov1.ImageUpdateAutomationList{}}, list: imageUpdateAutomationListAdapter{&autov1.ImageUpdateAutomationList{}},
......
...@@ -33,6 +33,7 @@ var exportKsCmd = &cobra.Command{ ...@@ -33,6 +33,7 @@ var exportKsCmd = &cobra.Command{
# Export a Kustomization # Export a Kustomization
flux export kustomization my-app > kustomization.yaml`, flux export kustomization my-app > kustomization.yaml`,
ValidArgsFunction: resourceNamesCompletionFunc(kustomizev1.GroupVersion.WithKind(kustomizev1.KustomizationKind)),
RunE: exportCommand{ RunE: exportCommand{
object: kustomizationAdapter{&kustomizev1.Kustomization{}}, object: kustomizationAdapter{&kustomizev1.Kustomization{}},
list: kustomizationListAdapter{&kustomizev1.KustomizationList{}}, list: kustomizationListAdapter{&kustomizev1.KustomizationList{}},
......
...@@ -32,6 +32,7 @@ var exportReceiverCmd = &cobra.Command{ ...@@ -32,6 +32,7 @@ var exportReceiverCmd = &cobra.Command{
# Export a Receiver # Export a Receiver
flux export receiver main > main.yaml`, flux export receiver main > main.yaml`,
ValidArgsFunction: resourceNamesCompletionFunc(notificationv1.GroupVersion.WithKind(notificationv1.ReceiverKind)),
RunE: exportCommand{ RunE: exportCommand{
list: receiverListAdapter{&notificationv1.ReceiverList{}}, list: receiverListAdapter{&notificationv1.ReceiverList{}},
object: receiverAdapter{&notificationv1.Receiver{}}, object: receiverAdapter{&notificationv1.Receiver{}},
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment