From a755e9ad83935d86005d5d745567b10f26bdc413 Mon Sep 17 00:00:00 2001 From: "Sean R. Sullivan" Date: Fri, 17 Apr 2020 11:32:02 -0700 Subject: [PATCH] Expand package dir configs; exclude inventory object --- cmd/diff/cmddiff.go | 11 +++++++-- pkg/common/path.go | 49 +++++++++++++++++++++++++++++++++++++++++ pkg/common/path_test.go | 34 ++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 2 deletions(-) diff --git a/cmd/diff/cmddiff.go b/cmd/diff/cmddiff.go index 407531c..55c4d6a 100644 --- a/cmd/diff/cmddiff.go +++ b/cmd/diff/cmddiff.go @@ -13,6 +13,9 @@ import ( "sigs.k8s.io/cli-utils/pkg/common" ) +// NewCmdDiff returns cobra command to implement client-side diff of package +// directory. For each local config file, get the resource in the cluster +// and diff the local config resource against the resource in the cluster. func NewCmdDiff(f util.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { options := diff.NewDiffOptions(ioStreams) cmd := &cobra.Command{ @@ -33,13 +36,17 @@ func NewCmdDiff(f util.Factory, ioStreams genericclioptions.IOStreams) *cobra.Co // Returns error if there is an error filling in the options or if there // is not one argument that is a directory. func Initialize(o *diff.DiffOptions, f util.Factory, args []string) error { - var err error - // Validate the only argument is a (package) directory path. filenameFlags, err := common.DemandOneDirectory(args) if err != nil { return err } + // We do not want to diff the inventory object. So we expand + // the config file paths, excluding the inventory object. + filenameFlags, err = common.ExpandPackageDir(filenameFlags) + if err != nil { + return err + } o.FilenameOptions = filenameFlags.ToOptions() o.OpenAPISchema, err = f.OpenAPISchema() diff --git a/pkg/common/path.go b/pkg/common/path.go index 9d75353..da11af9 100644 --- a/pkg/common/path.go +++ b/pkg/common/path.go @@ -6,8 +6,12 @@ package common import ( "fmt" "os" + "path/filepath" "k8s.io/cli-runtime/pkg/genericclioptions" + "sigs.k8s.io/cli-utils/pkg/apply/prune" + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/kio/kioutil" ) func processPaths(paths []string) genericclioptions.FileNameFlags { @@ -47,3 +51,48 @@ func isPathADirectory(name string) bool { } return false } + +// ExpandPackageDir expands the one package directory entry in the flags to all +// the config file paths recursively. Excludes the inventory object (since +// this object is specially processed). Used for the diff command, so it will +// not always show a diff of the inventory object. Must be called AFTER +// DemandOneDirectory. +func ExpandPackageDir(f genericclioptions.FileNameFlags) (genericclioptions.FileNameFlags, error) { + if len(*f.Filenames) != 1 { + return f, fmt.Errorf("expand package directory should pass one package directory. "+ + "Passed the following paths: %v", f.Filenames) + } + configFilepaths, err := expandDir((*f.Filenames)[0]) + if err != nil { + return f, err + } + f.Filenames = &configFilepaths + return f, nil +} + +// expandDir takes a single package directory as a parameter, and returns +// an array of config file paths excluding the inventory object. Returns +// an error if one occurred while processing the paths. +func expandDir(dir string) ([]string, error) { + filepaths := []string{} + r := kio.LocalPackageReader{PackagePath: dir} + nodes, err := r.Read() + if err != nil { + return filepaths, err + } + for _, node := range nodes { + meta, err := node.GetMeta() + if err != nil { + continue + } + // If object has inventory label, skip it. + labels := meta.Labels + if _, exists := labels[prune.GroupingLabel]; exists { + continue + } + path := meta.Annotations[kioutil.PathAnnotation] + path = filepath.Join(dir, path) + filepaths = append(filepaths, path) + } + return filepaths, nil +} diff --git a/pkg/common/path_test.go b/pkg/common/path_test.go index d2886ad..d688509 100644 --- a/pkg/common/path_test.go +++ b/pkg/common/path_test.go @@ -62,3 +62,37 @@ func TestProcessPaths(t *testing.T) { }) } } + +func TestExpandDirErrors(t *testing.T) { + trueVal := true + testCases := map[string]struct { + paths []string + isError bool + }{ + "empty path is error": { + paths: []string{}, + isError: true, + }, + "more than one path is error": { + paths: []string{"fakedir1", "fakedir2"}, + isError: true, + }, + "path that is not dir is error": { + paths: []string{"fakedir1"}, + isError: true, + }, + } + + for tn, tc := range testCases { + t.Run(tn, func(t *testing.T) { + filenameFlags := genericclioptions.FileNameFlags{ + Filenames: &tc.paths, + Recursive: &trueVal, + } + _, err := ExpandPackageDir(filenameFlags) + if tc.isError && err == nil { + t.Fatalf("expected error but received none") + } + }) + } +}