Skip to content

Commit

Permalink
Merge pull request #2494 from dgageot/simpler-faster-fidn-configs
Browse files Browse the repository at this point in the history
Simpler faster find configs
  • Loading branch information
balopat authored Jul 18, 2019
2 parents f988df5 + 3aa7f71 commit c3f9521
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 112 deletions.
6 changes: 6 additions & 0 deletions cmd/skaffold/app/cmd/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type Builder interface {
WithExample(comment, command string) Builder
WithFlags(adder func(*pflag.FlagSet)) Builder
WithCommonFlags() Builder
Hidden() Builder
ExactArgs(argCount int, action func(io.Writer, []string) error) *cobra.Command
NoArgs(action func(io.Writer) error) *cobra.Command
}
Expand Down Expand Up @@ -76,6 +77,11 @@ func (b *builder) WithFlags(adder func(*pflag.FlagSet)) Builder {
return b
}

func (b *builder) Hidden() Builder {
b.cmd.Hidden = true
return b
}

func (b *builder) ExactArgs(argCount int, action func(io.Writer, []string) error) *cobra.Command {
b.cmd.Args = cobra.ExactArgs(argCount)
b.cmd.RunE = func(_ *cobra.Command, args []string) error {
Expand Down
8 changes: 8 additions & 0 deletions cmd/skaffold/app/cmd/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@ func TestNewCmdWithCommonFlags(t *testing.T) {
}
}

func TestNewCmdHidden(t *testing.T) {
cmd := NewCmd("").NoArgs(nil)
testutil.CheckDeepEqual(t, false, cmd.Hidden)

cmd = NewCmd("").Hidden().NoArgs(nil)
testutil.CheckDeepEqual(t, true, cmd.Hidden)
}

func listFlags(set *pflag.FlagSet) map[string]*pflag.Flag {
flagsByName := make(map[string]*pflag.Flag)

Expand Down
54 changes: 18 additions & 36 deletions cmd/skaffold/app/cmd/find_configs.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,15 @@ limitations under the License.
package cmd

import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"strings"

"github.com/GoogleContainerTools/skaffold/pkg/skaffold/color"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
"github.com/karrick/godirwalk"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
Expand All @@ -40,76 +37,61 @@ var (

// NewCmdFindConfigs list the skaffold config files in the specified directory.
func NewCmdFindConfigs() *cobra.Command {
cmd := NewCmd("find-configs").
return NewCmd("find-configs").
WithDescription("Find in a given directory all skaffold yamls files that are parseable or upgradeable with their versions.").
WithFlags(func(f *pflag.FlagSet) {
// Default to current directory
f.StringVarP(&directory, "directory", "d", ".", "Root directory to lookup the config files.")
// Output format of this Command
f.StringVarP(&format, "output", "o", "table", "Result format, default to table. [(-o|--output=)json|table]")
}).
Hidden().
NoArgs(doFindConfigs)
cmd.Hidden = true
return cmd
}

func doFindConfigs(out io.Writer) error {
pathToVersion, err := findConfigs(directory)

if err != nil {
return err
}

switch format {
case "json":
jsonBytes, err := json.Marshal(pathToVersion)
if err != nil {
return err
}
encoder := json.NewEncoder(out)
encoder.SetIndent("", "\t")
return encoder.Encode(pathToVersion)

var prettyJSON bytes.Buffer
err = json.Indent(&prettyJSON, jsonBytes, "", "\t")
if err != nil {
return err
}
fmt.Fprintln(out, prettyJSON.String())
case "table":
pathOutLen, versionOutLen := 70, 30
for p, v := range pathToVersion {
var c color.Color
if v == latest.Version {
c = color.Default
} else {
c := color.Default
if v != latest.Version {
c = color.Green
}
c.Fprintf(out, fmt.Sprintf("%%-%ds\t%%-%ds\n", pathOutLen, versionOutLen), p, v)
}

return nil

default:
return errors.New("unsupported template")
return fmt.Errorf("unsupported template: %s", format)
}

return nil
}

func findConfigs(directory string) (map[string]string, error) {
pathToVersion := make(map[string]string)

err := filepath.Walk(directory,
func(path string, info os.FileInfo, err error) error {
if err != nil {
fmt.Println(err)
return err
}

err := godirwalk.Walk(directory, &godirwalk.Options{
Callback: func(path string, info *godirwalk.Dirent) error {
// Find files ending in ".yaml" and parseable to skaffold config in the specified root directory recursively.
if !info.IsDir() && (strings.Contains(path, ".yaml") || strings.Contains(path, ".yml")) {
cfg, err := schema.ParseConfig(path, false)
if err == nil {
if !info.IsDir() && (strings.HasSuffix(path, ".yaml") || strings.HasSuffix(path, ".yml")) {
if cfg, err := schema.ParseConfig(path, false); err == nil {
pathToVersion[path] = cfg.GetVersion()
}
}
return nil
})
},
})

return pathToVersion, err
}
117 changes: 41 additions & 76 deletions cmd/skaffold/app/cmd/find_configs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,89 +25,54 @@ import (
"github.com/GoogleContainerTools/skaffold/testutil"
)

var (
invalidFileName = "invalid-skaffold.yaml"
validFileName = "valid-skaffold.yaml"
upgradeableFileName = "upgradeable-skaffold.yaml"
)

func TestFindConfigs(t *testing.T) {
testutil.Run(t, "", func(tt *testutil.T) {
latestVersion := latest.Version
upgradeableVersion := v1beta7.Version
tmpDir1, tmpDir2 := setUpTempFiles(tt, latestVersion, upgradeableVersion)

tests := []struct {
flagDir *testutil.TempDir
resultCounts int
shouldContainsMappings map[string]string
}{
{
flagDir: tmpDir1,
resultCounts: 2,
shouldContainsMappings: map[string]string{validFileName: latestVersion, upgradeableFileName: upgradeableVersion},
tests := []struct {
files map[string]string
expected map[string]string
}{
{
files: map[string]string{
"valid.yml": validYaml(latest.Version),
"upgradeable.yaml": validYaml(v1beta7.Version),
"invalid.yaml": invalidYaml(),
},
{
flagDir: tmpDir2,
resultCounts: 1,
shouldContainsMappings: map[string]string{validFileName: latestVersion},
expected: map[string]string{
"valid.yml": latest.Version,
"upgradeable.yaml": v1beta7.Version,
},
}
for _, test := range tests {
pathToVersion, err := findConfigs(test.flagDir.Root())

tt.CheckErrorAndDeepEqual(false, err, len(test.shouldContainsMappings), len(pathToVersion))
for f, v := range test.shouldContainsMappings {
version, ok := pathToVersion[test.flagDir.Path(f)]
tt.CheckDeepEqual(true, ok)
tt.CheckDeepEqual(version, v)
}
}
})
}
},
{
files: map[string]string{
"valid.yaml": validYaml(latest.Version),
"invalid.yaml": invalidYaml(),
},
expected: map[string]string{
"valid.yaml": latest.Version,
},
},
}
for _, test := range tests {
testutil.Run(t, "", func(t *testutil.T) {
tmpDir := t.NewTempDir().WriteFiles(test.files)

/*
This helper function will generate the following file tree for testing purpose
...
├── tmpDir1
│   ├── valid-skaffold.yaml
| ├── upgradeable-skaffold.yaml
│   └── invalid-skaffold.yaml
└── tmpDir2
├── valid-skaffold.yaml
└── invalid-skaffold.yaml
*/
func setUpTempFiles(t *testutil.T, latestVersion, upgradeableVersion string) (*testutil.TempDir, *testutil.TempDir) {
validYaml := fmt.Sprintf(`apiVersion: %s
kind: Config
build:
artifacts:
- image: docker/image
docker:
dockerfile: dockerfile.test
`, latestVersion)
pathToVersion, err := findConfigs(tmpDir.Root())

upgradeableYaml := fmt.Sprintf(`apiVersion: %s
kind: Config
build:
artifacts:
- image: docker/image
docker:
dockerfile: dockerfile.test
`, upgradeableVersion)
t.CheckNoError(err)
t.CheckDeepEqual(len(test.expected), len(pathToVersion))

invalidYaml := `This is invalid`
for f, v := range test.expected {
version := pathToVersion[tmpDir.Path(f)]

tmpDir1 := t.NewTempDir().WriteFiles(map[string]string{
invalidFileName: invalidYaml,
validFileName: validYaml,
upgradeableFileName: upgradeableYaml,
})
t.CheckDeepEqual(version, v)
}
})
}
}

tmpDir2 := t.NewTempDir().WriteFiles(map[string]string{
invalidFileName: invalidYaml,
validFileName: validYaml,
})
func validYaml(version string) string {
return fmt.Sprintf("apiVersion: %s\nkind: Config", version)
}

return tmpDir1, tmpDir2
func invalidYaml() string {
return "This is invalid"
}

0 comments on commit c3f9521

Please sign in to comment.