diff --git a/Dockerfile b/Dockerfile index 8f875476..af44e2d3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ RUN CGO_ENABLED=0 \ -ldflags="-w -s -extldflags '-static' -X github.com/Boeing/config-file-validator.version=$VALIDATOR_VERSION" \ -tags netgo \ -o validator \ - cmd/validator/validator.go + main.go FROM $BASE_IMAGE COPY --from=go-builder /build/validator / diff --git a/README.md b/README.md index 1fd0db24..34f3d36a 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,6 @@ Apache 2 License - - Awesome Go - - Go Reference @@ -31,9 +27,7 @@ ## Supported config files formats: * Apple PList XML * CSV -* ENV * HCL -* HOCON * INI * JSON * Properties @@ -97,28 +91,28 @@ go install github.com/Boeing/config-file-validator/cmd/validator@v1.6.0 ## Usage ``` -Usage: validator [OPTIONS] [...] - -positional arguments: - search_path: The search path on the filesystem for configuration files. Defaults to the current working directory if no search_path provided - -optional flags: - -depth int - Depth of recursion for the provided search paths. Set depth to 0 to disable recursive path traversal - -exclude-dirs string - Subdirectories to exclude when searching for configuration files - -exclude-file-types string - A comma separated list of file types to ignore - -groupby string - Group output by filetype, directory, pass-fail. Supported for Standard and JSON reports - -output string - Destination to a file to output results - -quiet - If quiet flag is set. It doesn't print any output to stdout. - -reporter string - Format of the printed report. Options are standard and json (default "standard") - -version - Version prints the release version of validator +Cross Platform tool to validate configuration files + +Usage: + validator [flags] + validator [command] + +Available Commands: + completion Generate the autocompletion script for the specified shell + help Help about any command + version Version prints the release version of validator + +Flags: + --depth int Depth of recursion for the provided search paths. Set depth to 0 to disable recursive path traversal. + --exclude-dirs string Subdirectories to exclude when searching for configuration files + --exclude-file-types string A comma separated list of file types to ignore + --groupby string Group output by filetype, directory, pass-fail. Supported for Standard and JSON reports + -h, --help help for validator + --output string Destination to a file to output results + --quiet If quiet flag is set. It doesn't print any output to stdout. + --reporter string Format of the printed report. Options are standard and json (default "standard") + +Use "validator [command] --help" for more information about a command. ``` ### Examples @@ -190,6 +184,7 @@ validator -groupby directory,pass-fail ![Groupby File Type and Pass/Fail](./img/gb-filetype-and-pass-fail.png) + ### Output results to a file Output report results to a file (default name is `result.{extension}`). Must provide reporter flag with a supported extension format. Available options are `junit` and `json`. If an existing directory is provided, create a file named default name in the given directory. If a file name is provided, create a file named the given name at the current working directory. @@ -224,7 +219,7 @@ go build \ -ldflags='-w -s -extldflags "-static"' \ -tags netgo \ -o validator \ -cmd/validator/validator.go +main.go ``` #### Install @@ -243,7 +238,7 @@ go build \ -ldflags='-w -s -extldflags "-static"' \ -tags netgo \ -o validator \ -cmd/validator/validator.go +main.go ``` #### Install @@ -262,7 +257,7 @@ go build \ -ldflags='-w -s -extldflags "-static"' \ -tags netgo \ -o validator.exe \ -cmd/validator/validator.go +main.go ``` #### Install diff --git a/cmd/validator/commands/flags.go b/cmd/validator/commands/flags.go new file mode 100644 index 00000000..24be4c58 --- /dev/null +++ b/cmd/validator/commands/flags.go @@ -0,0 +1,26 @@ +package cmd + +import ( + validator "github.com/Boeing/config-file-validator/cmd/validator" + "github.com/spf13/cobra" +) + +func CmdFlags(cmd *cobra.Command) { + cmd.PersistentFlags(). + IntVar(&validator.Flags.Depth, "depth", 0, "Depth of recursion for the provided search paths. Set depth to 0 to disable recursive path traversal.") + cmd.PersistentFlags(). + StringVar(&validator.Flags.ExcludeDirs, "exclude-dirs", "", "Subdirectories to exclude when searching for configuration files") + cmd.PersistentFlags(). + StringVar(&validator.Flags.ExcludeFileTypes, "exclude-file-types", "", "A comma separated list of file types to ignore") + cmd.PersistentFlags().StringVar(&validator.Flags.Output, "output", "", "Destination to a file to output results") + cmd.PersistentFlags(). + StringVar(&validator.Flags.ReportType, "reporter", "standard", "Format of the printed report. Options are standard and json") + cmd.PersistentFlags(). + StringVar(&validator.Flags.GroupOutput, "groupby", "", "Group output by filetype, directory, pass-fail. Supported for Standard and JSON reports") + cmd.PersistentFlags(). + BoolVar(&validator.Flags.Quiet, "quiet", false, "If quiet flag is set. It doesn't print any output to stdout.") +} + +func init() { + CmdFlags(rootCmd) +} diff --git a/cmd/validator/commands/flags_test.go b/cmd/validator/commands/flags_test.go new file mode 100644 index 00000000..5bca2b46 --- /dev/null +++ b/cmd/validator/commands/flags_test.go @@ -0,0 +1,73 @@ +package cmd + +import ( + "bytes" + "strings" + "testing" + + cmd "github.com/Boeing/config-file-validator/cmd/validator" + "github.com/spf13/cobra" +) + +func ExecuteTestHelper(t *testing.T, c *cobra.Command, args ...string) (string, error) { + t.Helper() + + buf := new(bytes.Buffer) + c.SetOut(buf) + c.SetErr(buf) + c.SetArgs(args) + + err := c.Execute() + return strings.TrimSpace(buf.String()), err +} + +func Test_flags(t *testing.T) { + // We manipulate the Args to set them up for the testcases + cases := []struct { + Name string + Args []string + ExpectedExit int + }{ + {"blank", []string{}, 0}, + {"negative depth set", []string{"--depth", "-1", "--reporter", "standard"}, 1}, + {"flags set, wrong reporter", []string{"--exclude-dirs", "subdir", "--reporter", "wrong"}, 1}, + {"flags set, json reporter", []string{"--exclude-dirs", "subdir", "--reporter", "json"}, 0}, + {"flags set, junit reported", []string{"--exclude-dirs", "subdir", "--reporter", "junit"}, 0}, + {"bad path", []string{"/path/does/not/exit"}, 1}, + {"exclude file types set", []string{"--exclude-file-types", "json"}, 0}, + {"multiple paths", []string{"../../../test/fixtures/subdir/good.json", "../../../test/fixtures/good.json"}, 0}, + {"output set", []string{"--output", "../../../test/output", "--reporter", "json"}, 0}, + + {"empty string output set", []string{"--output", "", "--reporter", "json", "."}, 0}, + {"wrong output set", []string{"--output", "/path/not/exist", "--reporter", "json", "."}, 1}, + {"incorrect group", []string{"--groupby", "badgroup"}, 1}, + {"correct group", []string{"--groupby", "directory"}, 0}, + {"grouped junit", []string{"--groupby", "directory", "--reporter", "junit", "."}, 1}, + {"groupby duplicate", []string{"--groupby", "directory,directory", "."}, 1}, + {"quiet flag", []string{"--quiet", "."}, 0}, + } + + var exitStatus int + + for _, tc := range cases { + root := &cobra.Command{ + Use: "root", + Run: func(c *cobra.Command, args []string) { + exitStatus = cmd.ExecRoot(c, args) + }, + } + CmdFlags(root) + + t.Run(tc.Name, func(t *testing.T) { + _, err := ExecuteTestHelper(t, root, tc.Args...) + if err != nil { + t.Error("ExecuteTestHelper: ", err) + } + + if tc.ExpectedExit != exitStatus { + t.Errorf("Wrong exit code, expected: %v, got: %v", tc.ExpectedExit, exitStatus) + } + }) + } + +} diff --git a/cmd/validator/commands/root.go b/cmd/validator/commands/root.go new file mode 100644 index 00000000..1089a4c0 --- /dev/null +++ b/cmd/validator/commands/root.go @@ -0,0 +1,26 @@ +package cmd + +import ( + "fmt" + "os" + + validator "github.com/Boeing/config-file-validator/cmd/validator" + "github.com/spf13/cobra" +) + +// rootCmd command configuration and setup +var rootCmd = &cobra.Command{ + Use: "validator", + Short: "Cross Platform tool to validate configuration files", + Args: cobra.ArbitraryArgs, + Run: func(cmd *cobra.Command, args []string) { + os.Exit(validator.ExecRoot(cmd, args)) + }, +} + +func Execute() { + if err := rootCmd.Execute(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/version.go b/cmd/validator/commands/version.go similarity index 53% rename from version.go rename to cmd/validator/commands/version.go index 56eaa212..8bf8db96 100644 --- a/version.go +++ b/cmd/validator/commands/version.go @@ -1,6 +1,10 @@ -package configfilevalidator +package cmd -import "fmt" +import ( + "fmt" + + "github.com/spf13/cobra" +) // Version information set by link flags during build. We fall back to these sane // default values when not provided @@ -18,9 +22,28 @@ func (v Version) String() string { return fmt.Sprintf("validator version %v", v.Version) } +// SetVersion set the version +func SetVersion(v string) { + version = v +} + // GetVersion returns the version information func GetVersion() Version { return Version{ Version: version, } } + +func init() { + rootCmd.AddCommand(versionCmd) +} + +// versionCmd command configuration and setup +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Version prints the release version of validator", + Long: ``, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println(GetVersion()) + }, +} diff --git a/cmd/validator/commands/version_test.go b/cmd/validator/commands/version_test.go new file mode 100644 index 00000000..ad8814a9 --- /dev/null +++ b/cmd/validator/commands/version_test.go @@ -0,0 +1,33 @@ +package cmd + +import ( + "testing" + + cmd "github.com/Boeing/config-file-validator/cmd/validator" + "github.com/spf13/cobra" +) + +func TestFlagVersion(t *testing.T) { + var exitStatus int + expectedExit := 0 + root := &cobra.Command{ + Use: "root", + Run: func(c *cobra.Command, args []string) { + exitStatus = cmd.ExecRoot(c, args) + }} + + SetVersion("testing") + root.AddCommand(versionCmd) + + args := []string{"version"} + + _, err := ExecuteTestHelper(t, root, args...) + if err != nil { + t.Error(err) + } + + if expectedExit != exitStatus { + t.Errorf("Wrong exit code, expected: %v, got: %v", expectedExit, exitStatus) + } + +} diff --git a/cmd/validator/validator.go b/cmd/validator/validator.go index 63fceebc..b0e671bf 100644 --- a/cmd/validator/validator.go +++ b/cmd/validator/validator.go @@ -5,64 +5,83 @@ validates them using the go package for each configuration type. Currently Apple PList XML, CSV, HCL, HOCON, INI, JSON, Properties, TOML, XML, and YAML. configuration file types are supported. -Usage: validator [OPTIONS] [...] - -positional arguments: - search_path: The search path on the filesystem for configuration files. Defaults to the current working directory if no search_path provided. Multiple search paths can be declared separated by a space. - -optional flags: - -depth int - Depth of recursion for the provided search paths. Set depth to 0 to disable recursive path traversal - -exclude-dirs string - Subdirectories to exclude when searching for configuration files - -exclude-file-types string - A comma separated list of file types to ignore - -output - Destination of a file to outputting results - -reporter string - Format of the printed report. Options are standard and json (default "standard") - -version - Version prints the release version of validator +Cross Platform tool to validate configuration files + +Usage: + validator [flags] + validator [command] + +Available Commands: + completion Generate the autocompletion script for the specified shell + help Help about any command + version Version prints the release version of validator + +Flags: + --depth int Depth of recursion for the provided search paths. Set depth to 0 to disable recursive path traversal. + --exclude-dirs string Subdirectories to exclude when searching for configuration files + --exclude-file-types string A comma separated list of file types to ignore + --groupby string Group output by filetype, directory, pass-fail. Supported for Standard and JSON reports + -h, --help help for validator + --output string Destination to a file to output results + --quiet If quiet flag is set. It doesn't print any output to stdout. + --reporter string Format of the printed report. Options are standard and json (default "standard") + +Use "validator [command] --help" for more information about a command. */ -package main +package cmd import ( "errors" - "flag" "fmt" "log" - "os" "slices" "strings" - configfilevalidator "github.com/Boeing/config-file-validator" "github.com/Boeing/config-file-validator/pkg/cli" "github.com/Boeing/config-file-validator/pkg/finder" "github.com/Boeing/config-file-validator/pkg/reporter" + "github.com/spf13/cobra" ) -type validatorConfig struct { - searchPaths []string - excludeDirs *string - excludeFileTypes *string - reportType *string - depth *int - versionQuery *bool - output *string - groupOutput *string - quiet *bool +// ValidatorConfig holds all flag possible to be setted +type ValidatorConfig struct { + SearchPaths []string + Depth int + ExcludeDirs string + ExcludeFileTypes string + Output string + ReportType string + GroupOutput string + Quiet bool } -// Custom Usage function to cover -func validatorUsage() { - fmt.Printf("Usage: validator [OPTIONS] [...]\n\n") - fmt.Printf("positional arguments:\n") - fmt.Printf( - " search_path: The search path on the filesystem for configuration files. " + - "Defaults to the current working directory if no search_path provided\n\n") - fmt.Printf("optional flags:\n") - flag.PrintDefaults() +var Flags ValidatorConfig + +// isFlagSet verifies if a given flag has been set or not +func isFlagSet(flagName string, cmd *cobra.Command) bool { + return cmd.Flags().Lookup(flagName).Changed +} + +// CleanString takes a command string and a split string +// and returns a cleaned string +func CleanString(str string) string { + str = strings.ToLower(str) + str = strings.TrimSpace(str) + return str +} + +// Return the reporter associated with the +// reportType string +func getReporter(reportType, outputDest string) reporter.Reporter { + switch reportType { + case "junit": + return reporter.NewJunitReporter(outputDest) + case "json": + return reporter.NewJSONReporter(outputDest) + default: + return reporter.StdoutReporter{} + } } // Parses, validates, and returns the flags @@ -70,157 +89,116 @@ func validatorUsage() { // If a required parameter is missing the help // output will be displayed and the function // will return with exit = 1 -func getFlags() (validatorConfig, error) { - flag.Usage = validatorUsage - depthPtr := flag.Int("depth", 0, "Depth of recursion for the provided search paths. Set depth to 0 to disable recursive path traversal") - excludeDirsPtr := flag.String("exclude-dirs", "", "Subdirectories to exclude when searching for configuration files") - excludeFileTypesPtr := flag.String("exclude-file-types", "", "A comma separated list of file types to ignore") - outputPtr := flag.String("output", "", "Destination to a file to output results") - reportTypePtr := flag.String("reporter", "standard", "Format of the printed report. Options are standard and json") - versionPtr := flag.Bool("version", false, "Version prints the release version of validator") - groupOutputPtr := flag.String("groupby", "", "Group output by filetype, directory, pass-fail. Supported for Standard and JSON reports") - quietPrt := flag.Bool("quiet", false, "If quiet flag is set. It doesn't print any output to stdout.") - flag.Parse() +func getFlags(cmd *cobra.Command, args []string) (ValidatorConfig, error) { + depth := Flags.Depth + excludeDirs := Flags.ExcludeDirs + excludeFileTypes := Flags.ExcludeFileTypes + output := Flags.Output + reportType := Flags.ReportType + groupby := Flags.GroupOutput + quiet := Flags.Quiet searchPaths := make([]string, 0) - // If search path arg is empty, set it to the cwd - // if not, set it to the arg. Supports n number of + // If search path arg is empty, default is cwd (".") + // if not, set it to the arg. Supports N number of // paths - if flag.NArg() == 0 { + if len(args) == 0 { searchPaths = append(searchPaths, ".") } else { - searchPaths = append(searchPaths, flag.Args()...) + searchPaths = append(searchPaths, args...) } - if *reportTypePtr != "standard" && *reportTypePtr != "json" && *reportTypePtr != "junit" { + if reportType != "standard" && reportType != "json" && reportType != "junit" { fmt.Println("Wrong parameter value for reporter, only supports standard, json or junit") - flag.Usage() - return validatorConfig{}, errors.New("Wrong parameter value for reporter, only supports standard, json or junit") + _ = cmd.Usage() + return ValidatorConfig{}, errors.New("Wrong parameter value for reporter, only supports standard, json or junit") } - if *reportTypePtr == "junit" && *groupOutputPtr != "" { + if reportType == "junit" && groupby != "" { fmt.Println("Wrong parameter value for reporter, groupby is not supported for JUnit reports") - flag.Usage() - return validatorConfig{}, errors.New("Wrong parameter value for reporter, groupby is not supported for JUnit reports") + _ = cmd.Usage() + return ValidatorConfig{}, errors.New("Wrong parameter value for reporter, groupby is not supported for JUnit reports") } - if depthPtr != nil && isFlagSet("depth") && *depthPtr < 0 { + if isFlagSet("depth", cmd) && depth < 0 { fmt.Println("Wrong parameter value for depth, value cannot be negative.") - flag.Usage() - return validatorConfig{}, errors.New("Wrong parameter value for depth, value cannot be negative") + _ = cmd.Usage() + return ValidatorConfig{}, errors.New("Wrong parameter value for depth, value cannot be negative") } - groupByCleanString := cleanString("groupby") - groupByUserInput := strings.Split(groupByCleanString, ",") - groupByAllowedValues := []string{"filetype", "directory", "pass-fail"} - seenValues := make(map[string]bool) + if groupby != "" { + groupByCleanString := CleanString(groupby) + groupByUserInput := strings.Split(groupByCleanString, ",") + groupByAllowedValues := []string{"filetype", "directory", "pass-fail"} + seenValues := make(map[string]bool) - // Check that the groupby values are valid and not duplicates - if groupOutputPtr != nil && isFlagSet("groupby") { + // Check that the groupby values are valid and not duplicates for _, groupBy := range groupByUserInput { if !slices.Contains(groupByAllowedValues, groupBy) { fmt.Println("Wrong parameter value for groupby, only supports filetype, directory, pass-fail") - flag.Usage() - return validatorConfig{}, errors.New("Wrong parameter value for groupby, only supports filetype, directory, pass-fail") + _ = cmd.Usage() + return ValidatorConfig{}, errors.New( + "Wrong parameter value for groupby, only supports filetype, directory, pass-fail", + ) } if _, ok := seenValues[groupBy]; ok { fmt.Println("Wrong parameter value for groupby, duplicate values are not allowed") - flag.Usage() - return validatorConfig{}, errors.New("Wrong parameter value for groupby, duplicate values are not allowed") + _ = cmd.Usage() + return ValidatorConfig{}, errors.New("Wrong parameter value for groupby, duplicate values are not allowed") } seenValues[groupBy] = true } } - config := validatorConfig{ - searchPaths, - excludeDirsPtr, - excludeFileTypesPtr, - reportTypePtr, - depthPtr, - versionPtr, - outputPtr, - groupOutputPtr, - quietPrt, + config := ValidatorConfig{ + SearchPaths: searchPaths, + ExcludeDirs: excludeDirs, + ExcludeFileTypes: excludeFileTypes, + ReportType: reportType, + Depth: depth, + Output: output, + GroupOutput: groupby, + Quiet: quiet, } return config, nil } -// isFlagSet verifies if a given flag has been set or not -func isFlagSet(flagName string) bool { - var isSet bool - - flag.Visit(func(f *flag.Flag) { - if f.Name == flagName { - isSet = true - } - }) - - return isSet -} - -// Return the reporter associated with the -// reportType string -func getReporter(reportType, outputDest *string) reporter.Reporter { - switch *reportType { - case "junit": - return reporter.NewJunitReporter(*outputDest) - case "json": - return reporter.NewJSONReporter(*outputDest) - default: - return reporter.StdoutReporter{} - } -} - -// cleanString takes a command string and a split string -// and returns a cleaned string -func cleanString(command string) string { - cleanedString := flag.Lookup(command).Value.String() - cleanedString = strings.ToLower(cleanedString) - cleanedString = strings.TrimSpace(cleanedString) - - return cleanedString -} - -func mainInit() int { - validatorConfig, err := getFlags() +// ExecRoot control all the flow of the program and call cli.Run() that process everything. +func ExecRoot(cmd *cobra.Command, args []string) int { + validatorConfig, err := getFlags(cmd, args) if err != nil { return 1 } - if *validatorConfig.versionQuery { - fmt.Println(configfilevalidator.GetVersion()) - return 0 - } - // since the exclude dirs are a comma separated string // it needs to be split into a slice of strings - excludeDirs := strings.Split(*validatorConfig.excludeDirs, ",") - choosenReporter := getReporter(validatorConfig.reportType, validatorConfig.output) - excludeFileTypes := strings.Split(*validatorConfig.excludeFileTypes, ",") - groupOutput := strings.Split(*validatorConfig.groupOutput, ",") + excludeDirs := strings.Split(validatorConfig.ExcludeDirs, ",") + excludeFileTypes := strings.Split(validatorConfig.ExcludeFileTypes, ",") + fsOpts := []finder.FSFinderOptions{ - finder.WithPathRoots(validatorConfig.searchPaths...), + finder.WithPathRoots(validatorConfig.SearchPaths...), finder.WithExcludeDirs(excludeDirs), finder.WithExcludeFileTypes(excludeFileTypes), } - quiet := *validatorConfig.quiet - if validatorConfig.depth != nil && isFlagSet("depth") { - fsOpts = append(fsOpts, finder.WithDepth(*validatorConfig.depth)) + if isFlagSet("depth", cmd) { + fsOpts = append(fsOpts, finder.WithDepth(validatorConfig.Depth)) } // Initialize a file system finder fileSystemFinder := finder.FileSystemFinderInit(fsOpts...) + choosenReporter := getReporter(validatorConfig.ReportType, validatorConfig.Output) + groupby := strings.Split(validatorConfig.GroupOutput, ",") + // Initialize the CLI c := cli.Init( cli.WithReporter(choosenReporter), cli.WithFinder(fileSystemFinder), - cli.WithGroupOutput(groupOutput), - cli.WithQuiet(quiet), + cli.WithGroupOutput(groupby), + cli.WithQuiet(validatorConfig.Quiet), ) // Run the config file validation @@ -231,7 +209,3 @@ func mainInit() int { return exitStatus } - -func main() { - os.Exit(mainInit()) -} diff --git a/cmd/validator/validator_test.go b/cmd/validator/validator_test.go deleted file mode 100644 index bcd9c03b..00000000 --- a/cmd/validator/validator_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - "testing" -) - -func Test_flags(t *testing.T) { - // We manipuate the Args to set them up for the testcases - // After this test we restore the initial args - oldArgs := os.Args - defer func() { os.Args = oldArgs }() - cases := []struct { - Name string - Args []string - ExpectedExit int - }{ - {"blank", []string{}, 0}, - {"negative depth set", []string{"-depth=-1", "."}, 1}, - {"depth set", []string{"-depth=1", "."}, 0}, - {"flags set, wrong reporter", []string{"--exclude-dirs=subdir", "--reporter=wrong", "."}, 1}, - {"flags set, json reporter", []string{"--exclude-dirs=subdir", "--reporter=json", "."}, 0}, - {"flags set, junit reported", []string{"--exclude-dirs=subdir", "--reporter=junit", "."}, 0}, - {"bad path", []string{"/path/does/not/exit"}, 1}, - {"exclude file types set", []string{"--exclude-file-types=json", "."}, 0}, - {"multiple paths", []string{"../../test/fixtures/subdir/good.json", "../../test/fixtures/good.json"}, 0}, - {"version", []string{"--version"}, 0}, - {"output set", []string{"--output=../../test/output", "--reporter=json", "."}, 0}, - {"empty string output set", []string{"--output", "", "--reporter", "json", "."}, 0}, - {"wrong output set", []string{"--output", "/path/not/exist", "--reporter", "json", "."}, 1}, - {"incorrect group", []string{"-groupby=badgroup", "."}, 1}, - {"correct group", []string{"-groupby=directory", "."}, 0}, - {"grouped junit", []string{"-groupby=directory", "--reporter=junit", "."}, 1}, - {"groupby duplicate", []string{"--groupby=directory,directory", "."}, 1}, - {"quiet flag", []string{"--quiet=true", "."}, 0}, - } - for _, tc := range cases { - // this call is required because otherwise flags panics, - // if args are set between flag.Parse call - fmt.Printf("Testing args: %v = %v\n", tc.Name, tc.Args) - flag.CommandLine = flag.NewFlagSet(tc.Name, flag.ExitOnError) - // we need a value to set Args[0] to cause flag begins parsing at Args[1] - os.Args = append([]string{tc.Name}, tc.Args...) - actualExit := mainInit() - if tc.ExpectedExit != actualExit { - t.Errorf("Wrong exit code, expected: %v, got: %v", tc.ExpectedExit, actualExit) - } - } -} diff --git a/go.mod b/go.mod index 1a90e610..d59d0d44 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,11 @@ go 1.21 require ( github.com/fatih/color v1.13.0 github.com/gurkankaymak/hocon v1.2.18 + github.com/hashicorp/go-envparse v0.1.0 github.com/hashicorp/hcl/v2 v2.18.1 github.com/magiconair/properties v1.8.7 github.com/pelletier/go-toml/v2 v2.0.6 + github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.1 gopkg.in/ini.v1 v1.67.0 gopkg.in/yaml.v3 v3.0.1 @@ -20,13 +22,13 @@ require ( github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/google/go-cmp v0.5.8 // indirect - github.com/hashicorp/go-envparse v0.1.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/mattn/go-colorable v0.1.9 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect github.com/zclconf/go-cty v1.13.0 // indirect - golang.org/x/sync v0.2.0 // indirect golang.org/x/sys v0.12.0 // indirect golang.org/x/text v0.11.0 // indirect ) diff --git a/go.sum b/go.sum index 5984a6d1..37b06d7a 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,7 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6 github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -19,6 +20,8 @@ github.com/hashicorp/go-envparse v0.1.0 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdm github.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc= github.com/hashicorp/hcl/v2 v2.18.1 h1:6nxnOJFku1EuSawSD81fuviYUV8DxFr3fp2dUi3ZYSo= github.com/hashicorp/hcl/v2 v2.18.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -39,6 +42,11 @@ github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvI github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -48,8 +56,6 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/zclconf/go-cty v1.13.0 h1:It5dfKTTZHe9aeppbNOda3mN7Ag7sg6QkBNm6TkyFa0= github.com/zclconf/go-cty v1.13.0/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/img/gb-filetype-and-pass-fail.png b/img/gb-filetype-and-pass-fail.png deleted file mode 100644 index 3a30c2ae..00000000 Binary files a/img/gb-filetype-and-pass-fail.png and /dev/null differ diff --git a/img/gb-filetype.png b/img/gb-filetype.png deleted file mode 100644 index a89f93eb..00000000 Binary files a/img/gb-filetype.png and /dev/null differ diff --git a/index.md b/index.md index b1be0fe1..6453599d 100644 --- a/index.md +++ b/index.md @@ -111,28 +111,28 @@ go install github.com/Boeing/config-file-validator/cmd/validator@v1.6.0 ## Usage ``` -Usage: validator [OPTIONS] [...] - -positional arguments: - search_path: The search path on the filesystem for configuration files. Defaults to the current working directory if no search_path provided - -optional flags: - -depth int - Depth of recursion for the provided search paths. Set depth to 0 to disable recursive path traversal - -exclude-dirs string - Subdirectories to exclude when searching for configuration files - -exclude-file-types string - A comma separated list of file types to ignore - -groupby string - Group output by filetype, directory, pass-fail. Supported for Standard and JSON reports - -output string - Destination to a file to output results - -quiet - If quiet flag is set. It doesn't print any output to stdout. - -reporter string - Format of the printed report. Options are standard and json (default "standard") - -version - Version prints the release version of validator +Cross Platform tool to validate configuration files + +Usage: + validator [flags] + validator [command] + +Available Commands: + completion Generate the autocompletion script for the specified shell + help Help about any command + version Version prints the release version of validator + +Flags: + --depth int Depth of recursion for the provided search paths. Set depth to 0 to disable recursive path traversal. + --exclude-dirs string Subdirectories to exclude when searching for configuration files + --exclude-file-types string A comma separated list of file types to ignore + --groupby string Group output by filetype, directory, pass-fail. Supported for Standard and JSON reports + -h, --help help for validator + --output string Destination to a file to output results + --quiet If quiet flag is set. It doesn't print any output to stdout. + --reporter string Format of the printed report. Options are standard and json (default "standard") + +Use "validator [command] --help" for more information about a command. ``` ### Examples diff --git a/main.go b/main.go new file mode 100644 index 00000000..1a357b11 --- /dev/null +++ b/main.go @@ -0,0 +1,7 @@ +package main + +import cmd "github.com/Boeing/config-file-validator/cmd/validator/commands" + +func main() { + cmd.Execute() +} diff --git a/pkg/finder/finder_test.go b/pkg/finder/finder_test.go index 4b5b8242..6e1fd206 100644 --- a/pkg/finder/finder_test.go +++ b/pkg/finder/finder_test.go @@ -204,7 +204,7 @@ func Test_FileSystemFinderAbsPath(t *testing.T) { } } -func Test_FileSystemFinderUpperCaseExtension(t *testing.T) { +func Test_FileSystemFinderUpperCaseExtention(t *testing.T) { fsFinder := FileSystemFinderInit( WithPathRoots("../../test/fixtures/uppercase-extension"), ) @@ -220,7 +220,7 @@ func Test_FileSystemFinderUpperCaseExtension(t *testing.T) { } } -func Test_FileSystemFinderMixedCaseExtension(t *testing.T) { +func Test_FileSystemFinderMixedCaseExtention(t *testing.T) { fsFinder := FileSystemFinderInit( WithPathRoots("../../test/fixtures/mixedcase-extension"), ) diff --git a/pkg/validator/validator_test.go b/pkg/validator/validator_test.go index ac07aca4..f90a9e45 100644 --- a/pkg/validator/validator_test.go +++ b/pkg/validator/validator_test.go @@ -64,8 +64,6 @@ var testData = []struct { {"invalidPlist", invalidPlistBytes, false, PlistValidator{}}, {"validHocon", []byte(`test = [1, 2, 3]`), true, HoconValidator{}}, {"invalidHocon", []byte(`test = [1, 2,, 3]`), false, HoconValidator{}}, - {"validEnv", []byte("KEY=VALUE"), true, EnvValidator{}}, - {"invalidEnv", []byte("=TEST"), false, EnvValidator{}}, } func Test_ValidationInput(t *testing.T) { diff --git a/test/fixtures/good.env b/test/fixtures/good.env deleted file mode 100644 index 4655ae15..00000000 --- a/test/fixtures/good.env +++ /dev/null @@ -1 +0,0 @@ -TEST=True diff --git a/test/fixtures/subdir2/bad.env b/test/fixtures/subdir2/bad.env deleted file mode 100644 index 6c00b663..00000000 --- a/test/fixtures/subdir2/bad.env +++ /dev/null @@ -1,2 +0,0 @@ -TEST=True -DEMO="\a"