diff --git a/pkg/commands/edit/add/addpatch.go b/pkg/commands/edit/add/addpatch.go index abd8c4826..7ab1e871b 100644 --- a/pkg/commands/edit/add/addpatch.go +++ b/pkg/commands/edit/add/addpatch.go @@ -21,6 +21,7 @@ import ( "log" "github.com/spf13/cobra" + "sigs.k8s.io/kustomize/v3/pkg/commands/edit/util" "sigs.k8s.io/kustomize/v3/pkg/commands/kustfile" "sigs.k8s.io/kustomize/v3/pkg/fs" "sigs.k8s.io/kustomize/v3/pkg/patch" @@ -70,7 +71,7 @@ func (o *addPatchOptions) Complete(cmd *cobra.Command, args []string) error { // RunAddPatch runs addPatch command (do real work). func (o *addPatchOptions) RunAddPatch(fSys fs.FileSystem) error { - patches, err := globPatterns(fSys, o.patchFilePaths) + patches, err := util.GlobPatterns(fSys, o.patchFilePaths) if err != nil { return err } diff --git a/pkg/commands/edit/add/addresource.go b/pkg/commands/edit/add/addresource.go index 6b9964475..37c63a5ea 100644 --- a/pkg/commands/edit/add/addresource.go +++ b/pkg/commands/edit/add/addresource.go @@ -21,6 +21,7 @@ import ( "log" "github.com/spf13/cobra" + "sigs.k8s.io/kustomize/v3/pkg/commands/edit/util" "sigs.k8s.io/kustomize/v3/pkg/commands/kustfile" "sigs.k8s.io/kustomize/v3/pkg/fs" ) @@ -69,7 +70,7 @@ func (o *addResourceOptions) Complete(cmd *cobra.Command, args []string) error { // RunAddResource runs addResource command (do real work). func (o *addResourceOptions) RunAddResource(fSys fs.FileSystem) error { - resources, err := globPatterns(fSys, o.resourceFilePaths) + resources, err := util.GlobPatterns(fSys, o.resourceFilePaths) if err != nil { return err } diff --git a/pkg/commands/edit/add/flagsandargs.go b/pkg/commands/edit/add/flagsandargs.go index 75fbb4f6e..85807c2ac 100644 --- a/pkg/commands/edit/add/flagsandargs.go +++ b/pkg/commands/edit/add/flagsandargs.go @@ -20,6 +20,7 @@ import ( "fmt" "strings" + "sigs.k8s.io/kustomize/v3/pkg/commands/edit/util" "sigs.k8s.io/kustomize/v3/pkg/fs" ) @@ -85,7 +86,7 @@ func (a *flagsAndArgs) ExpandFileSource(fSys fs.FileSystem) error { } else { patterns = append(patterns, s[0]) } - result, err := globPatterns(fSys, patterns) + result, err := util.GlobPatterns(fSys, patterns) if err != nil { return err } diff --git a/pkg/commands/edit/add/util.go b/pkg/commands/edit/add/util.go deleted file mode 100644 index 56cafa95b..000000000 --- a/pkg/commands/edit/add/util.go +++ /dev/null @@ -1,39 +0,0 @@ -/* -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 add - -import ( - "log" - - "sigs.k8s.io/kustomize/v3/pkg/fs" -) - -func globPatterns(fsys fs.FileSystem, patterns []string) ([]string, error) { - var result []string - for _, pattern := range patterns { - files, err := fsys.Glob(pattern) - if err != nil { - return nil, err - } - if len(files) == 0 { - log.Printf("%s has no match", pattern) - continue - } - result = append(result, files...) - } - return result, nil -} diff --git a/pkg/commands/edit/remove/all.go b/pkg/commands/edit/remove/all.go index eb258a3d4..e34b82e02 100644 --- a/pkg/commands/edit/remove/all.go +++ b/pkg/commands/edit/remove/all.go @@ -35,6 +35,9 @@ func NewCmdRemove( kustomize edit remove resource {filepath} {filepath} kustomize edit remove resource {pattern} + # Removes one or more patches from the kustomization file + kustomize edit remove patch + # Removes one or more commonLabels from the kustomization file kustomize edit remove label {labelKey1},{labelKey2} @@ -47,6 +50,7 @@ func NewCmdRemove( newCmdRemoveResource(fsys), newCmdRemoveLabel(fsys, ldr.Validator().MakeLabelNameValidator()), newCmdRemoveAnnotation(fsys, ldr.Validator().MakeAnnotationNameValidator()), + newCmdRemovePatch(fsys), ) return c } diff --git a/pkg/commands/edit/remove/removepatch.go b/pkg/commands/edit/remove/removepatch.go new file mode 100644 index 000000000..f40995332 --- /dev/null +++ b/pkg/commands/edit/remove/removepatch.go @@ -0,0 +1,91 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package remove + +import ( + "log" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + "sigs.k8s.io/kustomize/v3/pkg/commands/edit/util" + "sigs.k8s.io/kustomize/v3/pkg/commands/kustfile" + "sigs.k8s.io/kustomize/v3/pkg/fs" + "sigs.k8s.io/kustomize/v3/pkg/patch" + "sigs.k8s.io/kustomize/v3/pkg/pgmconfig" +) + +type removePatchOptions struct { + patchFilePaths []string +} + +// newCmdRemovePatch removes the name of a file containing a patch from the kustomization file. +func newCmdRemovePatch(fsys fs.FileSystem) *cobra.Command { + var o removePatchOptions + + cmd := &cobra.Command{ + Use: "patch", + Short: "Removes one or more patches from " + pgmconfig.KustomizationFileNames[0], + Example: ` + remove patch {filepath}`, + RunE: func(cmd *cobra.Command, args []string) error { + err := o.Validate(args) + if err != nil { + return err + } + err = o.Complete(cmd, args) + if err != nil { + return err + } + return o.RunRemovePatch(fsys) + }, + } + return cmd +} + +// Validate validates removePatch command. +func (o *removePatchOptions) Validate(args []string) error { + if len(args) == 0 { + return errors.New("must specify a patch file") + } + o.patchFilePaths = args + return nil +} + +// Complete completes removePatch command. +func (o *removePatchOptions) Complete(cmd *cobra.Command, args []string) error { + return nil +} + +// RunRemovePatch runs removePatch command (do real work). +func (o *removePatchOptions) RunRemovePatch(fSys fs.FileSystem) error { + patches, err := util.GlobPatterns(fSys, o.patchFilePaths) + if err != nil { + return err + } + if len(patches) == 0 { + return nil + } + + mf, err := kustfile.NewKustomizationFile(fSys) + if err != nil { + return err + } + + m, err := mf.Read() + if err != nil { + return err + } + + var removePatches []string + for _, p := range patches { + if !patch.Exist(m.PatchesStrategicMerge, p) { + log.Printf("patch %s doesn't exist in kustomization file", p) + continue + } + removePatches = append(removePatches, p) + } + m.PatchesStrategicMerge = patch.Delete(m.PatchesStrategicMerge, removePatches...) + + return mf.Write(m) +} diff --git a/pkg/commands/edit/remove/removepatch_test.go b/pkg/commands/edit/remove/removepatch_test.go new file mode 100644 index 000000000..90f168c1a --- /dev/null +++ b/pkg/commands/edit/remove/removepatch_test.go @@ -0,0 +1,136 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package remove + +import ( + "fmt" + "strings" + "testing" + + "sigs.k8s.io/kustomize/v3/pkg/fs" + "sigs.k8s.io/kustomize/v3/pkg/patch" +) + +const ( + patchFileContent = ` +Lorem ipsum dolor sit amet, consectetur adipiscing elit, +sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +` +) + +func makeKustomizationPatchFS() fs.FileSystem { + fakeFS := fs.MakeFakeFS() + patches := []string{"patch1.yaml", "patch2.yaml"} + + fakeFS.WriteTestKustomizationWith([]byte( + fmt.Sprintf("patchesStrategicMerge:\n - %s", + strings.Join(patches, "\n - ")))) + + for _, p := range patches { + fakeFS.WriteFile(p, []byte(patchFileContent)) + } + fakeFS.WriteFile("patch3.yaml", []byte(patchFileContent)) + return fakeFS +} + +func TestRemovePatch(t *testing.T) { + fakeFS := makeKustomizationPatchFS() + cmd := newCmdRemovePatch(fakeFS) + args := []string{"patch1.yaml"} + err := cmd.RunE(cmd, args) + + if err != nil { + t.Errorf("unexpected error %v", err) + } + + m := readKustomizationFS(t, fakeFS) + for _, k := range args { + if patch.Exist(m.PatchesStrategicMerge, k) { + t.Errorf("%s must be deleted", k) + } + } +} + +func TestRemovePatchMultipleArgs(t *testing.T) { + fakeFS := makeKustomizationPatchFS() + cmd := newCmdRemovePatch(fakeFS) + args := []string{"patch1.yaml", "patch2.yaml"} + err := cmd.RunE(cmd, args) + + if err != nil { + t.Errorf("unexpected error %v", err) + } + + m := readKustomizationFS(t, fakeFS) + for _, k := range args { + if patch.Exist(m.PatchesStrategicMerge, k) { + t.Errorf("%s must be deleted", k) + } + } +} + +func TestRemovePatchGlob(t *testing.T) { + fakeFS := makeKustomizationPatchFS() + cmd := newCmdRemovePatch(fakeFS) + args := []string{"patch*.yaml"} + err := cmd.RunE(cmd, args) + + if err != nil { + t.Errorf("unexpected error %v", err) + } + + m := readKustomizationFS(t, fakeFS) + if len(m.PatchesStrategicMerge) != 0 { + t.Errorf("all patch must be deleted") + } +} + +func TestRemovePatchNotDefinedInKustomization(t *testing.T) { + fakeFS := makeKustomizationPatchFS() + cmd := newCmdRemovePatch(fakeFS) + args := []string{"patch3.yaml"} + err := cmd.RunE(cmd, args) + + if err != nil { + t.Errorf("unexpected error %v", err) + } + + m := readKustomizationFS(t, fakeFS) + for _, k := range []string{"patch1.yaml", "patch2.yaml"} { + if !patch.Exist(m.PatchesStrategicMerge, k) { + t.Errorf("%s must exist", k) + } + } +} + +func TestRemovePatchNotExist(t *testing.T) { + fakeFS := makeKustomizationPatchFS() + cmd := newCmdRemovePatch(fakeFS) + args := []string{"patch4.yaml"} + err := cmd.RunE(cmd, args) + + if err != nil { + t.Errorf("unexpected error %v", err) + } + + m := readKustomizationFS(t, fakeFS) + for _, k := range []string{"patch1.yaml", "patch2.yaml"} { + if !patch.Exist(m.PatchesStrategicMerge, k) { + t.Errorf("%s must exist", k) + } + } +} + +func TestRemovePatchNoArgs(t *testing.T) { + fakeFS := makeKustomizationPatchFS() + cmd := newCmdRemovePatch(fakeFS) + err := cmd.RunE(cmd, nil) + + if err == nil { + t.Errorf("expected an error") + } + if err.Error() != "must specify a patch file" { + t.Errorf("incorrect error: %v", err.Error()) + } +} diff --git a/pkg/commands/edit/remove/removeresource.go b/pkg/commands/edit/remove/removeresource.go index d0eab20ec..517182c57 100644 --- a/pkg/commands/edit/remove/removeresource.go +++ b/pkg/commands/edit/remove/removeresource.go @@ -19,6 +19,7 @@ package remove import ( "errors" "path/filepath" + "sigs.k8s.io/kustomize/v3/pkg/pgmconfig" "github.com/spf13/cobra" "sigs.k8s.io/kustomize/v3/pkg/commands/kustfile" @@ -35,7 +36,7 @@ func newCmdRemoveResource(fsys fs.FileSystem) *cobra.Command { cmd := &cobra.Command{ Use: "resource", - Short: "Remove resource file paths to the kustomization file.", + Short: "Removes one or more resource file paths from " + pgmconfig.KustomizationFileNames[0], Example: ` remove resource my-resource.yml remove resource resource1.yml resource2.yml resource3.yml diff --git a/pkg/commands/edit/util/functions.go b/pkg/commands/edit/util/functions.go new file mode 100644 index 000000000..407e13027 --- /dev/null +++ b/pkg/commands/edit/util/functions.go @@ -0,0 +1,26 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package util + +import ( + "log" + + "sigs.k8s.io/kustomize/v3/pkg/fs" +) + +func GlobPatterns(fsys fs.FileSystem, patterns []string) ([]string, error) { + var result []string + for _, pattern := range patterns { + files, err := fsys.Glob(pattern) + if err != nil { + return nil, err + } + if len(files) == 0 { + log.Printf("%s has no match", pattern) + continue + } + result = append(result, files...) + } + return result, nil +} diff --git a/pkg/patch/strategicmerge.go b/pkg/patch/strategicmerge.go index 9042eb844..deec8980c 100644 --- a/pkg/patch/strategicmerge.go +++ b/pkg/patch/strategicmerge.go @@ -35,3 +35,20 @@ func Exist(patches []types.PatchStrategicMerge, path string) bool { } return false } + +// Delete deletes patches from a PatchStrategicMerge slice +func Delete(patches []types.PatchStrategicMerge, paths ...string) []types.PatchStrategicMerge { + // Convert paths into PatchStrategicMerge slice + convertedPath := make([]types.PatchStrategicMerge, len(paths)) + for i, p := range paths { + convertedPath[i] = types.PatchStrategicMerge(p) + } + + filteredPatches := make([]types.PatchStrategicMerge, 0, len(patches)) + for _, containedPatch := range patches { + if !Exist(convertedPath, string(containedPatch)) { + filteredPatches = append(filteredPatches, containedPatch) + } + } + return filteredPatches +} diff --git a/pkg/patch/strategicmerge_test.go b/pkg/patch/strategicmerge_test.go new file mode 100644 index 000000000..1cf96d45b --- /dev/null +++ b/pkg/patch/strategicmerge_test.go @@ -0,0 +1,83 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2. + +package patch + +import ( + "testing" + + "sigs.k8s.io/kustomize/v3/pkg/types" +) + +func buildPatchStrategicMergeSlice(patchStrings []string) []types.PatchStrategicMerge { + var patches []types.PatchStrategicMerge + for _, patchString := range patchStrings { + patches = append(patches, types.PatchStrategicMerge(patchString)) + } + return patches +} + +func TestAppend(t *testing.T) { + patchStrings := []string{"patch1.yaml", "patch2.yaml"} + patches := buildPatchStrategicMergeSlice(patchStrings) + + patches = Append(patches, "patch3.yaml") + + for i, k := range []string{"patch1.yaml", "patch2.yaml", "patch3.yaml"} { + if patches[i] != types.PatchStrategicMerge(k) { + t.Fatalf("patches[%d] must be %s, got %s", i, k, patches[i]) + } + } +} + +func TestExistTrue(t *testing.T) { + patchStrings := []string{"patch1.yaml", "patch2.yaml"} + patches := buildPatchStrategicMergeSlice(patchStrings) + + for _, patchString := range patchStrings { + if !Exist(patches, patchString) { + t.Fatalf("%s must exist", patchString) + } + } +} + +func TestExistFalse(t *testing.T) { + patchStrings := []string{"patch1.yaml", "patch2.yaml"} + patches := buildPatchStrategicMergeSlice(patchStrings) + + for _, patchString := range []string{"invalid1.yaml", "invalid2.yaml"} { + if Exist(patches, patchString) { + t.Fatalf("%s must not exist", patchString) + } + } +} + +func TestDelete(t *testing.T) { + patchStrings := []string{"patch1.yaml", "patch2.yaml"} + patches := buildPatchStrategicMergeSlice(patchStrings) + + patches = Delete(patches, "patch1.yaml") + + if Exist(patches, "patch1.yaml") { + t.Fatalf("patch1.yaml should be deleted") + } + if !Exist(patches, "patch2.yaml") { + t.Fatalf("patch2.yaml should exist") + } + if len(patches) != 1 { + t.Fatalf("Length of slice must be 1: actual %d", len(patches)) + } +} + +func TestDeleteMultiple(t *testing.T) { + patchStrings := []string{"patch1.yaml", "patch2.yaml"} + patches := buildPatchStrategicMergeSlice(patchStrings) + + patches = Delete(patches, "patch2.yaml", "patch4.yaml", "patch1.yaml", "patch3.yaml") + + for _, k := range patchStrings { + if Exist(patches, k) { + t.Fatalf("%s should be deleted", k) + } + } +}