Set validate functions requiring no parameters for all commands

Validate function is used to validate command options and should not get
any additional parameter. To preserve compatibility across all
kubectl commands, this PR removes all parameters in validate functions.
This commit is contained in:
Arda Güçlü 2022-05-17 11:38:20 +03:00
parent c84d0864dd
commit 8fb423bfab
17 changed files with 123 additions and 108 deletions

View File

@ -193,7 +193,7 @@ func NewCmdApply(baseName string, f cmdutil.Factory, ioStreams genericclioptions
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
o, err := flags.ToOptions(cmd, baseName, args) o, err := flags.ToOptions(cmd, baseName, args)
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
cmdutil.CheckErr(o.Validate(cmd, args)) cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run()) cmdutil.CheckErr(o.Run())
}, },
} }
@ -230,6 +230,10 @@ func (flags *ApplyFlags) AddFlags(cmd *cobra.Command) {
// ToOptions converts from CLI inputs to runtime inputs // ToOptions converts from CLI inputs to runtime inputs
func (flags *ApplyFlags) ToOptions(cmd *cobra.Command, baseName string, args []string) (*ApplyOptions, error) { func (flags *ApplyFlags) ToOptions(cmd *cobra.Command, baseName string, args []string) (*ApplyOptions, error) {
if len(args) != 0 {
return nil, cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
}
serverSideApply := cmdutil.GetServerSideApplyFlag(cmd) serverSideApply := cmdutil.GetServerSideApplyFlag(cmd)
forceConflicts := cmdutil.GetForceConflictsFlag(cmd) forceConflicts := cmdutil.GetForceConflictsFlag(cmd)
dryRunStrategy, err := cmdutil.GetDryRunStrategy(cmd) dryRunStrategy, err := cmdutil.GetDryRunStrategy(cmd)
@ -344,11 +348,7 @@ func (flags *ApplyFlags) ToOptions(cmd *cobra.Command, baseName string, args []s
} }
// Validate verifies if ApplyOptions are valid and without conflicts. // Validate verifies if ApplyOptions are valid and without conflicts.
func (o *ApplyOptions) Validate(cmd *cobra.Command, args []string) error { func (o *ApplyOptions) Validate() error {
if len(args) != 0 {
return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
}
if o.ForceConflicts && !o.ServerSideApply { if o.ForceConflicts && !o.ServerSideApply {
return fmt.Errorf("--force-conflicts only works with --server-side") return fmt.Errorf("--force-conflicts only works with --server-side")
} }

View File

@ -81,7 +81,7 @@ func NewCmdApplyViewLastApplied(f cmdutil.Factory, ioStreams genericclioptions.I
ValidArgsFunction: completion.ResourceTypeAndNameCompletionFunc(f), ValidArgsFunction: completion.ResourceTypeAndNameCompletionFunc(f),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(cmd, f, args)) cmdutil.CheckErr(options.Complete(cmd, f, args))
cmdutil.CheckErr(options.Validate(cmd)) cmdutil.CheckErr(options.Validate())
cmdutil.CheckErr(options.RunApplyViewLastApplied(cmd)) cmdutil.CheckErr(options.RunApplyViewLastApplied(cmd))
}, },
} }
@ -141,7 +141,7 @@ func (o *ViewLastAppliedOptions) Complete(cmd *cobra.Command, f cmdutil.Factory,
} }
// Validate checks ViewLastAppliedOptions for validity. // Validate checks ViewLastAppliedOptions for validity.
func (o *ViewLastAppliedOptions) Validate(cmd *cobra.Command) error { func (o *ViewLastAppliedOptions) Validate() error {
return nil return nil
} }

View File

