mirror of https://github.com/fluxcd/cli-utils.git
Add StdIn as an acceptable argument for apply, preview, destroy, and diff commands
This commit is contained in:
parent
b3a34cc049
commit
681ceda41d
|
@ -23,9 +23,9 @@ func GetApplyRunner(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *A
|
|||
ioStreams: ioStreams,
|
||||
}
|
||||
cmd := &cobra.Command{
|
||||
Use: "apply DIRECTORY",
|
||||
Use: "apply (DIRECTORY | STDIN)",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: i18n.T("Apply a configuration to a resource by filename or stdin"),
|
||||
Short: i18n.T("Apply a configuration to a resource by package directory or stdin"),
|
||||
Run: r.Run,
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ func NewCmdDestroy(f util.Factory, ioStreams genericclioptions.IOStreams) *cobra
|
|||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "destroy DIRECTORY",
|
||||
Use: "destroy (DIRECTORY | STDIN)",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: i18n.T("Destroy all the resources related to configuration"),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
func NewCmdDiff(f util.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
|
||||
options := diff.NewDiffOptions(ioStreams)
|
||||
cmd := &cobra.Command{
|
||||
Use: "diff DIRECTORY",
|
||||
Use: "diff (DIRECTORY | STDIN)",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: i18n.T("Diff local config against cluster applied version"),
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
|
|
|
@ -24,7 +24,7 @@ func NewCmdPreview(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *co
|
|||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "preview DIRECTORY",
|
||||
Use: "preview (DIRECTORY | STDIN)",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: i18n.T("Preview the apply of a configuration"),
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
|
|
|
@ -13,32 +13,43 @@ import (
|
|||
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
|
||||
)
|
||||
|
||||
const stdinDash = "-"
|
||||
|
||||
func processPaths(paths []string) genericclioptions.FileNameFlags {
|
||||
// No arguments means we are reading from StdIn
|
||||
fileNameFlags := genericclioptions.FileNameFlags{}
|
||||
if len(paths) == 0 {
|
||||
fileNames := []string{"-"}
|
||||
fileNames := []string{stdinDash}
|
||||
fileNameFlags.Filenames = &fileNames
|
||||
return fileNameFlags
|
||||
}
|
||||
|
||||
// Must be a single directory here; set recursive flag.
|
||||
t := true
|
||||
fileNameFlags.Filenames = &paths
|
||||
fileNameFlags.Recursive = &t
|
||||
return fileNameFlags
|
||||
}
|
||||
|
||||
// DemandOneDirectoryOrStdin processes "paths" to ensure the
|
||||
// single argument in the array is a directory. Returns FileNameFlags
|
||||
// populated with the directory (recursive flag set), or
|
||||
// the StdIn dash. An empty array gets treated as StdIn
|
||||
// (adding dash to the array). Returns an error if more than
|
||||
// one element in the array or the filepath is not a directory.
|
||||
func DemandOneDirectory(paths []string) (genericclioptions.FileNameFlags, error) {
|
||||
result := processPaths(paths)
|
||||
// alas, the things called file names should have been called paths.
|
||||
if len(*result.Filenames) != 1 {
|
||||
result := genericclioptions.FileNameFlags{}
|
||||
if len(paths) == 1 {
|
||||
dirPath := paths[0]
|
||||
if !isPathADirectory(dirPath) {
|
||||
return result, fmt.Errorf("argument '%s' is not but must be a directory", dirPath)
|
||||
}
|
||||
}
|
||||
if len(paths) > 1 {
|
||||
return result, fmt.Errorf(
|
||||
"specify exactly one directory path argument; rejecting %v", paths)
|
||||
}
|
||||
path := (*result.Filenames)[0]
|
||||
if !isPathADirectory(path) {
|
||||
return result, fmt.Errorf("argument '%s' is not but must be a directory", path)
|
||||
}
|
||||
result = processPaths(paths)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -13,57 +13,31 @@ import (
|
|||
"sigs.k8s.io/cli-utils/pkg/testutil"
|
||||
)
|
||||
|
||||
func TestProcessPaths(t *testing.T) {
|
||||
trueVal := true
|
||||
testCases := map[string]struct {
|
||||
paths []string
|
||||
expectedFileNameFlags genericclioptions.FileNameFlags
|
||||
errFromDemandOneDirectory string
|
||||
}{
|
||||
"empty slice means reading from StdIn": {
|
||||
paths: []string{},
|
||||
expectedFileNameFlags: genericclioptions.FileNameFlags{
|
||||
Filenames: &[]string{"-"},
|
||||
},
|
||||
errFromDemandOneDirectory: "argument '-' is not but must be a directory",
|
||||
},
|
||||
"single file in slice means reading from that path": {
|
||||
paths: []string{"object.yaml"},
|
||||
expectedFileNameFlags: genericclioptions.FileNameFlags{
|
||||
Filenames: &[]string{"object.yaml"},
|
||||
Recursive: &trueVal,
|
||||
},
|
||||
errFromDemandOneDirectory: "argument 'object.yaml' is not but must be a directory",
|
||||
},
|
||||
"single dir in slice": {
|
||||
paths: []string{"/tmp"},
|
||||
expectedFileNameFlags: genericclioptions.FileNameFlags{
|
||||
Filenames: &[]string{"/tmp"},
|
||||
Recursive: &trueVal,
|
||||
},
|
||||
},
|
||||
"multiple elements in slice means reading from all files": {
|
||||
paths: []string{"rs.yaml", "dep.yaml"},
|
||||
expectedFileNameFlags: genericclioptions.FileNameFlags{
|
||||
Filenames: &[]string{"rs.yaml", "dep.yaml"},
|
||||
Recursive: &trueVal,
|
||||
},
|
||||
errFromDemandOneDirectory: "specify exactly one directory path argument; rejecting [rs.yaml dep.yaml]",
|
||||
},
|
||||
}
|
||||
const (
|
||||
packageDir = "test-pkg-dir"
|
||||
inventoryFilename = "inventory.yaml"
|
||||
podAFilename = "pod-a.yaml"
|
||||
podBFilename = "pod-b.yaml"
|
||||
)
|
||||
|
||||
for tn, tc := range testCases {
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
var err error
|
||||
fileNameFlags := processPaths(tc.paths)
|
||||
assert.DeepEqual(t, tc.expectedFileNameFlags, fileNameFlags)
|
||||
fileNameFlags, err = DemandOneDirectory(tc.paths)
|
||||
assert.DeepEqual(t, tc.expectedFileNameFlags, fileNameFlags)
|
||||
if err != nil && err.Error() != tc.errFromDemandOneDirectory {
|
||||
assert.Equal(t, err.Error(), tc.errFromDemandOneDirectory)
|
||||
}
|
||||
})
|
||||
}
|
||||
var (
|
||||
inventoryFilePath = filepath.Join(packageDir, inventoryFilename)
|
||||
podAFilePath = filepath.Join(packageDir, podAFilename)
|
||||
podBFilePath = filepath.Join(packageDir, podBFilename)
|
||||
)
|
||||
|
||||
func setupTestFilesystem(t *testing.T) testutil.TestFilesystem {
|
||||
// Create the test filesystem, and add package config files
|
||||
// to it.
|
||||
t.Log("Creating test filesystem")
|
||||
tf := testutil.Setup(t, packageDir)
|
||||
t.Logf("Adding File: %s", inventoryFilePath)
|
||||
tf.WriteFile(t, inventoryFilePath, inventoryConfigMap)
|
||||
t.Logf("Adding File: %s", podAFilePath)
|
||||
tf.WriteFile(t, podAFilePath, podA)
|
||||
t.Logf("Adding File: %s", podBFilePath)
|
||||
tf.WriteFile(t, podBFilePath, podB)
|
||||
return tf
|
||||
}
|
||||
|
||||
var inventoryConfigMap = []byte(`
|
||||
|
@ -104,17 +78,62 @@ spec:
|
|||
image: k8s.gcr.io/pause:2.0
|
||||
`)
|
||||
|
||||
func TestExpandDirErrors(t *testing.T) {
|
||||
// Create the test filesystem, and add package config files
|
||||
// to it.
|
||||
packageDir := "test-pkg-dir"
|
||||
tf := testutil.Setup(t, packageDir)
|
||||
tf.WriteFile(t, filepath.Join(packageDir, "inventory.yaml"), inventoryConfigMap)
|
||||
tf.WriteFile(t, filepath.Join(packageDir, "pod-a.yaml"), podA)
|
||||
tf.WriteFile(t, filepath.Join(packageDir, "pod-b.yaml"), podB)
|
||||
func TestProcessPaths(t *testing.T) {
|
||||
tf := setupTestFilesystem(t)
|
||||
defer tf.Clean()
|
||||
|
||||
trueVal := true
|
||||
testCases := map[string]struct {
|
||||
paths []string
|
||||
expectedFileNameFlags genericclioptions.FileNameFlags
|
||||
errFromDemandOneDirectory string
|
||||
}{
|
||||
"empty slice means reading from StdIn": {
|
||||
paths: []string{},
|
||||
expectedFileNameFlags: genericclioptions.FileNameFlags{
|
||||
Filenames: &[]string{"-"},
|
||||
},
|
||||
},
|
||||
"single file in slice is error; must be directory": {
|
||||
paths: []string{podAFilePath},
|
||||
expectedFileNameFlags: genericclioptions.FileNameFlags{
|
||||
Filenames: nil,
|
||||
Recursive: nil,
|
||||
},
|
||||
errFromDemandOneDirectory: "argument 'test-pkg-dir/pod-a.yaml' is not but must be a directory",
|
||||
},
|
||||
"single dir in slice": {
|
||||
paths: []string{tf.GetRootDir()},
|
||||
expectedFileNameFlags: genericclioptions.FileNameFlags{
|
||||
Filenames: &[]string{tf.GetRootDir()},
|
||||
Recursive: &trueVal,
|
||||
},
|
||||
},
|
||||
"multiple arguments is an error": {
|
||||
paths: []string{podAFilePath, podBFilePath},
|
||||
expectedFileNameFlags: genericclioptions.FileNameFlags{
|
||||
Filenames: nil,
|
||||
Recursive: nil,
|
||||
},
|
||||
errFromDemandOneDirectory: "specify exactly one directory path argument; rejecting [test-pkg-dir/pod-a.yaml test-pkg-dir/pod-b.yaml]",
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range testCases {
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
fileNameFlags, err := DemandOneDirectory(tc.paths)
|
||||
assert.DeepEqual(t, tc.expectedFileNameFlags, fileNameFlags)
|
||||
if err != nil && err.Error() != tc.errFromDemandOneDirectory {
|
||||
assert.Equal(t, err.Error(), tc.errFromDemandOneDirectory)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpandDirErrors(t *testing.T) {
|
||||
tf := setupTestFilesystem(t)
|
||||
defer tf.Clean()
|
||||
|
||||
testCases := map[string]struct {
|
||||
packageDirPath []string
|
||||
expandedPaths []string
|
||||
|
@ -144,6 +163,7 @@ func TestExpandDirErrors(t *testing.T) {
|
|||
|
||||
for tn, tc := range testCases {
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
trueVal := true
|
||||
filenameFlags := genericclioptions.FileNameFlags{
|
||||
Filenames: &tc.packageDirPath,
|
||||
Recursive: &trueVal,
|
||||
|
|
Loading…
Reference in New Issue