Uses single file for both addLabel and addAnnotation commands, as the code is nearly identical. Tests included.

This commit is contained in:
guineveresaenger
2018-07-16 13:57:28 -07:00
parent 20fd433f75
commit afac2fb46a
4 changed files with 496 additions and 118 deletions

View File

@@ -17,24 +17,24 @@ limitations under the License.
package commands
import (
"errors"
"fmt"
"regexp"
"strings"
// "errors"
// "fmt"
// "regexp"
// "strings"
"github.com/spf13/cobra"
"github.com/kubernetes-sigs/kustomize/pkg/constants"
// "github.com/kubernetes-sigs/kustomize/pkg/constants"
"github.com/kubernetes-sigs/kustomize/pkg/fs"
)
type addAnnotationOptions struct {
annotations string
}
// type addAnnotationOptions struct {
// annotations string
// }
// newCmdAddAnnotation adds one or more commonAnnotations to the kustomization file.
func newCmdAddAnnotation(fsys fs.FileSystem) *cobra.Command {
var o addAnnotationOptions
var o addMetadataOptions
cmd := &cobra.Command{
Use: "annotation",
@@ -42,7 +42,8 @@ func newCmdAddAnnotation(fsys fs.FileSystem) *cobra.Command {
Example: `
add annotation {annotationKey1:annotationValue1},{annotationKey2:annotationValue2}`,
RunE: func(cmd *cobra.Command, args []string) error {
err := o.Validate(args)
mdKind := "annotation"
err := o.Validate(args, mdKind)
if err != nil {
return err
}
@@ -50,62 +51,62 @@ func newCmdAddAnnotation(fsys fs.FileSystem) *cobra.Command {
if err != nil {
return err
}
return o.RunAddAnnotation(fsys)
return o.RunAddMetadata(fsys, mdKind)
},
}
return cmd
}
// Validate validates addAnnotation command.
func (o *addAnnotationOptions) Validate(args []string) error {
if len(args) < 1 {
return errors.New("must specify an annotation")
}
if len(args) > 1 {
return errors.New("annotations must be comma-separated, with no spaces. See help text for example.")
}
inputs := strings.Split(args[0], ",")
for _, input := range inputs {
ok, err := regexp.MatchString(`\A([a-zA-Z0-9_.-]+):([a-zA-Z0-9_.-]+)\z`, input)
if err != nil {
return err
}
if !ok {
return fmt.Errorf("invalid annotation format: %s", input)
}
}
o.annotations = args[0]
return nil
}
// // Validate validates addAnnotation command.
// func (o *addAnnotationOptions) Validate(args []string) error {
// if len(args) < 1 {
// return errors.New("must specify an annotation")
// }
// if len(args) > 1 {
// return errors.New("annotations must be comma-separated, with no spaces. See help text for example.")
// }
// inputs := strings.Split(args[0], ",")
// for _, input := range inputs {
// ok, err := regexp.MatchString(`\A([a-zA-Z0-9_.-]+):([a-zA-Z0-9_.-]+)\z`, input)
// if err != nil {
// return err
// }
// if !ok {
// return fmt.Errorf("invalid annotation format: %s", input)
// }
// }
// o.annotations = args[0]
// return nil
// }
// Complete completes addAnnotation command.
func (o *addAnnotationOptions) Complete(cmd *cobra.Command, args []string) error {
return nil
}
// // Complete completes addAnnotation command.
// func (o *addAnnotationOptions) Complete(cmd *cobra.Command, args []string) error {
// return nil
// }
// RunAddAnnotation runs addAnnotation command (do real work).
func (o *addAnnotationOptions) RunAddAnnotation(fsys fs.FileSystem) error {
mf, err := newKustomizationFile(constants.KustomizationFileName, fsys)
if err != nil {
return err
}
// // RunAddAnnotation runs addAnnotation command (do real work).
// func (o *addAnnotationOptions) RunAddAnnotation(fsys fs.FileSystem) error {
// mf, err := newKustomizationFile(constants.KustomizationFileName, fsys)
// if err != nil {
// return err
// }
m, err := mf.read()
if err != nil {
return err
}
// m, err := mf.read()
// if err != nil {
// return err
// }
if m.CommonAnnotations == nil {
m.CommonAnnotations = make(map[string]string)
}
annotations := strings.Split(o.annotations, ",")
for _, ann := range annotations {
kv := strings.Split(ann, ":")
if _, ok := m.CommonAnnotations[kv[0]]; ok {
return fmt.Errorf("annotation %s already in kustomization file", kv[0])
}
m.CommonAnnotations[kv[0]] = kv[1]
}
// if m.CommonAnnotations == nil {
// m.CommonAnnotations = make(map[string]string)
// }
// annotations := strings.Split(o.annotations, ",")
// for _, ann := range annotations {
// kv := strings.Split(ann, ":")
// if _, ok := m.CommonAnnotations[kv[0]]; ok {
// return fmt.Errorf("annotation %s already in kustomization file", kv[0])
// }
// m.CommonAnnotations[kv[0]] = kv[1]
// }
return mf.write(m)
}
// return mf.write(m)
// }

View File

@@ -17,24 +17,25 @@ limitations under the License.
package commands
import (
"errors"
"fmt"
"regexp"
"strings"
// "errors"
// "fmt"
// "regexp"
// "strings"
"github.com/spf13/cobra"
"github.com/kubernetes-sigs/kustomize/pkg/constants"
// "github.com/kubernetes-sigs/kustomize/pkg/constants"
"github.com/kubernetes-sigs/kustomize/pkg/fs"
)
type addLabelOptions struct {
labels string
}
// type addLabelOptions struct {
// labels string
// }
// newCmdAddLabel adds one or more commonLabels to the kustomization file.
func newCmdAddLabel(fsys fs.FileSystem) *cobra.Command {
var o addLabelOptions
var o addMetadataOptions
cmd := &cobra.Command{
Use: "label",
@@ -42,7 +43,8 @@ func newCmdAddLabel(fsys fs.FileSystem) *cobra.Command {
Example: `
add label {labelKey1:labelValue1},{labelKey2:labelValue2}`,
RunE: func(cmd *cobra.Command, args []string) error {
err := o.Validate(args)
mdKind := "label"
err := o.Validate(args, mdKind)
if err != nil {
return err
}
@@ -50,65 +52,65 @@ func newCmdAddLabel(fsys fs.FileSystem) *cobra.Command {
if err != nil {
return err
}
return o.RunAddLabel(fsys)
return o.RunAddMetadata(fsys, mdKind)
},
}
return cmd
}
// Validate validates addLabel command.
func (o *addLabelOptions) Validate(args []string) error {
if len(args) < 1 {
return errors.New("must specify a label")
}
if len(args) > 1 {
return errors.New("labels must be comma-separated, with no spaces. See help text for example.")
}
inputs := strings.Split(args[0], ",")
for _, input := range inputs {
ok, err := regexp.MatchString(`\A([a-zA-Z0-9_.-]+):([a-zA-Z0-9_.-]+)\z`, input)
if err != nil {
return err
}
if !ok {
return fmt.Errorf("invalid label format: %s", input)
}
// // Validate validates addLabel command.
// func (o *addLabelOptions) Validate(args []string) error {
// if len(args) < 1 {
// return errors.New("must specify a label")
// }
// if len(args) > 1 {
// return errors.New("labels must be comma-separated, with no spaces. See help text for example.")
// }
// inputs := strings.Split(args[0], ",")
// for _, input := range inputs {
// ok, err := regexp.MatchString(`\A([a-zA-Z0-9_.-]+):([a-zA-Z0-9_.-]+)\z`, input)
// if err != nil {
// return err
// }
// if !ok {
// return fmt.Errorf("invalid label format: %s", input)
// }
}
// }
o.labels = args[0]
return nil
}
// o.labels = args[0]
// return nil
// }
// Complete completes addLabel command.
func (o *addLabelOptions) Complete(cmd *cobra.Command, args []string) error {
return nil
}
// // Complete completes addLabel command.
// func (o *addLabelOptions) Complete(cmd *cobra.Command, args []string) error {
// return nil
// }
// RunAddLabel runs addLabel command (do real work).
func (o *addLabelOptions) RunAddLabel(fsys fs.FileSystem) error {
mf, err := newKustomizationFile(constants.KustomizationFileName, fsys)
if err != nil {
return err
}
// // RunAddLabel runs addLabel command (do real work).
// func (o *addLabelOptions) RunAddLabel(fsys fs.FileSystem) error {
// mf, err := newKustomizationFile(constants.KustomizationFileName, fsys)
// if err != nil {
// return err
// }
m, err := mf.read()
if err != nil {
return err
}
// m, err := mf.read()
// if err != nil {
// return err
// }
if m.CommonLabels == nil {
m.CommonLabels = make(map[string]string)
}
// if m.CommonLabels == nil {
// m.CommonLabels = make(map[string]string)
// }
labels := strings.Split(o.labels, ",")
for _, label := range labels {
kv := strings.Split(label, ":")
if _, ok := m.CommonLabels[kv[0]]; ok {
return fmt.Errorf("label %s already in kustomization file", kv[0])
}
m.CommonLabels[kv[0]] = kv[1]
}
// labels := strings.Split(o.labels, ",")
// for _, label := range labels {
// kv := strings.Split(label, ":")
// if _, ok := m.CommonLabels[kv[0]]; ok {
// return fmt.Errorf("label %s already in kustomization file", kv[0])
// }
// m.CommonLabels[kv[0]] = kv[1]
// }
return mf.write(m)
}
// return mf.write(m)
// }

149
pkg/commands/addmetadata.go Normal file
View File

@@ -0,0 +1,149 @@
/*
Copyright 2018 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 commands
import (
"fmt"
"github.com/kubernetes-sigs/kustomize/pkg/constants"
"github.com/kubernetes-sigs/kustomize/pkg/fs"
"github.com/spf13/cobra"
"regexp"
"strings"
)
type addMetadataOptions struct {
metadata string
}
// newCmdAddAnnotation adds one or more commonAnnotations to the kustomization file.
func newCmdAddAnnotation(fsys fs.FileSystem) *cobra.Command {
var o addMetadataOptions
cmd := &cobra.Command{
Use: "annotation",
Short: "Adds one or more commonAnnotations to the kustomization.yaml in current directory",
Example: `
add annotation {annotationKey1:annotationValue1},{annotationKey2:annotationValue2}`,
RunE: func(cmd *cobra.Command, args []string) error {
mdKind := "annotation"
err := o.Validate(args, mdKind)
if err != nil {
return err
}
err = o.Complete(cmd, args)
if err != nil {
return err
}
return o.RunAddMetadata(fsys, mdKind)
},
}
return cmd
}
// newCmdAddLabel adds one or more commonLabels to the kustomization file.
func newCmdAddLabel(fsys fs.FileSystem) *cobra.Command {
var o addMetadataOptions
cmd := &cobra.Command{
Use: "label",
Short: "Adds one or more commonLabels to the kustomization.yaml in current directory",
Example: `
add label {labelKey1:labelValue1},{labelKey2:labelValue2}`,
RunE: func(cmd *cobra.Command, args []string) error {
mdKind := "label"
err := o.Validate(args, mdKind)
if err != nil {
return err
}
err = o.Complete(cmd, args)
if err != nil {
return err
}
return o.RunAddMetadata(fsys, mdKind)
},
}
return cmd
}
// Validate validates addLabel and addAnnotation commands.
func (o *addMetadataOptions) Validate(args []string, mdKind string) error {
if len(args) < 1 {
return fmt.Errorf("must specify %s", mdKind)
}
if len(args) > 1 {
return fmt.Errorf("%ss must be comma-separated, with no spaces. See help text for example", mdKind)
}
inputs := strings.Split(args[0], ",")
for _, input := range inputs {
ok, err := regexp.MatchString(`\A([a-zA-Z0-9_.-]+):([a-zA-Z0-9_.-]+)\z`, input)
if err != nil {
return err
}
if !ok {
return fmt.Errorf("invalid %s format: %s", mdKind, input)
}
}
o.metadata = args[0]
return nil
}
// Complete completes addMetadata command.
func (o *addMetadataOptions) Complete(cmd *cobra.Command, args []string) error {
return nil
}
// RunAddMetadata runs addLabel and addAnnotation commands (do real work).
func (o *addMetadataOptions) RunAddMetadata(fsys fs.FileSystem, mdKind string) error {
mf, err := newKustomizationFile(constants.KustomizationFileName, fsys)
if err != nil {
return err
}
m, err := mf.read()
if err != nil {
return err
}
if mdKind == "label" && m.CommonLabels == nil {
m.CommonLabels = make(map[string]string)
}
if mdKind == "annotation" && m.CommonAnnotations == nil {
m.CommonAnnotations = make(map[string]string)
}
entries := strings.Split(o.metadata, ",")
for _, entry := range entries {
kv := strings.Split(entry, ":")
if mdKind == "label" {
if _, ok := m.CommonLabels[kv[0]]; ok {
return fmt.Errorf("%s %s already in kustomization file", mdKind, kv[0])
}
m.CommonLabels[kv[0]] = kv[1]
}
if mdKind == "annotation" {
if _, ok := m.CommonAnnotations[kv[0]]; ok {
return fmt.Errorf("%s %s already in kustomization file", mdKind, kv[0])
}
m.CommonAnnotations[kv[0]] = kv[1]
}
}
return mf.write(m)
}

View File

@@ -0,0 +1,226 @@
/*
Copyright 2018 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 commands
import (
"testing"
"strings"
"github.com/kubernetes-sigs/kustomize/pkg/constants"
"github.com/kubernetes-sigs/kustomize/pkg/fs"
)
func TestLabelsValid(t *testing.T) {
var testcases = []struct {
input string
valid bool
name string
}{
{
input: "owls:great,unicorns:magical",
valid: true,
name: "Adds two labels",
},
{
input: "owls:great",
valid: false,
name: "Label keys must be unique",
},
{
input: "otters:cute",
valid: true,
name: "Adds single label",
},
{
input: "dogs,cats",
valid: false,
name: "Does not contain colon",
},
{
input: ":noKey",
valid: false,
name: "Missing key",
},
{
input: "noValue:",
valid: false,
name: "Missing value",
},
}
fakeFS := fs.MakeFakeFS()
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
cmd := newCmdAddLabel(fakeFS)
for _, tc := range testcases {
labels := strings.Split(tc.input, ",")
//run command with test input
args := []string{tc.input}
err := cmd.RunE(cmd, args)
if err != nil && tc.valid {
t.Errorf("for test case %s, unexpected cmd error: %v", tc.name, err)
}
if err == nil && !tc.valid {
t.Errorf("unexpected error: expected invalid annotation format error for test case %v", tc.name)
}
if err == nil && (tc.name == "Label keys must be unique") {
t.Errorf("unexpected error: for test case %s, expected already there problem", tc.name)
}
content, readErr := fakeFS.ReadFile(constants.KustomizationFileName)
if readErr != nil {
t.Errorf("unexpected read error: %v", readErr)
}
//check if valid input was added to commonLabels
for _, label := range labels {
key := strings.Split(label, ":")[0]
if !strings.Contains(string(content), key) && tc.valid {
t.Errorf("unexpected error: for test case %s, expected key to be in file.", tc.name)
}
}
}
}
func TestAddLabelNoArgs(t *testing.T) {
fakeFS := fs.MakeFakeFS()
cmd := newCmdAddLabel(fakeFS)
err := cmd.Execute()
if err == nil {
t.Errorf("expected an error but error is: %v", err)
}
if err != nil && err.Error() != "must specify label" {
t.Errorf("incorrect error: %v", err.Error())
}
}
func TestAddLabelMultipleArgs(t *testing.T) {
fakeFS := fs.MakeFakeFS()
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
cmd := newCmdAddLabel(fakeFS)
args := []string{"this:input", "has:spaces"}
err := cmd.RunE(cmd, args)
if err == nil {
t.Errorf("expected an error but error is: %v", err)
}
if err != nil && err.Error() != "labels must be comma-separated, with no spaces. See help text for example" {
t.Errorf("incorrect error: %v", err.Error())
}
}
func TestAnnotationsValid(t *testing.T) {
var testcases = []struct {
input string
valid bool
name string
}{
{
input: "cats:great,dogs:okay",
valid: true,
name: "Adds two annotations",
},
{
input: "cats:great",
valid: false,
name: "Annotation keys must be unique",
},
{
input: "owls:best",
valid: true,
name: "Adds single annotation",
},
{
input: "cake,cookies",
valid: false,
name: "Does not contain colon",
},
{
input: ":hasNoKey",
valid: false,
name: "Missing key",
},
{
input: "hasNoValue:",
valid: false,
name: "Missing value",
},
}
fakeFS := fs.MakeFakeFS()
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
cmd := newCmdAddAnnotation(fakeFS)
for _, tc := range testcases {
annotations := strings.Split(tc.input, ",")
//run command with test input
args := []string{tc.input}
err := cmd.RunE(cmd, args)
if err != nil && tc.valid {
t.Errorf("for test case %s, unexpected cmd error: %v", tc.name, err)
}
if err == nil && !tc.valid {
t.Errorf("unexpected error: expected invalid annotation format error for test case %v", tc.name)
}
if err == nil && (tc.name == "Annotation keys must be unique") {
t.Errorf("unexpected error: for test case %s, expected already there problem", tc.name)
}
content, readErr := fakeFS.ReadFile(constants.KustomizationFileName)
if readErr != nil {
t.Errorf("unexpected read error: %v", readErr)
}
//check if valid input was added to commonAnnotations
for _, annotation := range annotations {
key := strings.Split(annotation, ":")[0]
if !strings.Contains(string(content), key) && tc.valid {
t.Errorf("unexpected error: for test case %s, expected key to be in file.", tc.name)
}
}
}
}
func TestAddAnnotationNoArgs(t *testing.T) {
fakeFS := fs.MakeFakeFS()
cmd := newCmdAddAnnotation(fakeFS)
err := cmd.Execute()
if err == nil {
t.Errorf("expected an error but error is %v", err)
}
if err != nil && err.Error() != "must specify annotation" {
t.Errorf("incorrect error: %v", err.Error())
}
}
func TestAddAnnotationMultipleArgs(t *testing.T) {
fakeFS := fs.MakeFakeFS()
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
cmd := newCmdAddAnnotation(fakeFS)
args := []string{"this:annotation", "has:spaces"}
err := cmd.RunE(cmd, args)
if err == nil {
t.Errorf("expected an error but error is %v", err)
}
if err != nil && err.Error() != "annotations must be comma-separated, with no spaces. See help text for example" {
t.Errorf("incorrect error: %v", err.Error())
}
}