@ -43,6 +43,9 @@ type GetContextsOptions struct {
showHeaders bool showHeaders bool
contextNames []string contextNames []string
outputFormat string
noHeaders bool
genericclioptions.IOStreams genericclioptions.IOStreams
} }
@ -73,22 +76,26 @@ func NewCmdConfigGetContexts(streams genericclioptions.IOStreams, configAccess c
Long: getContextsLong, Long: getContextsLong,
Example: getContextsExample, Example: getContextsExample,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Validate(cmd))
cmdutil.CheckErr(options.Complete(cmd, args)) cmdutil.CheckErr(options.Complete(cmd, args))
cmdutil.CheckErr(options.Validate())
cmdutil.CheckErr(options.RunGetContexts()) cmdutil.CheckErr(options.RunGetContexts())
}, },
} }
cmd.Flags().Bool("no-headers", false, "When using the default or custom-column output format, don't print headers (default print headers).") cmd.Flags().BoolVar(&options.noHeaders, "no-headers", options.noHeaders, "When using the default or custom-column output format, don't print headers (default print headers).")
cmd.Flags().StringP("output", "o", "", `Output format. One of: (name).`) cmd.Flags().StringVarP(&options.outputFormat, "output", "o", options.outputFormat, `Output format. One of: (name).`)
return cmd return cmd
} }
// Complete assigns GetContextsOptions from the args. // Complete assigns GetContextsOptions from the args.
func (o *GetContextsOptions) Complete(cmd *cobra.Command, args []string) error { func (o *GetContextsOptions) Complete(cmd *cobra.Command, args []string) error {
supportedOutputTypes := sets.NewString("", "name")
if !supportedOutputTypes.Has(o.outputFormat) {
return fmt.Errorf("--output %v is not available in kubectl config get-contexts; resetting to default output format", o.outputFormat)
}
o.contextNames = args o.contextNames = args
o.nameOnly = false o.nameOnly = false
if cmdutil.GetFlagString(cmd, "output") == "name" { if o.outputFormat == "name" {
o.nameOnly = true o.nameOnly = true
} }
o.showHeaders = true o.showHeaders = true
@ -100,17 +107,7 @@ func (o *GetContextsOptions) Complete(cmd *cobra.Command, args []string) error {
} }
// Validate ensures the of output format // Validate ensures the of output format
func (o *GetContextsOptions) Validate(cmd *cobra.Command) error { func (o *GetContextsOptions) Validate() error {
validOutputTypes := sets.NewString("", "json", "yaml", "wide", "name", "custom-columns", "custom-columns-file", "go-template", "go-template-file", "jsonpath", "jsonpath-file")
supportedOutputTypes := sets.NewString("", "name")
outputFormat := cmdutil.GetFlagString(cmd, "output")
if !validOutputTypes.Has(outputFormat) {
return fmt.Errorf("output must be one of '' or 'name': %v", outputFormat)
}
if !supportedOutputTypes.Has(outputFormat) {
cmd.Flags().Set("output", "")
return fmt.Errorf("--output %v is not available in kubectl config get-contexts; resetting to default output format", outputFormat)
}
return nil return nil
} }

View File

@ -77,6 +77,8 @@ type CopyOptions struct {
Clientset kubernetes.Interface Clientset kubernetes.Interface
ExecParentCmdName string ExecParentCmdName string
args []string
genericclioptions.IOStreams genericclioptions.IOStreams
} }
@ -149,9 +151,9 @@ func NewCmdCp(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.C
return comps, cobra.ShellCompDirectiveNoSpace return comps, cobra.ShellCompDirectiveNoSpace
}, },
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd)) cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate(cmd, args)) cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run(args)) cmdutil.CheckErr(o.Run())
}, },
} }
cmdutil.AddContainerVarFlags(cmd, &o.Container, o.Container) cmdutil.AddContainerVarFlags(cmd, &o.Container, o.Container)
@ -198,7 +200,7 @@ func extractFileSpec(arg string) (fileSpec, error) {
} }
// Complete completes all the required options // Complete completes all the required options
func (o *CopyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error { func (o *CopyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
if cmd.Parent() != nil { if cmd.Parent() != nil {
o.ExecParentCmdName = cmd.Parent().CommandPath() o.ExecParentCmdName = cmd.Parent().CommandPath()
} }
@ -218,24 +220,26 @@ func (o *CopyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
if err != nil { if err != nil {
return err return err
} }
o.args = args
return nil return nil
} }
// Validate makes sure provided values for CopyOptions are valid // Validate makes sure provided values for CopyOptions are valid
func (o *CopyOptions) Validate(cmd *cobra.Command, args []string) error { func (o *CopyOptions) Validate() error {
if len(args) != 2 { if len(o.args) != 2 {
return fmt.Errorf("source and destination are required") return fmt.Errorf("source and destination are required")
} }
return nil return nil
} }
// Run performs the execution // Run performs the execution
func (o *CopyOptions) Run(args []string) error { func (o *CopyOptions) Run() error {
srcSpec, err := extractFileSpec(args[0]) srcSpec, err := extractFileSpec(o.args[0])
if err != nil { if err != nil {
return err return err
} }
destSpec, err := extractFileSpec(args[1]) destSpec, err := extractFileSpec(o.args[1])
if err != nil { if err != nil {
return err return err
} }

View File

@ -659,9 +659,9 @@ func TestCopyToPod(t *testing.T) {
for name, test := range tests { for name, test := range tests {
opts := NewCopyOptions(ioStreams) opts := NewCopyOptions(ioStreams)
opts.Complete(tf, cmd) opts.Complete(tf, cmd, []string{test.src, fmt.Sprintf("pod-ns/pod-name:%s", test.dest)})
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
err = opts.Run([]string{test.src, fmt.Sprintf("pod-ns/pod-name:%s", test.dest)}) err = opts.Run()
//If error is NotFound error , it indicates that the //If error is NotFound error , it indicates that the
//request has been sent correctly. //request has been sent correctly.
//Treat this as no error. //Treat this as no error.
@ -723,7 +723,7 @@ func TestCopyToPodNoPreserve(t *testing.T) {
PodName: "pod-name", PodName: "pod-name",
File: newRemotePath("foo"), File: newRemotePath("foo"),
} }
opts.Complete(tf, cmd) opts.Complete(tf, cmd, nil)
for name, test := range tests { for name, test := range tests {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
@ -754,14 +754,13 @@ func TestValidate(t *testing.T) {
expectedErr: true, expectedErr: true,
}, },
} }
tf := cmdtesting.NewTestFactory()
ioStreams, _, _, _ := genericclioptions.NewTestIOStreams() ioStreams, _, _, _ := genericclioptions.NewTestIOStreams()
opts := NewCopyOptions(ioStreams) opts := NewCopyOptions(ioStreams)
cmd := NewCmdCp(tf, ioStreams)
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
err := opts.Validate(cmd, test.args) opts.args = test.args
err := opts.Validate()
if (err != nil) != test.expectedErr { if (err != nil) != test.expectedErr {
t.Errorf("expected error: %v, saw: %v, error: %v", test.expectedErr, err != nil, err) t.Errorf("expected error: %v, saw: %v, error: %v", test.expectedErr, err != nil, err)
} }

View File

@ -116,8 +116,8 @@ func NewCmdCreate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cob
defaultRunFunc(cmd, args) defaultRunFunc(cmd, args)
return return
} }
cmdutil.CheckErr(o.Complete(f, cmd)) cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.ValidateArgs(cmd, args)) cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.RunCreate(f, cmd)) cmdutil.CheckErr(o.RunCreate(f, cmd))
}, },
} }
@ -160,32 +160,29 @@ func NewCmdCreate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cob
return cmd return cmd
} }
// ValidateArgs makes sure there is no discrepency in command options // Validate makes sure there is no discrepency in command options
func (o *CreateOptions) ValidateArgs(cmd *cobra.Command, args []string) error { func (o *CreateOptions) Validate() error {
if len(args) != 0 {
return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
}
if len(o.Raw) > 0 { if len(o.Raw) > 0 {
if o.EditBeforeCreate { if o.EditBeforeCreate {
return cmdutil.UsageErrorf(cmd, "--raw and --edit are mutually exclusive") return fmt.Errorf("--raw and --edit are mutually exclusive")
} }
if len(o.FilenameOptions.Filenames) != 1 { if len(o.FilenameOptions.Filenames) != 1 {
return cmdutil.UsageErrorf(cmd, "--raw can only use a single local file or stdin") return fmt.Errorf("--raw can only use a single local file or stdin")
} }
if strings.Index(o.FilenameOptions.Filenames[0], "http://") == 0 || strings.Index(o.FilenameOptions.Filenames[0], "https://") == 0 { if strings.Index(o.FilenameOptions.Filenames[0], "http://") == 0 || strings.Index(o.FilenameOptions.Filenames[0], "https://") == 0 {
return cmdutil.UsageErrorf(cmd, "--raw cannot read from a url") return fmt.Errorf("--raw cannot read from a url")
} }
if o.FilenameOptions.Recursive { if o.FilenameOptions.Recursive {
return cmdutil.UsageErrorf(cmd, "--raw and --recursive are mutually exclusive") return fmt.Errorf("--raw and --recursive are mutually exclusive")
} }
if len(o.Selector) > 0 { if len(o.Selector) > 0 {
return cmdutil.UsageErrorf(cmd, "--raw and --selector (-l) are mutually exclusive") return fmt.Errorf("--raw and --selector (-l) are mutually exclusive")
} }
if len(cmdutil.GetFlagString(cmd, "output")) > 0 { if o.PrintFlags.OutputFormat != nil && len(*o.PrintFlags.OutputFormat) > 0 {
return cmdutil.UsageErrorf(cmd, "--raw and --output are mutually exclusive") return fmt.Errorf("--raw and --output are mutually exclusive")
} }
if _, err := url.ParseRequestURI(o.Raw); err != nil { if _, err := url.ParseRequestURI(o.Raw); err != nil {
return cmdutil.UsageErrorf(cmd, "--raw must be a valid URL path: %v", err) return fmt.Errorf("--raw must be a valid URL path: %v", err)
} }
} }
@ -193,7 +190,10 @@ func (o *CreateOptions) ValidateArgs(cmd *cobra.Command, args []string) error {
} }
// Complete completes all the required options // Complete completes all the required options
func (o *CreateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error { func (o *CreateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
if len(args) != 0 {
return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
}
var err error var err error
o.RecordFlags.Complete(cmd) o.RecordFlags.Complete(cmd)
o.Recorder, err = o.RecordFlags.ToRecorder() o.Recorder, err = o.RecordFlags.ToRecorder()

View File

@ -35,8 +35,9 @@ func TestExtraArgsFail(t *testing.T) {
defer f.Cleanup() defer f.Cleanup()
c := NewCmdCreate(f, genericclioptions.NewTestIOStreamsDiscard()) c := NewCmdCreate(f, genericclioptions.NewTestIOStreamsDiscard())
options := CreateOptions{} ioStreams, _, _, _ := genericclioptions.NewTestIOStreams()
if options.ValidateArgs(c, []string{"rc"}) == nil { options := NewCreateOptions(ioStreams)
if options.Complete(f, c, []string{"rc"}) == nil {
t.Errorf("unexpected non-error") t.Errorf("unexpected non-error")
} }
} }

View File

@ -151,7 +151,7 @@ func NewCmdDebug(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.
Example: debugExample, Example: debugExample,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args)) cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate(cmd)) cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run(f, cmd)) cmdutil.CheckErr(o.Run(f, cmd))
}, },
} }
@ -221,7 +221,7 @@ func (o *DebugOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
} }
// Validate checks that the provided debug options are specified. // Validate checks that the provided debug options are specified.
func (o *DebugOptions) Validate(cmd *cobra.Command) error { func (o *DebugOptions) Validate() error {
// Attach // Attach
if o.Attach && o.attachChanged && len(o.Image) == 0 && len(o.Container) == 0 { if o.Attach && o.attachChanged && len(o.Image) == 0 && len(o.Container) == 0 {
return fmt.Errorf("you must specify --container or create a new container using --image in order to attach.") return fmt.Errorf("you must specify --container or create a new container using --image in order to attach.")

View File

@ -1538,7 +1538,7 @@ func TestCompleteAndValidate(t *testing.T) {
if gotError != nil { if gotError != nil {
return return
} }
gotError = opts.Validate(cmd) gotError = opts.Validate()
}, },
} }
cmd.SetArgs(strings.Split(tc.args, " ")) cmd.SetArgs(strings.Split(tc.args, " "))

View File

@ -110,6 +110,7 @@ func NewCmdDescribe(parent string, f cmdutil.Factory, streams genericclioptions.
ValidArgsFunction: completion.ResourceTypeAndNameCompletionFunc(f), ValidArgsFunction: completion.ResourceTypeAndNameCompletionFunc(f),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args)) cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run()) cmdutil.CheckErr(o.Run())
}, },
} }
@ -148,7 +149,7 @@ func (o *DescribeOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
return nil return nil
} }
func (o *DescribeOptions) Validate(args []string) error { func (o *DescribeOptions) Validate() error {
return nil return nil
} }

