From da3504105ec0212f6df33bfa542f38e593574a27 Mon Sep 17 00:00:00 2001 From: Takuro Wada Date: Sat, 22 Jun 2019 02:02:51 +0900 Subject: [PATCH 1/4] Add remove label command --- k8sdeps/validator/validators.go | 15 ++ pkg/commands/edit/all.go | 2 +- pkg/commands/edit/remove/all.go | 9 +- pkg/commands/edit/remove/removemetadata.go | 151 +++++++++++++ .../edit/remove/removemetadata_test.go | 203 ++++++++++++++++++ pkg/ifc/ifc.go | 1 + pkg/validators/validators.go | 13 ++ 7 files changed, 392 insertions(+), 2 deletions(-) create mode 100644 pkg/commands/edit/remove/removemetadata.go create mode 100644 pkg/commands/edit/remove/removemetadata_test.go diff --git a/k8sdeps/validator/validators.go b/k8sdeps/validator/validators.go index ffbed5b46..6c4645202 100644 --- a/k8sdeps/validator/validators.go +++ b/k8sdeps/validator/validators.go @@ -64,6 +64,21 @@ func (v *KustValidator) MakeLabelValidator() func(map[string]string) error { } } +// MakeLabelNameValidator returns a ArrayValidatorFunc using apimachinery. +func (v *KustValidator) MakeLabelNameValidator() func([]string) error { + return func(x []string) error { + errs := field.ErrorList{} + fldPath := field.NewPath("field") + for _, k := range x { + errs = append(errs, v1validation.ValidateLabelName(k, fldPath)...) + } + if len(errs) > 0 { + return errors.New(errs.ToAggregate().Error()) + } + return nil + } +} + // ValidateNamespace validates a string is a valid namespace using apimachinery. func (v *KustValidator) ValidateNamespace(s string) []string { return validation.IsDNS1123Label(s) diff --git a/pkg/commands/edit/all.go b/pkg/commands/edit/all.go index 162ae08d1..ecba55f73 100644 --- a/pkg/commands/edit/all.go +++ b/pkg/commands/edit/all.go @@ -38,7 +38,7 @@ func NewCmdEdit( add.NewCmdAdd(fSys, loader.NewFileLoaderAtCwd(v, fSys), kf), set.NewCmdSet(fSys, v), fix.NewCmdFix(fSys), - remove.NewCmdRemove(fSys), + remove.NewCmdRemove(fSys, loader.NewFileLoaderAtCwd(v, fSys)), ) return c } diff --git a/pkg/commands/edit/remove/all.go b/pkg/commands/edit/remove/all.go index aa75f7272..efa27307f 100644 --- a/pkg/commands/edit/remove/all.go +++ b/pkg/commands/edit/remove/all.go @@ -19,10 +19,13 @@ package remove import ( "github.com/spf13/cobra" "sigs.k8s.io/kustomize/pkg/fs" + "sigs.k8s.io/kustomize/pkg/ifc" ) // NewCmdRemove returns an instance of 'remove' subcommand. -func NewCmdRemove(fsys fs.FileSystem) *cobra.Command { +func NewCmdRemove( + fsys fs.FileSystem, + ldr ifc.Loader) *cobra.Command { c := &cobra.Command{ Use: "remove", Short: "Removes items from the kustomization file.", @@ -31,11 +34,15 @@ func NewCmdRemove(fsys fs.FileSystem) *cobra.Command { # Removes resources from the kustomization file kustomize edit remove resource {filepath} {filepath} kustomize edit remove resource {pattern} + + # Removes one or more commonLabels from the kustomization file + kustomize edit remove label {labelKey1},{labelKey2} `, Args: cobra.MinimumNArgs(1), } c.AddCommand( newCmdRemoveResource(fsys), + newCmdRemoveLabel(fsys, ldr.Validator().MakeLabelNameValidator()), ) return c } diff --git a/pkg/commands/edit/remove/removemetadata.go b/pkg/commands/edit/remove/removemetadata.go new file mode 100644 index 000000000..dbf71b5b5 --- /dev/null +++ b/pkg/commands/edit/remove/removemetadata.go @@ -0,0 +1,151 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package remove + +import ( + "fmt" + "github.com/spf13/cobra" + "sigs.k8s.io/kustomize/pkg/commands/kustfile" + "sigs.k8s.io/kustomize/pkg/fs" + "sigs.k8s.io/kustomize/pkg/pgmconfig" + "sigs.k8s.io/kustomize/pkg/types" + "strings" +) + +// kindOfAdd is the kind of metadata being added: label or annotation +type kindOfAdd int + +const ( + annotation kindOfAdd = iota + label +) + +func (k kindOfAdd) String() string { + kinds := [...]string{ + "annotation", + "label", + } + if k < 0 || k > 1 { + return "Unknown metadatakind" + } + return kinds[k] +} + +type removeMetadataOptions struct { + ignore bool + metadata []string + arrayValidator func([]string) error + kind kindOfAdd +} + +// newCmdRemoveLabel removes one or more commonLabels from the kustomization file. +func newCmdRemoveLabel(fSys fs.FileSystem, v func([]string) error) *cobra.Command { + var o removeMetadataOptions + o.kind = label + o.arrayValidator = v + cmd := &cobra.Command{ + Use: "label", + Short: "Removes one or more commonLabels from " + pgmconfig.KustomizationFileNames[0], + Example: ` + remove label {labelKey1},{labelKey2}`, + RunE: func(cmd *cobra.Command, args []string) error { + return o.runE(args, fSys, o.removeLabels) + }, + } + cmd.Flags().BoolVarP(&o.ignore, "ignore-non-existence", "i", false, + "ignore error if the given label doesn't exist", + ) + return cmd +} + +func (o *removeMetadataOptions) runE( + args []string, fSys fs.FileSystem, remover func(*types.Kustomization) error) error { + err := o.validateAndParse(args) + if err != nil { + return err + } + kf, err := kustfile.NewKustomizationFile(fSys) + if err != nil { + return err + } + m, err := kf.Read() + if err != nil { + return err + } + err = remover(m) + if err != nil { + return err + } + return kf.Write(m) +} + +// validateAndParse validates `remove` commands and parses them into o.metadata +func (o *removeMetadataOptions) validateAndParse(args []string) error { + if len(args) < 1 { + return fmt.Errorf("must specify %s", o.kind) + } + if len(args) > 1 { + return fmt.Errorf("%ss must be comma-separated, with no spaces", o.kind) + } + m, err := o.convertToArray(args[0]) + if err != nil { + return err + } + if err = o.arrayValidator(m); err != nil { + return err + } + o.metadata = m + return nil +} + +func (o *removeMetadataOptions) convertToArray(arg string) ([]string, error) { + inputs := strings.Split(arg, ",") + result := make([]string, 0, len(inputs)) + + for _, input := range inputs { + result = append(result, input) + } + return result, nil +} + +func (o *removeMetadataOptions) removeAnnotations(m *types.Kustomization) error { + if m.CommonAnnotations == nil && !o.ignore { + return fmt.Errorf("commonAnnotations is not defined in kustomization file") + } + return o.removeFromMap(m.CommonAnnotations, annotation) +} + +func (o *removeMetadataOptions) removeLabels(m *types.Kustomization) error { + if m.CommonLabels == nil && !o.ignore { + return fmt.Errorf("commonLabels is not defined in kustomization file") + } + return o.removeFromMap(m.CommonLabels, label) +} + +func (o *removeMetadataOptions) removeFromMap(m map[string]string, kind kindOfAdd) error { + for _, k := range o.metadata { + if _, ok := m[k]; !ok && !o.ignore { + return fmt.Errorf("%s %s is not defined in kustomization file", kind, k) + } + delete(m, k) + } + return nil +} + +func (o *removeMetadataOptions) makeError(input string, message string) error { + return fmt.Errorf("invalid %s: '%s' (%s)", o.kind, input, message) +} diff --git a/pkg/commands/edit/remove/removemetadata_test.go b/pkg/commands/edit/remove/removemetadata_test.go new file mode 100644 index 000000000..bffd01506 --- /dev/null +++ b/pkg/commands/edit/remove/removemetadata_test.go @@ -0,0 +1,203 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package remove + +import ( + "fmt" + "sigs.k8s.io/kustomize/pkg/commands/kustfile" + "sigs.k8s.io/kustomize/pkg/fs" + "sigs.k8s.io/kustomize/pkg/types" + "sigs.k8s.io/kustomize/pkg/validators" + "strings" + "testing" +) + +func makeKustomizationFS() fs.FileSystem { + fakeFS := fs.MakeFakeFS() + commonLabels := []string{"label1: val1", "label2: val2"} + commonAnnotations := []string{"annotation1: val1", "annotation2: val2"} + + fakeFS.WriteTestKustomizationWith([]byte( + fmt.Sprintf("commonLabels:\n %s\ncommonAnnotations:\n %s", + strings.Join(commonLabels, "\n "), strings.Join(commonAnnotations, "\n ")))) + return fakeFS +} + +func readKustomizationFS(t *testing.T, fakeFS fs.FileSystem) *types.Kustomization { + kf, err := kustfile.NewKustomizationFile(fakeFS) + if err != nil { + t.Errorf("unexpected new error %v", err) + } + m, err := kf.Read() + if err != nil { + t.Errorf("unexpected read error %v", err) + } + return m +} + +func makeKustomization(t *testing.T) *types.Kustomization { + fakeFS := makeKustomizationFS() + return readKustomizationFS(t, fakeFS) +} + +func TestRemoveLabel(t *testing.T) { + var o removeMetadataOptions + o.metadata = []string{"label1"} + + m := makeKustomization(t) + err := o.removeLabels(m) + if err != nil { + t.Errorf("unexpected error: could not write to kustomization file") + } + + // adding the same test input should not work + err = o.removeLabels(m) + if err == nil { + t.Errorf("expected not exist in kustomization file error") + } + + _, exists := m.CommonLabels["label1"] + if exists { + t.Errorf("label1 must be deleted") + } + + _, exists = m.CommonLabels["label2"] + if !exists { + t.Errorf("label2 must exist") + } +} + +func TestRemoveLabelIgnore(t *testing.T) { + fakeFS := makeKustomizationFS() + + v := validators.MakeHappyMapValidator(t) + cmd := newCmdRemoveLabel(fakeFS, v.ValidatorArray) + cmd.Flag("ignore-non-existence").Value.Set("true") + args := []string{"label3"} + err := cmd.RunE(cmd, args) + v.VerifyCall() + + if err != nil { + t.Errorf("unexpected error %v", err) + } +} + +func TestRemoveLabelNoDefinition(t *testing.T) { + fakeFS := fs.MakeFakeFS() + fakeFS.WriteTestKustomizationWith([]byte("")) + + v := validators.MakeHappyMapValidator(t) + cmd := newCmdRemoveLabel(fakeFS, v.ValidatorArray) + args := []string{"label1,label2"} + err := cmd.RunE(cmd, args) + v.VerifyCall() + + if err == nil { + t.Errorf("expected an error") + } + if err.Error() != "commonLabels is not defined in kustomization file" { + t.Errorf("incorrect error: %v", err.Error()) + } +} + +func TestRemoveLabelNoDefinitionIgnore(t *testing.T) { + fakeFS := fs.MakeFakeFS() + fakeFS.WriteTestKustomizationWith([]byte("")) + + v := validators.MakeHappyMapValidator(t) + cmd := newCmdRemoveLabel(fakeFS, v.ValidatorArray) + cmd.Flag("ignore-non-existence").Value.Set("true") + args := []string{"label1,label2"} + err := cmd.RunE(cmd, args) + v.VerifyCall() + + if err != nil { + t.Errorf("unexpected error %v", err) + } +} + +func TestRemoveLabelNoArgs(t *testing.T) { + fakeFS := makeKustomizationFS() + + v := validators.MakeHappyMapValidator(t) + cmd := newCmdRemoveLabel(fakeFS, v.ValidatorArray) + err := cmd.Execute() + v.VerifyNoCall() + + if err == nil { + t.Errorf("expected an error") + } + if err.Error() != "must specify label" { + t.Errorf("incorrect error: %v", err.Error()) + } +} + +func TestRemoveLabelInvalidFormat(t *testing.T) { + fakeFS := makeKustomizationFS() + + v := validators.MakeSadMapValidator(t) + cmd := newCmdRemoveLabel(fakeFS, v.ValidatorArray) + args := []string{"exclamation!"} + err := cmd.RunE(cmd, args) + v.VerifyCall() + + if err == nil { + t.Errorf("expected an error") + } + if err.Error() != validators.SAD { + t.Errorf("incorrect error: %v", err.Error()) + } +} + +func TestRemoveLabelMultipleArgs(t *testing.T) { + fakeFS := makeKustomizationFS() + + v := validators.MakeHappyMapValidator(t) + cmd := newCmdRemoveLabel(fakeFS, v.ValidatorArray) + args := []string{"label1,label2"} + err := cmd.RunE(cmd, args) + v.VerifyCall() + + if err != nil { + t.Errorf("unexpected error %v", err) + } + + m := readKustomizationFS(t, fakeFS) + splitArgs := strings.Split(args[0], ",") + for _, k := range splitArgs { + if _, exist := m.CommonLabels[k]; exist { + t.Errorf("%s must be deleted", k) + } + } +} + +func TestRemoveLabelMultipleArgsInvalidFormat(t *testing.T) { + fakeFS := makeKustomizationFS() + + v := validators.MakeSadMapValidator(t) + cmd := newCmdRemoveLabel(fakeFS, v.ValidatorArray) + args := []string{"label1", "label2"} + err := cmd.RunE(cmd, args) + v.VerifyNoCall() + + if err == nil { + t.Errorf("expected an error") + } + if err.Error() != "labels must be comma-separated, with no spaces" { + t.Errorf("incorrect error: %v", err.Error()) + } +} diff --git a/pkg/ifc/ifc.go b/pkg/ifc/ifc.go index ac61f03f4..9b17fefbc 100644 --- a/pkg/ifc/ifc.go +++ b/pkg/ifc/ifc.go @@ -13,6 +13,7 @@ import ( type Validator interface { MakeAnnotationValidator() func(map[string]string) error MakeLabelValidator() func(map[string]string) error + MakeLabelNameValidator() func([]string) error ValidateNamespace(string) []string ErrIfInvalidKey(string) error IsEnvVarName(k string) error diff --git a/pkg/validators/validators.go b/pkg/validators/validators.go index 719f47611..faba97793 100644 --- a/pkg/validators/validators.go +++ b/pkg/validators/validators.go @@ -55,6 +55,11 @@ func (v *FakeValidator) MakeLabelValidator() func(map[string]string) error { return nil } +// MakeLabelNameValidator returns a nil function +func (v *FakeValidator) MakeLabelNameValidator() func([]string) error { + return nil +} + // ValidateNamespace validates namespace by regexp func (v *FakeValidator) ValidateNamespace(s string) []string { pattern := regexp.MustCompile(`^[a-zA-Z].*`) @@ -75,6 +80,14 @@ func (v *FakeValidator) Validator(_ map[string]string) error { return errors.New(SAD) } +func (v *FakeValidator) ValidatorArray(_ []string) error { + v.called = true + if v.happy { + return nil + } + return errors.New(SAD) +} + // VerifyCall returns true if Validator was used. func (v *FakeValidator) VerifyCall() { if !v.called { From 158f754f18ef983faa7e9589ebd0f7c6597bbce3 Mon Sep 17 00:00:00 2001 From: Takuro Wada Date: Sun, 23 Jun 2019 18:41:24 +0900 Subject: [PATCH 2/4] Add remove annotation command --- k8sdeps/validator/validators.go | 17 ++ pkg/commands/edit/remove/all.go | 4 + pkg/commands/edit/remove/removemetadata.go | 20 +++ .../edit/remove/removemetadata_test.go | 148 ++++++++++++++++++ pkg/ifc/ifc.go | 1 + 5 files changed, 190 insertions(+) diff --git a/k8sdeps/validator/validators.go b/k8sdeps/validator/validators.go index 6c4645202..7ac71ecea 100644 --- a/k8sdeps/validator/validators.go +++ b/k8sdeps/validator/validators.go @@ -53,6 +53,23 @@ func (v *KustValidator) MakeAnnotationValidator() func(map[string]string) error } } +// MakeAnnotationNameValidator returns a MapValidatorFunc using apimachinery. +func (v *KustValidator) MakeAnnotationNameValidator() func([]string) error { + return func(x []string) error { + errs := field.ErrorList{} + fldPath := field.NewPath("field") + for _, k := range x { + for _, msg := range validation.IsQualifiedName(strings.ToLower(k)) { + errs = append(errs, field.Invalid(fldPath, k, msg)) + } + } + if len(errs) > 0 { + return errors.New(errs.ToAggregate().Error()) + } + return nil + } +} + // MakeLabelValidator returns a MapValidatorFunc using apimachinery. func (v *KustValidator) MakeLabelValidator() func(map[string]string) error { return func(x map[string]string) error { diff --git a/pkg/commands/edit/remove/all.go b/pkg/commands/edit/remove/all.go index efa27307f..7a425d081 100644 --- a/pkg/commands/edit/remove/all.go +++ b/pkg/commands/edit/remove/all.go @@ -37,12 +37,16 @@ func NewCmdRemove( # Removes one or more commonLabels from the kustomization file kustomize edit remove label {labelKey1},{labelKey2} + + # Removes one or more commonAnnotations from the kustomization file + kustomize edit remove annotation {annotationKey1},{annotationKey2} `, Args: cobra.MinimumNArgs(1), } c.AddCommand( newCmdRemoveResource(fsys), newCmdRemoveLabel(fsys, ldr.Validator().MakeLabelNameValidator()), + newCmdRemoveAnnotation(fsys, ldr.Validator().MakeAnnotationNameValidator()), ) return c } diff --git a/pkg/commands/edit/remove/removemetadata.go b/pkg/commands/edit/remove/removemetadata.go index dbf71b5b5..df2c73dca 100644 --- a/pkg/commands/edit/remove/removemetadata.go +++ b/pkg/commands/edit/remove/removemetadata.go @@ -52,6 +52,26 @@ type removeMetadataOptions struct { kind kindOfAdd } +// newCmdRemoveLabel removes one or more commonAnnotations from the kustomization file. +func newCmdRemoveAnnotation(fSys fs.FileSystem, v func([]string) error) *cobra.Command { + var o removeMetadataOptions + o.kind = label + o.arrayValidator = v + cmd := &cobra.Command{ + Use: "annotation", + Short: "Removes one or more commonAnnotations from " + pgmconfig.KustomizationFileNames[0], + Example: ` + remove annotation {annotationKey1},{annotationKey2}`, + RunE: func(cmd *cobra.Command, args []string) error { + return o.runE(args, fSys, o.removeAnnotations) + }, + } + cmd.Flags().BoolVarP(&o.ignore, "ignore-non-existence", "i", false, + "ignore error if the given label doesn't exist", + ) + return cmd +} + // newCmdRemoveLabel removes one or more commonLabels from the kustomization file. func newCmdRemoveLabel(fSys fs.FileSystem, v func([]string) error) *cobra.Command { var o removeMetadataOptions diff --git a/pkg/commands/edit/remove/removemetadata_test.go b/pkg/commands/edit/remove/removemetadata_test.go index bffd01506..f431ae49b 100644 --- a/pkg/commands/edit/remove/removemetadata_test.go +++ b/pkg/commands/edit/remove/removemetadata_test.go @@ -54,6 +54,154 @@ func makeKustomization(t *testing.T) *types.Kustomization { return readKustomizationFS(t, fakeFS) } +func TestRemoveAnnotation(t *testing.T) { + var o removeMetadataOptions + o.metadata = []string{"annotation1"} + + m := makeKustomization(t) + err := o.removeAnnotations(m) + if err != nil { + t.Errorf("unexpected error: could not write to kustomization file") + } + + // adding the same test input should not work + err = o.removeAnnotations(m) + if err == nil { + t.Errorf("expected not exist in kustomization file error") + } + + _, exists := m.CommonAnnotations["annotation1"] + if exists { + t.Errorf("annotation1 must be deleted") + } + + _, exists = m.CommonAnnotations["annotation2"] + if !exists { + t.Errorf("annotation2 must exist") + } +} + +func TestRemoveAnnotationIgnore(t *testing.T) { + fakeFS := makeKustomizationFS() + + v := validators.MakeHappyMapValidator(t) + cmd := newCmdRemoveAnnotation(fakeFS, v.ValidatorArray) + cmd.Flag("ignore-non-existence").Value.Set("true") + args := []string{"annotation3"} + err := cmd.RunE(cmd, args) + v.VerifyCall() + + if err != nil { + t.Errorf("unexpected error %v", err) + } +} + +func TestRemoveAnnotationNoDefinition(t *testing.T) { + fakeFS := fs.MakeFakeFS() + fakeFS.WriteTestKustomizationWith([]byte("")) + + v := validators.MakeHappyMapValidator(t) + cmd := newCmdRemoveAnnotation(fakeFS, v.ValidatorArray) + args := []string{"annotation1,annotation2"} + err := cmd.RunE(cmd, args) + v.VerifyCall() + + if err == nil { + t.Errorf("expected an error") + } + if err.Error() != "commonAnnotations is not defined in kustomization file" { + t.Errorf("incorrect error: %v", err.Error()) + } +} + +func TestRemoveAnnotationNoDefinitionIgnore(t *testing.T) { + fakeFS := fs.MakeFakeFS() + fakeFS.WriteTestKustomizationWith([]byte("")) + + v := validators.MakeHappyMapValidator(t) + cmd := newCmdRemoveLabel(fakeFS, v.ValidatorArray) + cmd.Flag("ignore-non-existence").Value.Set("true") + args := []string{"annotation1,annotation2"} + err := cmd.RunE(cmd, args) + v.VerifyCall() + + if err != nil { + t.Errorf("unexpected error %v", err) + } +} + +func TestRemoveAnnotationNoArgs(t *testing.T) { + fakeFS := makeKustomizationFS() + + v := validators.MakeHappyMapValidator(t) + cmd := newCmdRemoveAnnotation(fakeFS, v.ValidatorArray) + err := cmd.Execute() + v.VerifyNoCall() + + if err == nil { + t.Errorf("expected an error") + } + if err.Error() != "must specify label" { + t.Errorf("incorrect error: %v", err.Error()) + } +} + +func TestRemoveAnnotationInvalidFormat(t *testing.T) { + fakeFS := makeKustomizationFS() + + v := validators.MakeSadMapValidator(t) + cmd := newCmdRemoveAnnotation(fakeFS, v.ValidatorArray) + args := []string{"nospecialchars%^=@"} + err := cmd.RunE(cmd, args) + v.VerifyCall() + + if err == nil { + t.Errorf("expected an error") + } + if err.Error() != validators.SAD { + t.Errorf("incorrect error: %v", err.Error()) + } +} + +func TestRemoveAnnotationMultipleArgs(t *testing.T) { + fakeFS := makeKustomizationFS() + + v := validators.MakeHappyMapValidator(t) + cmd := newCmdRemoveAnnotation(fakeFS, v.ValidatorArray) + args := []string{"annotation1,annotation2"} + err := cmd.RunE(cmd, args) + v.VerifyCall() + + if err != nil { + t.Errorf("unexpected error %v", err) + } + + m := readKustomizationFS(t, fakeFS) + splitArgs := strings.Split(args[0], ",") + for _, k := range splitArgs { + if _, exist := m.CommonAnnotations[k]; exist { + t.Errorf("%s must be deleted", k) + } + } +} + +func TestRemoveAnnotationMultipleArgsInvalidFormat(t *testing.T) { + fakeFS := makeKustomizationFS() + + v := validators.MakeSadMapValidator(t) + cmd := newCmdRemoveAnnotation(fakeFS, v.ValidatorArray) + args := []string{"annotation1", "annotation2"} + err := cmd.RunE(cmd, args) + v.VerifyNoCall() + + if err == nil { + t.Errorf("expected an error") + } + if err.Error() != "labels must be comma-separated, with no spaces" { + t.Errorf("incorrect error: %v", err.Error()) + } +} + func TestRemoveLabel(t *testing.T) { var o removeMetadataOptions o.metadata = []string{"label1"} diff --git a/pkg/ifc/ifc.go b/pkg/ifc/ifc.go index 9b17fefbc..550d488e9 100644 --- a/pkg/ifc/ifc.go +++ b/pkg/ifc/ifc.go @@ -12,6 +12,7 @@ import ( // Validator provides functions to validate annotations and labels type Validator interface { MakeAnnotationValidator() func(map[string]string) error + MakeAnnotationNameValidator() func([]string) error MakeLabelValidator() func(map[string]string) error MakeLabelNameValidator() func([]string) error ValidateNamespace(string) []string From 297812ec11c35c9c61378cc73f455ab75015e6ed Mon Sep 17 00:00:00 2001 From: Takuro Wada Date: Sun, 23 Jun 2019 19:43:49 +0900 Subject: [PATCH 3/4] Fix lint --- pkg/commands/edit/remove/removemetadata.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/commands/edit/remove/removemetadata.go b/pkg/commands/edit/remove/removemetadata.go index df2c73dca..6229951ca 100644 --- a/pkg/commands/edit/remove/removemetadata.go +++ b/pkg/commands/edit/remove/removemetadata.go @@ -137,6 +137,9 @@ func (o *removeMetadataOptions) convertToArray(arg string) ([]string, error) { result := make([]string, 0, len(inputs)) for _, input := range inputs { + if len(input) == 0 { + return nil, o.makeError(input, "name is empty") + } result = append(result, input) } return result, nil From ab2643ef14f7c67a4c045157f454408055d69628 Mon Sep 17 00:00:00 2001 From: Takuro Wada Date: Sun, 23 Jun 2019 19:59:01 +0900 Subject: [PATCH 4/4] Fix FakeValidator --- pkg/validators/validators.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/validators/validators.go b/pkg/validators/validators.go index faba97793..652fe307c 100644 --- a/pkg/validators/validators.go +++ b/pkg/validators/validators.go @@ -50,6 +50,11 @@ func (v *FakeValidator) MakeAnnotationValidator() func(map[string]string) error return nil } +// MakeAnnotationNameValidator returns a nil function +func (v *FakeValidator) MakeAnnotationNameValidator() func([]string) error { + return nil +} + // MakeLabelValidator returns a nil function func (v *FakeValidator) MakeLabelValidator() func(map[string]string) error { return nil