View File

@ -118,13 +118,6 @@ type DiffOptions struct {
pruner *pruner pruner *pruner
} }
func validateArgs(cmd *cobra.Command, args []string) error {
if len(args) != 0 {
return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
}
return nil
}
func NewDiffOptions(ioStreams genericclioptions.IOStreams) *DiffOptions { func NewDiffOptions(ioStreams genericclioptions.IOStreams) *DiffOptions {
return &DiffOptions{ return &DiffOptions{
Diff: &DiffProgram{ Diff: &DiffProgram{
@ -143,8 +136,8 @@ func NewCmdDiff(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.C
Long: diffLong, Long: diffLong,
Example: diffExample, Example: diffExample,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckDiffErr(options.Complete(f, cmd)) cmdutil.CheckDiffErr(options.Complete(f, cmd, args))
cmdutil.CheckDiffErr(validateArgs(cmd, args)) cmdutil.CheckDiffErr(options.Validate())
// `kubectl diff` propagates the error code from // `kubectl diff` propagates the error code from
// diff or `KUBECTL_EXTERNAL_DIFF`. Also, we // diff or `KUBECTL_EXTERNAL_DIFF`. Also, we
// don't want to print an error if diff returns // don't want to print an error if diff returns
@ -605,7 +598,11 @@ func isConflict(err error) bool {
return err != nil && errors.IsConflict(err) return err != nil && errors.IsConflict(err)
} }
func (o *DiffOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error { func (o *DiffOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
if len(args) != 0 {
return cmdutil.UsageErrorf(cmd, "Unexpected args: %v", args)
}
var err error var err error
err = o.FilenameOptions.RequireFilenameOrKustomize() err = o.FilenameOptions.RequireFilenameOrKustomize()
@ -759,6 +756,11 @@ func (o *DiffOptions) Run() error {
return differ.Run(o.Diff) return differ.Run(o.Diff)
} }
// Validate makes sure provided values for DiffOptions are valid
func (o *DiffOptions) Validate() error {
return nil
}
func getObjectName(obj runtime.Object) (string, error) { func getObjectName(obj runtime.Object) (string, error) {
gvk := obj.GetObjectKind().GroupVersionKind() gvk := obj.GetObjectKind().GroupVersionKind()
metadata, err := meta.Accessor(obj) metadata, err := meta.Accessor(obj)

View File

@ -58,6 +58,8 @@ type ExplainOptions struct {
APIVersion string APIVersion string
Recursive bool Recursive bool
args []string
Mapper meta.RESTMapper Mapper meta.RESTMapper
Schema openapi.Resources Schema openapi.Resources
} }
@ -80,9 +82,9 @@ func NewCmdExplain(parent string, f cmdutil.Factory, streams genericclioptions.I
Long: explainLong + "\n\n" + cmdutil.SuggestAPIResources(parent), Long: explainLong + "\n\n" + cmdutil.SuggestAPIResources(parent),
Example: explainExamples, Example: explainExamples,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd)) cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate(args)) cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run(args)) cmdutil.CheckErr(o.Run())
}, },
} }
cmd.Flags().BoolVar(&o.Recursive, "recursive", o.Recursive, "Print the fields of fields (Currently only 1 level deep)") cmd.Flags().BoolVar(&o.Recursive, "recursive", o.Recursive, "Print the fields of fields (Currently only 1 level deep)")
@ -90,7 +92,7 @@ func NewCmdExplain(parent string, f cmdutil.Factory, streams genericclioptions.I
return cmd return cmd
} }
func (o *ExplainOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error { func (o *ExplainOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
var err error var err error
o.Mapper, err = f.ToRESTMapper() o.Mapper, err = f.ToRESTMapper()
if err != nil { if err != nil {
@ -101,14 +103,16 @@ func (o *ExplainOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
if err != nil { if err != nil {
return err return err
} }
o.args = args
return nil return nil
} }
func (o *ExplainOptions) Validate(args []string) error { func (o *ExplainOptions) Validate() error {
if len(args) == 0 { if len(o.args) == 0 {
return fmt.Errorf("You must specify the type of resource to explain. %s\n", cmdutil.SuggestAPIResources(o.CmdParent)) return fmt.Errorf("You must specify the type of resource to explain. %s\n", cmdutil.SuggestAPIResources(o.CmdParent))
} }
if len(args) > 1 { if len(o.args) > 1 {
return fmt.Errorf("We accept only this format: explain RESOURCE\n") return fmt.Errorf("We accept only this format: explain RESOURCE\n")
} }
@ -116,7 +120,7 @@ func (o *ExplainOptions) Validate(args []string) error {
} }
// Run executes the appropriate steps to print a model's documentation // Run executes the appropriate steps to print a model's documentation
func (o *ExplainOptions) Run(args []string) error { func (o *ExplainOptions) Run() error {
recursive := o.Recursive recursive := o.Recursive
apiVersionString := o.APIVersion apiVersionString := o.APIVersion
@ -124,7 +128,7 @@ func (o *ExplainOptions) Run(args []string) error {
var fieldsPath []string var fieldsPath []string
var err error var err error
if len(apiVersionString) == 0 { if len(apiVersionString) == 0 {
fullySpecifiedGVR, fieldsPath, err = explain.SplitAndParseResourceRequestWithMatchingPrefix(args[0], o.Mapper) fullySpecifiedGVR, fieldsPath, err = explain.SplitAndParseResourceRequestWithMatchingPrefix(o.args[0], o.Mapper)
if err != nil { if err != nil {
return err return err
} }
@ -132,7 +136,7 @@ func (o *ExplainOptions) Run(args []string) error {
// TODO: After we figured out the new syntax to separate group and resource, allow // TODO: After we figured out the new syntax to separate group and resource, allow
// the users to use it in explain (kubectl explain <group><syntax><resource>). // the users to use it in explain (kubectl explain <group><syntax><resource>).
// Refer to issue #16039 for why we do this. Refer to PR #15808 that used "/" syntax. // Refer to issue #16039 for why we do this. Refer to PR #15808 that used "/" syntax.
fullySpecifiedGVR, fieldsPath, err = explain.SplitAndParseResourceRequest(args[0], o.Mapper) fullySpecifiedGVR, fieldsPath, err = explain.SplitAndParseResourceRequest(o.args[0], o.Mapper)
if err != nil { if err != nil {
return err return err
} }

View File

@ -169,7 +169,7 @@ func NewCmdGet(parent string, f cmdutil.Factory, streams genericclioptions.IOStr
// ValidArgsFunction is set when this function is called so that we have access to the util package // ValidArgsFunction is set when this function is called so that we have access to the util package
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args)) cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate(cmd)) cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run(f, cmd, args)) cmdutil.CheckErr(o.Run(f, cmd, args))
}, },
SuggestFor: []string{"list", "ps"}, SuggestFor: []string{"list", "ps"},
@ -303,26 +303,26 @@ func (o *GetOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri
} }
// Validate checks the set of flags provided by the user. // Validate checks the set of flags provided by the user.
func (o *GetOptions) Validate(cmd *cobra.Command) error { func (o *GetOptions) Validate() error {
if len(o.Raw) > 0 { if len(o.Raw) > 0 {
if o.Watch || o.WatchOnly || len(o.LabelSelector) > 0 { if o.Watch || o.WatchOnly || len(o.LabelSelector) > 0 {
return fmt.Errorf("--raw may not be specified with other flags that filter the server request or alter the output") return fmt.Errorf("--raw may not be specified with other flags that filter the server request or alter the output")
} }
if len(cmdutil.GetFlagString(cmd, "output")) > 0 { if o.PrintFlags.OutputFormat != nil && len(*o.PrintFlags.OutputFormat) > 0 {
return cmdutil.UsageErrorf(cmd, "--raw and --output are mutually exclusive") return fmt.Errorf("--raw and --output are mutually exclusive")
} }
if _, err := url.ParseRequestURI(o.Raw); err != nil { if _, err := url.ParseRequestURI(o.Raw); err != nil {
return cmdutil.UsageErrorf(cmd, "--raw must be a valid URL path: %v", err) return fmt.Errorf("--raw must be a valid URL path: %v", err)
} }
} }
if cmdutil.GetFlagBool(cmd, "show-labels") { if o.PrintFlags.HumanReadableFlags.ShowLabels != nil && *o.PrintFlags.HumanReadableFlags.ShowLabels && o.PrintFlags.OutputFormat != nil {
outputOption := cmd.Flags().Lookup("output").Value.String() outputOption := *o.PrintFlags.OutputFormat
if outputOption != "" && outputOption != "wide" { if outputOption != "" && outputOption != "wide" {
return fmt.Errorf("--show-labels option cannot be used with %s printer", outputOption) return fmt.Errorf("--show-labels option cannot be used with %s printer", outputOption)
} }
} }
if o.OutputWatchEvents && !(o.Watch || o.WatchOnly) { if o.OutputWatchEvents && !(o.Watch || o.WatchOnly) {
return cmdutil.UsageErrorf(cmd, "--output-watch-events option can only be used with --watch or --watch-only") return fmt.Errorf("--output-watch-events option can only be used with --watch or --watch-only")
} }
if len(o.Subresource) > 0 && !slice.ContainsString(supportedSubresources, o.Subresource, nil) { if len(o.Subresource) > 0 && !slice.ContainsString(supportedSubresources, o.Subresource, nil) {
return fmt.Errorf("invalid subresource value: %q. Must be one of %v", o.Subresource, supportedSubresources) return fmt.Errorf("invalid subresource value: %q. Must be one of %v", o.Subresource, supportedSubresources)

View File

@ -123,7 +123,7 @@ func NewCmdReplace(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobr
Example: replaceExample, Example: replaceExample,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args)) cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate(cmd)) cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run(f)) cmdutil.CheckErr(o.Run(f))
}, },
} }
@ -218,7 +218,7 @@ func (o *ReplaceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []
return nil return nil
} }
func (o *ReplaceOptions) Validate(cmd *cobra.Command) error { func (o *ReplaceOptions) Validate() error {
if o.DeleteOptions.GracePeriod >= 0 && !o.DeleteOptions.ForceDeletion { if o.DeleteOptions.GracePeriod >= 0 && !o.DeleteOptions.ForceDeletion {
return fmt.Errorf("--grace-period must have --force specified") return fmt.Errorf("--grace-period must have --force specified")
} }
@ -228,24 +228,24 @@ func (o *ReplaceOptions) Validate(cmd *cobra.Command) error {
} }
if cmdutil.IsFilenameSliceEmpty(o.DeleteOptions.FilenameOptions.Filenames, o.DeleteOptions.FilenameOptions.Kustomize) { if cmdutil.IsFilenameSliceEmpty(o.DeleteOptions.FilenameOptions.Filenames, o.DeleteOptions.FilenameOptions.Kustomize) {
return cmdutil.UsageErrorf(cmd, "Must specify --filename to replace") return fmt.Errorf("Must specify --filename to replace")
} }
if len(o.Raw) > 0 { if len(o.Raw) > 0 {
if len(o.DeleteOptions.FilenameOptions.Filenames) != 1 { if len(o.DeleteOptions.FilenameOptions.Filenames) != 1 {
return cmdutil.UsageErrorf(cmd, "--raw can only use a single local file or stdin") return fmt.Errorf("--raw can only use a single local file or stdin")
} }
if strings.Index(o.DeleteOptions.FilenameOptions.Filenames[0], "http://") == 0 || strings.Index(o.DeleteOptions.FilenameOptions.Filenames[0], "https://") == 0 { if strings.Index(o.DeleteOptions.FilenameOptions.Filenames[0], "http://") == 0 || strings.Index(o.DeleteOptions.FilenameOptions.Filenames[0], "https://") == 0 {
return cmdutil.UsageErrorf(cmd, "--raw cannot read from a url") return fmt.Errorf("--raw cannot read from a url")
} }
if o.DeleteOptions.FilenameOptions.Recursive { if o.DeleteOptions.FilenameOptions.Recursive {
return cmdutil.UsageErrorf(cmd, "--raw and --recursive are mutually exclusive") return fmt.Errorf("--raw and --recursive are mutually exclusive")
} }
if len(cmdutil.GetFlagString(cmd, "output")) > 0 { if o.PrintFlags.OutputFormat != nil && len(*o.PrintFlags.OutputFormat) > 0 {
return cmdutil.UsageErrorf(cmd, "--raw and --output are mutually exclusive") return fmt.Errorf("--raw and --output are mutually exclusive")
} }
if _, err := url.ParseRequestURI(o.Raw); err != nil { if _, err := url.ParseRequestURI(o.Raw); err != nil {
return cmdutil.UsageErrorf(cmd, "--raw must be a valid URL path: %v", err) return fmt.Errorf("--raw must be a valid URL path: %v", err)
} }
} }

View File

@ -117,7 +117,7 @@ func NewCmdScale(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobr
ValidArgsFunction: completion.SpecifiedResourceTypeAndNameCompletionFunc(f, validArgs), ValidArgsFunction: completion.SpecifiedResourceTypeAndNameCompletionFunc(f, validArgs),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args)) cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate(cmd)) cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.RunScale()) cmdutil.CheckErr(o.RunScale())
}, },
} }
@ -181,7 +181,7 @@ func (o *ScaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
return nil return nil
} }
func (o *ScaleOptions) Validate(cmd *cobra.Command) error { func (o *ScaleOptions) Validate() error {
if o.Replicas < 0 { if o.Replicas < 0 {
return fmt.Errorf("The --replicas=COUNT flag is required, and COUNT must be greater than or equal to 0") return fmt.Errorf("The --replicas=COUNT flag is required, and COUNT must be greater than or equal to 0")
} }

View File

@ -57,6 +57,8 @@ type Options struct {
Short bool Short bool
Output string Output string
args []string
discoveryClient discovery.CachedDiscoveryInterface discoveryClient discovery.CachedDiscoveryInterface
genericclioptions.IOStreams genericclioptions.IOStreams
@ -79,8 +81,8 @@ func NewCmdVersion(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *co
Long: i18n.T("Print the client and server version information for the current context."), Long: i18n.T("Print the client and server version information for the current context."),
Example: versionExample, Example: versionExample,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd)) cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate(args)) cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run()) cmdutil.CheckErr(o.Run())
}, },
} }
@ -92,7 +94,7 @@ func NewCmdVersion(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *co
} }
// Complete completes all the required options // Complete completes all the required options
func (o *Options) Complete(f cmdutil.Factory, cmd *cobra.Command) error { func (o *Options) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
var err error var err error
if o.ClientOnly { if o.ClientOnly {
return nil return nil
@ -103,13 +105,15 @@ func (o *Options) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
if err != nil && !clientcmd.IsEmptyConfig(err) { if err != nil && !clientcmd.IsEmptyConfig(err) {
return err return err
} }
o.args = args
return nil return nil
} }
// Validate validates the provided options // Validate validates the provided options
func (o *Options) Validate(args []string) error { func (o *Options) Validate() error {
if len(args) != 0 { if len(o.args) != 0 {
return errors.New(fmt.Sprintf("extra arguments: %v", args)) return errors.New(fmt.Sprintf("extra arguments: %v", o.args))
} }
if o.Output != "" && o.Output != "yaml" && o.Output != "json" { if o.Output != "" && o.Output != "yaml" && o.Output != "json" {

View File

@ -31,13 +31,16 @@ func TestNewCmdVersionClientVersion(t *testing.T) {
defer tf.Cleanup() defer tf.Cleanup()
streams, _, buf, _ := genericclioptions.NewTestIOStreams() streams, _, buf, _ := genericclioptions.NewTestIOStreams()
o := NewOptions(streams) o := NewOptions(streams)
if err := o.Complete(tf, &cobra.Command{}); err != nil { if err := o.Complete(tf, &cobra.Command{}, nil); err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
if err := o.Validate(nil); err != nil { if err := o.Validate(); err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
if err := o.Validate([]string{"extraParameter0"}); !strings.Contains(err.Error(), "extra arguments") { if err := o.Complete(tf, &cobra.Command{}, []string{"extraParameter0"}); err != nil {
t.Errorf("Unexpected error: %v", err)
}
if err := o.Validate(); !strings.Contains(err.Error(), "extra arguments") {
t.Errorf("Unexpected error: should fail to validate the args length greater than 0") t.Errorf("Unexpected error: should fail to validate the args length greater than 0")
} }
if err := o.Run(); err != nil { if err := o.Run(); err != nil {