From fb451a150c723d5ba107517fda0be2903aab6219 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Sun, 19 Nov 2023 12:58:27 -0800 Subject: [PATCH 01/48] Add GroupBy command Add -groupby command to group output by file type, pass/fail, and directory --- README.md | 11 +++-- cmd/validator/validator.go | 5 +++ pkg/cli/cli.go | 92 +++++++++++++++++++++++++++++++++++++- pkg/finder/fsfinder.go | 1 - 4 files changed, 103 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 033fc040..d5bedaa2 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ There are several ways to install the config file validator tool We offer alpine, ubuntu, and scratch containers -#### Apline +#### Apline ``` docker pull ghcr.io/boeing/config-file-validator:v1.5.0 @@ -107,6 +107,9 @@ optional flags: Format of the printed report. Options are standard and json (default "standard") -version Version prints the release version of validator + -groupby string + Group the output by file type, pass/fail, or directory + ``` ### Examples @@ -130,7 +133,7 @@ validator /path/to/search /another/path/to/search Exclude subdirectories in the search path ``` -validator --exclude-dirs=/path/to/search/tests /path/to/search +validator --exclude-dirs=/path/to/search/tests /path/to/search ``` ![Exclude Dirs Run](./img/exclude_dirs.png) @@ -145,7 +148,7 @@ validator --exclude-file-types=json /path/to/search ![Exclude File Types Run](./img/exclude_file_types.png) #### Customize recursion depth -By default there is no recursion limit. If desired, the recursion depth can be set to an integer value. If depth is set to `0` recursion will be disabled and only the files in the search path will be validated. +By default there is no recursion limit. If desired, the recursion depth can be set to an integer value. If depth is set to `0` recursion will be disabled and only the files in the search path will be validated. ``` validator --depth=0 /path/to/search @@ -242,4 +245,4 @@ docker build . -t config-file-validator:v1.5.0 We welcome contributions! Please refer to our [contributing guide](/CONTRIBUTING.md) ## License -The Config File Validator is released under the [Apache 2.0](/LICENSE) License \ No newline at end of file +The Config File Validator is released under the [Apache 2.0](/LICENSE) License diff --git a/cmd/validator/validator.go b/cmd/validator/validator.go index 63fcffdb..12e7a91e 100644 --- a/cmd/validator/validator.go +++ b/cmd/validator/validator.go @@ -46,6 +46,7 @@ type validatorConfig struct { reportType *string depth *int versionQuery *bool + groupOutput *string } // Custom Usage function to cover @@ -71,6 +72,7 @@ func getFlags() (validatorConfig, error) { excludeFileTypesPtr := flag.String("exclude-file-types", "", "A comma separated list of file types to ignore") depthPtr := flag.Int("depth", 0, "Depth of recursion for the provided search paths. Set depth to 0 to disable recursive path traversal") versionPtr := flag.Bool("version", false, "Version prints the release version of validator") + groupOutputPtr := flag.String("groupby", "", "Group output by file type, directory, pass/fail, or none ") flag.Parse() searchPaths := make([]string, 0) @@ -103,6 +105,7 @@ func getFlags() (validatorConfig, error) { reportTypePtr, depthPtr, versionPtr, + groupOutputPtr, } return config, nil @@ -148,6 +151,7 @@ func mainInit() int { excludeDirs := strings.Split(*validatorConfig.excludeDirs, ",") reporter := getReporter(validatorConfig.reportType) excludeFileTypes := strings.Split(*validatorConfig.excludeFileTypes, ",") + groupOutput := *validatorConfig.groupOutput fsOpts := []finder.FSFinderOptions{finder.WithPathRoots(validatorConfig.searchPaths...), finder.WithExcludeDirs(excludeDirs), @@ -164,6 +168,7 @@ func mainInit() int { cli := cli.Init( cli.WithReporter(reporter), cli.WithFinder(fileSystemFinder), + cli.WithGroupOutput(groupOutput), ) // Run the config file validation diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index 8a2bc934..d1870771 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -3,11 +3,14 @@ package cli import ( "fmt" "os" + "strings" "github.com/Boeing/config-file-validator/pkg/finder" "github.com/Boeing/config-file-validator/pkg/reporter" ) +var GroupOutput string + type CLI struct { // FileFinder interface to search for the files // in the SearchPath @@ -36,6 +39,12 @@ func WithReporter(reporter reporter.Reporter) CLIOption { } } +func WithGroupOutput(groupOutput string) CLIOption { + return func(c *CLI) { + GroupOutput = groupOutput + } +} + // Initialize the CLI object func Init(opts ...CLIOption) *CLI { defaultFsFinder := finder.FileSystemFinderInit() @@ -88,7 +97,19 @@ func (c CLI) Run() (int, error) { reports = append(reports, report) } - c.Reporter.Print(reports) + switch { + case GroupOutput == "filetype": + reports = GroupByFile(reports) + c.Reporter.Print(reports) + case GroupOutput == "pass/fail": + reports = GroupByPassFail(reports) + c.Reporter.Print(reports) + case GroupOutput == "directory": + reports = GroupByDirectory(reports) + c.Reporter.Print(reports) + default: + c.Reporter.Print(reports) + } if errorFound { return 1, nil @@ -96,3 +117,72 @@ func (c CLI) Run() (int, error) { return 0, nil } } + +// Group Files by File Type +func GroupByFile(reports []reporter.Report) []reporter.Report { + + mapFiles := make(map[string][]reporter.Report) + reportByFile := []reporter.Report{} + + for _, report := range reports { + fileType := strings.Split(report.FileName, ".")[1] + if mapFiles[fileType] == nil { + mapFiles[fileType] = []reporter.Report{report} + } else { + mapFiles[fileType] = append(mapFiles[fileType], report) + } + } + + for _, reports := range mapFiles { + reportByFile = append(reportByFile, reports...) + } + + return reportByFile +} + +func GroupByPassFail(reports []reporter.Report) []reporter.Report { + mapFiles := make(map[string][]reporter.Report) + reportByPassOrFail := []reporter.Report{} + + for _, report := range reports { + if report.IsValid { + if mapFiles["pass"] == nil { + mapFiles["pass"] = []reporter.Report{report} + } else { + mapFiles["pass"] = append(mapFiles["pass"], report) + } + } else { + if mapFiles["fail"] == nil { + mapFiles["fail"] = []reporter.Report{report} + } else { + mapFiles["fail"] = append(mapFiles["fail"], report) + } + } + } + + for _, reports := range mapFiles { + reportByPassOrFail = append(reportByPassOrFail, reports...) + } + + return reportByPassOrFail +} + +func GroupByDirectory(reports []reporter.Report) []reporter.Report { + mapFiles := make(map[string][]reporter.Report) + reportByDirectory := []reporter.Report{} + + for _, report := range reports { + directory := strings.Split(report.FilePath, "/")[1] + if mapFiles[directory] == nil { + mapFiles[directory] = []reporter.Report{report} + } else { + mapFiles[directory] = append(mapFiles[directory], report) + } + } + + for _, reports := range mapFiles { + reportByDirectory = append(reportByDirectory, reports...) + } + + return reportByDirectory +} diff --git a/pkg/finder/fsfinder.go b/pkg/finder/fsfinder.go index 11b5f029..b5185ced 100644 --- a/pkg/finder/fsfinder.go +++ b/pkg/finder/fsfinder.go @@ -55,7 +55,6 @@ func WithDepth(depthVal int) FSFinderOptions { fsf.Depth = &depthVal } } - func FileSystemFinderInit(opts ...FSFinderOptions) *FileSystemFinder { var defaultExludeDirs []string defaultPathRoots := []string{"."} From fdb4d5ff245f8f30801a280eccb5c42dd8589a82 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Sun, 19 Nov 2023 14:39:56 -0800 Subject: [PATCH 02/48] Add multiple groupby commands and validation Add: Validation for the groupby command and return error if value passed is not a valid command Add: Allow for multiple values for the groupby command --- cmd/validator/validator.go | 34 ++++++++++++-- pkg/cli/cli.go | 96 ++++++-------------------------------- pkg/cli/groupoutput.go | 77 ++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 88 deletions(-) create mode 100644 pkg/cli/groupoutput.go diff --git a/cmd/validator/validator.go b/cmd/validator/validator.go index 12e7a91e..7f47639c 100644 --- a/cmd/validator/validator.go +++ b/cmd/validator/validator.go @@ -31,6 +31,7 @@ import ( "fmt" "log" "os" + "slices" "strings" configfilevalidator "github.com/Boeing/config-file-validator" @@ -46,7 +47,7 @@ type validatorConfig struct { reportType *string depth *int versionQuery *bool - groupOutput *string + groupOutput *string } // Custom Usage function to cover @@ -72,11 +73,24 @@ func getFlags() (validatorConfig, error) { excludeFileTypesPtr := flag.String("exclude-file-types", "", "A comma separated list of file types to ignore") depthPtr := flag.Int("depth", 0, "Depth of recursion for the provided search paths. Set depth to 0 to disable recursive path traversal") versionPtr := flag.Bool("version", false, "Version prints the release version of validator") - groupOutputPtr := flag.String("groupby", "", "Group output by file type, directory, pass/fail, or none ") + groupOutputPtr := flag.String("groupby", "", "Group output by file type, directory, pass/fail") flag.Parse() searchPaths := make([]string, 0) + // groupByOptions is a slice of strings that contains the valid options for the groupby flag + groupByOptions := []string{"filetype", "directory", "pass/fail"} + + // groupByPassed is a string that contains the value passed to the groupby flag + // We need to convert it to lowercase and remove any whitespace to give users more flexibility + groupByPassed := flag.Lookup("groupby").Value.String() + groupByPassed = strings.ToLower(groupByPassed) + groupByPassed = strings.TrimSpace(groupByPassed) + + // groupByStrings is a slice of strings that contains the groupby options passed to the flag + // This will be used to validate that the options the user passed are valid + groupByStrings := strings.Split(groupByPassed, ",") + // If search path arg is empty, set it to the cwd // if not, set it to the arg. Supports n number of // paths @@ -98,6 +112,16 @@ func getFlags() (validatorConfig, error) { return validatorConfig{}, errors.New("Wrong parameter value for depth, value cannot be negative") } + if groupOutputPtr != nil && isFlagSet("groupby") { + for _, groupBy := range groupByStrings { + if !slices.Contains(groupByOptions, 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, or none") + } + } + } + config := validatorConfig{ searchPaths, excludeDirsPtr, @@ -105,7 +129,7 @@ func getFlags() (validatorConfig, error) { reportTypePtr, depthPtr, versionPtr, - groupOutputPtr, + groupOutputPtr, } return config, nil @@ -151,7 +175,7 @@ func mainInit() int { excludeDirs := strings.Split(*validatorConfig.excludeDirs, ",") reporter := getReporter(validatorConfig.reportType) excludeFileTypes := strings.Split(*validatorConfig.excludeFileTypes, ",") - groupOutput := *validatorConfig.groupOutput + groupOutput := strings.Split(*validatorConfig.groupOutput, ",") fsOpts := []finder.FSFinderOptions{finder.WithPathRoots(validatorConfig.searchPaths...), finder.WithExcludeDirs(excludeDirs), @@ -168,7 +192,7 @@ func mainInit() int { cli := cli.Init( cli.WithReporter(reporter), cli.WithFinder(fileSystemFinder), - cli.WithGroupOutput(groupOutput), + cli.WithGroupOutput(groupOutput), ) // Run the config file validation diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index d1870771..e491269f 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -3,13 +3,12 @@ package cli import ( "fmt" "os" - "strings" "github.com/Boeing/config-file-validator/pkg/finder" "github.com/Boeing/config-file-validator/pkg/reporter" ) -var GroupOutput string +var GroupOutput []string type CLI struct { // FileFinder interface to search for the files @@ -39,7 +38,7 @@ func WithReporter(reporter reporter.Reporter) CLIOption { } } -func WithGroupOutput(groupOutput string) CLIOption { +func WithGroupOutput(groupOutput []string) CLIOption { return func(c *CLI) { GroupOutput = groupOutput } @@ -97,17 +96,17 @@ func (c CLI) Run() (int, error) { reports = append(reports, report) } - switch { - case GroupOutput == "filetype": - reports = GroupByFile(reports) - c.Reporter.Print(reports) - case GroupOutput == "pass/fail": - reports = GroupByPassFail(reports) - c.Reporter.Print(reports) - case GroupOutput == "directory": - reports = GroupByDirectory(reports) - c.Reporter.Print(reports) - default: + if len(GroupOutput) > 0 { + for _, group := range GroupOutput { + switch group { + case "filetype": + reports = GroupByFile(reports) + case "pass/fail": + reports = GroupByPassFail(reports) + case "directory": + reports = GroupByDirectory(reports) + } + } c.Reporter.Print(reports) } @@ -117,72 +116,3 @@ func (c CLI) Run() (int, error) { return 0, nil } } - -// Group Files by File Type -func GroupByFile(reports []reporter.Report) []reporter.Report { - - mapFiles := make(map[string][]reporter.Report) - reportByFile := []reporter.Report{} - - for _, report := range reports { - fileType := strings.Split(report.FileName, ".")[1] - if mapFiles[fileType] == nil { - mapFiles[fileType] = []reporter.Report{report} - } else { - mapFiles[fileType] = append(mapFiles[fileType], report) - } - } - - for _, reports := range mapFiles { - reportByFile = append(reportByFile, reports...) - } - - return reportByFile -} - -func GroupByPassFail(reports []reporter.Report) []reporter.Report { - mapFiles := make(map[string][]reporter.Report) - reportByPassOrFail := []reporter.Report{} - - for _, report := range reports { - if report.IsValid { - if mapFiles["pass"] == nil { - mapFiles["pass"] = []reporter.Report{report} - } else { - mapFiles["pass"] = append(mapFiles["pass"], report) - } - } else { - if mapFiles["fail"] == nil { - mapFiles["fail"] = []reporter.Report{report} - } else { - mapFiles["fail"] = append(mapFiles["fail"], report) - } - } - } - - for _, reports := range mapFiles { - reportByPassOrFail = append(reportByPassOrFail, reports...) - } - - return reportByPassOrFail -} - -func GroupByDirectory(reports []reporter.Report) []reporter.Report { - mapFiles := make(map[string][]reporter.Report) - reportByDirectory := []reporter.Report{} - - for _, report := range reports { - directory := strings.Split(report.FilePath, "/")[1] - if mapFiles[directory] == nil { - mapFiles[directory] = []reporter.Report{report} - } else { - mapFiles[directory] = append(mapFiles[directory], report) - } - } - - for _, reports := range mapFiles { - reportByDirectory = append(reportByDirectory, reports...) - } - - return reportByDirectory -} diff --git a/pkg/cli/groupoutput.go b/pkg/cli/groupoutput.go new file mode 100644 index 00000000..b4b54568 --- /dev/null +++ b/pkg/cli/groupoutput.go @@ -0,0 +1,77 @@ +package cli + +import ( + "strings" + + "github.com/Boeing/config-file-validator/pkg/reporter" +) + +// Group Files by File Type +func GroupByFile(reports []reporter.Report) []reporter.Report { + mapFiles := make(map[string][]reporter.Report) + reportByFile := []reporter.Report{} + + for _, report := range reports { + fileType := strings.Split(report.FileName, ".")[1] + if mapFiles[fileType] == nil { + mapFiles[fileType] = []reporter.Report{report} + } else { + mapFiles[fileType] = append(mapFiles[fileType], report) + } + } + + for _, reports := range mapFiles { + reportByFile = append(reportByFile, reports...) + } + + return reportByFile +} + +// Group Files by Pass/Fail +func GroupByPassFail(reports []reporter.Report) []reporter.Report { + mapFiles := make(map[string][]reporter.Report) + reportByPassOrFail := []reporter.Report{} + + for _, report := range reports { + if report.IsValid { + if mapFiles["pass"] == nil { + mapFiles["pass"] = []reporter.Report{report} + } else { + mapFiles["pass"] = append(mapFiles["pass"], report) + } + } else { + if mapFiles["fail"] == nil { + mapFiles["fail"] = []reporter.Report{report} + } else { + mapFiles["fail"] = append(mapFiles["fail"], report) + } + } + } + + for _, reports := range mapFiles { + reportByPassOrFail = append(reportByPassOrFail, reports...) + } + + return reportByPassOrFail +} + +// Group Files by Directory +func GroupByDirectory(reports []reporter.Report) []reporter.Report { + mapFiles := make(map[string][]reporter.Report) + reportByDirectory := []reporter.Report{} + + for _, report := range reports { + directory := strings.Split(report.FilePath, "/")[1] + if mapFiles[directory] == nil { + mapFiles[directory] = []reporter.Report{report} + } else { + mapFiles[directory] = append(mapFiles[directory], report) + } + } + + for _, reports := range mapFiles { + reportByDirectory = append(reportByDirectory, reports...) + } + + return reportByDirectory +} From 4e048fdf8417838b583842fc64d129a9ceee0c42 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Sun, 19 Nov 2023 14:57:21 -0800 Subject: [PATCH 03/48] Add Tests Add: Added tests for cli_test.go and validator_test.go --- cmd/validator/validator.go | 3 +++ cmd/validator/validator_test.go | 2 ++ pkg/cli/cli_test.go | 27 +++++++++++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/cmd/validator/validator.go b/cmd/validator/validator.go index 7f47639c..fc9c17a6 100644 --- a/cmd/validator/validator.go +++ b/cmd/validator/validator.go @@ -175,6 +175,9 @@ func mainInit() int { excludeDirs := strings.Split(*validatorConfig.excludeDirs, ",") reporter := getReporter(validatorConfig.reportType) excludeFileTypes := strings.Split(*validatorConfig.excludeFileTypes, ",") + + // since the group output is a comma separated string + // it needs to be split into a slice of strings groupOutput := strings.Split(*validatorConfig.groupOutput, ",") fsOpts := []finder.FSFinderOptions{finder.WithPathRoots(validatorConfig.searchPaths...), diff --git a/cmd/validator/validator_test.go b/cmd/validator/validator_test.go index a25fb6bf..2e85fd38 100644 --- a/cmd/validator/validator_test.go +++ b/cmd/validator/validator_test.go @@ -24,6 +24,8 @@ func Test_flags(t *testing.T) { {"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}, + {"incorrect group", []string{"--groupby=badgroup", "."}, 1}, + {"correct group", []string{"--groupby=directory", "."}, 0}, } for _, tc := range cases { // this call is required because otherwise flags panics, diff --git a/pkg/cli/cli_test.go b/pkg/cli/cli_test.go index 6a1014f7..7b3186d2 100644 --- a/pkg/cli/cli_test.go +++ b/pkg/cli/cli_test.go @@ -1,6 +1,7 @@ package cli import ( + "fmt" "testing" "github.com/Boeing/config-file-validator/pkg/finder" @@ -70,3 +71,29 @@ func Test_CLIBadPath(t *testing.T) { t.Errorf("Exit status was not 1") } } + +func Test_AllGroupedCLI(t *testing.T) { + searchPath := "../../test" + excludeDirs := []string{"subdir", "subdir2"} + groupOutput := []string{"pass/fail", "directory", "file"} + stdoutReporter := reporter.StdoutReporter{} + + fsFinder := finder.FileSystemFinderInit( + finder.WithPathRoots(searchPath), + finder.WithExcludeDirs(excludeDirs), + ) + cli := Init( + WithFinder(fsFinder), + WithReporter(stdoutReporter), + WithGroupOutput(groupOutput), + ) + exitStatus, err := cli.Run() + + if err != nil { + t.Errorf("An error was returned: %v", err) + } + + if exitStatus != 0 { + t.Errorf("Exit status was not 0") + } +} From 5683cb653dd46193582933ed151e5fd122da0eb7 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Sun, 19 Nov 2023 20:21:08 -0800 Subject: [PATCH 04/48] Reformat groupBy Reformatted the groupBy functions and groupBy validation --- cmd/validator/validator.go | 35 ++++++++++++++++++----------------- pkg/cli/cli.go | 14 +++----------- pkg/cli/groupoutput.go | 14 ++++++++++++++ 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/cmd/validator/validator.go b/cmd/validator/validator.go index fc9c17a6..98106b93 100644 --- a/cmd/validator/validator.go +++ b/cmd/validator/validator.go @@ -78,19 +78,6 @@ func getFlags() (validatorConfig, error) { searchPaths := make([]string, 0) - // groupByOptions is a slice of strings that contains the valid options for the groupby flag - groupByOptions := []string{"filetype", "directory", "pass/fail"} - - // groupByPassed is a string that contains the value passed to the groupby flag - // We need to convert it to lowercase and remove any whitespace to give users more flexibility - groupByPassed := flag.Lookup("groupby").Value.String() - groupByPassed = strings.ToLower(groupByPassed) - groupByPassed = strings.TrimSpace(groupByPassed) - - // groupByStrings is a slice of strings that contains the groupby options passed to the flag - // This will be used to validate that the options the user passed are valid - groupByStrings := strings.Split(groupByPassed, ",") - // If search path arg is empty, set it to the cwd // if not, set it to the arg. Supports n number of // paths @@ -112,9 +99,12 @@ func getFlags() (validatorConfig, error) { return validatorConfig{}, errors.New("Wrong parameter value for depth, value cannot be negative") } + groupByAllowedValues := []string{"filetype", "directory", "pass/fail"} + groupByUserInput := cleanMultiInputCommandString("groupby",",") + if groupOutputPtr != nil && isFlagSet("groupby") { - for _, groupBy := range groupByStrings { - if !slices.Contains(groupByOptions, groupBy) { + 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, or none") @@ -159,6 +149,17 @@ func getReporter(reportType *string) reporter.Reporter { } } +// cleanMultiInputCommandString takes a command string and a split string +// and returns a slice of strings +func cleanMultiInputCommandString(command, split string) []string { + commandValue := flag.Lookup(command).Value.String() + commandValue = strings.ToLower(commandValue) + commandValue = strings.TrimSpace(commandValue) + cleanedString := strings.Split(commandValue, split) + + return cleanedString +} + func mainInit() int { validatorConfig, err := getFlags() if err != nil { @@ -176,8 +177,8 @@ func mainInit() int { reporter := getReporter(validatorConfig.reportType) excludeFileTypes := strings.Split(*validatorConfig.excludeFileTypes, ",") - // since the group output is a comma separated string - // it needs to be split into a slice of strings + // since the group output is a comma separated string + // it needs to be split into a slice of strings groupOutput := strings.Split(*validatorConfig.groupOutput, ",") fsOpts := []finder.FSFinderOptions{finder.WithPathRoots(validatorConfig.searchPaths...), diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index e491269f..554adcb7 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -96,19 +96,11 @@ func (c CLI) Run() (int, error) { reports = append(reports, report) } + // Group the output if the user specified a group by option if len(GroupOutput) > 0 { - for _, group := range GroupOutput { - switch group { - case "filetype": - reports = GroupByFile(reports) - case "pass/fail": - reports = GroupByPassFail(reports) - case "directory": - reports = GroupByDirectory(reports) - } - } - c.Reporter.Print(reports) + reports = GroupBy(reports, GroupOutput) } + c.Reporter.Print(reports) if errorFound { return 1, nil diff --git a/pkg/cli/groupoutput.go b/pkg/cli/groupoutput.go index b4b54568..6bb5e9fd 100644 --- a/pkg/cli/groupoutput.go +++ b/pkg/cli/groupoutput.go @@ -75,3 +75,17 @@ func GroupByDirectory(reports []reporter.Report) []reporter.Report { return reportByDirectory } + +func GroupBy(reports []reporter.Report, groupBy []string) []reporter.Report { + for _, group := range groupBy { + switch group { + case "file": + reports = GroupByFile(reports) + case "directory": + reports = GroupByDirectory(reports) + case "pass/fail": + reports = GroupByPassFail(reports) + } + } + return reports +} From a88b172de5a17753bcbc22f1ce3edbcfbf8855e9 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Sun, 19 Nov 2023 20:51:05 -0800 Subject: [PATCH 05/48] Add Test Files Added more test files for testing purposes --- pkg/cli/{groupoutput.go => group_output.go} | 22 ++++++++++----------- test/fixtures/subdir2/bad.properties | 4 ++-- test/fixtures/subdir2/good.ini | 8 ++++++++ test/fixtures/subdir2/good.json | 5 +++++ 4 files changed, 26 insertions(+), 13 deletions(-) rename pkg/cli/{groupoutput.go => group_output.go} (86%) create mode 100644 test/fixtures/subdir2/good.ini create mode 100644 test/fixtures/subdir2/good.json diff --git a/pkg/cli/groupoutput.go b/pkg/cli/group_output.go similarity index 86% rename from pkg/cli/groupoutput.go rename to pkg/cli/group_output.go index 6bb5e9fd..208ca2a0 100644 --- a/pkg/cli/groupoutput.go +++ b/pkg/cli/group_output.go @@ -77,15 +77,15 @@ func GroupByDirectory(reports []reporter.Report) []reporter.Report { } func GroupBy(reports []reporter.Report, groupBy []string) []reporter.Report { - for _, group := range groupBy { - switch group { - case "file": - reports = GroupByFile(reports) - case "directory": - reports = GroupByDirectory(reports) - case "pass/fail": - reports = GroupByPassFail(reports) - } - } - return reports + for _, group := range groupBy { + switch group { + case "pass/fail": + reports = GroupByPassFail(reports) + case "filetype": + reports = GroupByFile(reports) + case "directory": + reports = GroupByDirectory(reports) + } + } + return reports } diff --git a/test/fixtures/subdir2/bad.properties b/test/fixtures/subdir2/bad.properties index 0057b938..246a47c5 100644 --- a/test/fixtures/subdir2/bad.properties +++ b/test/fixtures/subdir2/bad.properties @@ -23,7 +23,7 @@ multiline = This line \ continues # If you want your value to include a \, it should be escaped by another \. path = c:\\wiki\\templates -# This means that if the number of \ at the end of the line is even, the next line is not included in the value. +# This means that if the number of \ at the end of the line is even, the next line is not included in the value. # In the following example, the value for "evenKey" is "This is on one line\". evenKey = This is on one line\\ # This line is a normal comment and is not included in the value for "evenKey" @@ -45,4 +45,4 @@ encodedHelloInJapanese = \u3053\u3093\u306b\u3061\u306f # But with more modern file encodings like UTF-8, you can directly use supported characters. helloInJapanese = こんにちは # Circular Dependency -key = ${key} \ No newline at end of file +key = ${key} diff --git a/test/fixtures/subdir2/good.ini b/test/fixtures/subdir2/good.ini new file mode 100644 index 00000000..553e7ce0 --- /dev/null +++ b/test/fixtures/subdir2/good.ini @@ -0,0 +1,8 @@ +[Version] +First=name +second=value + +[Empty] + +[Last] +1=2 diff --git a/test/fixtures/subdir2/good.json b/test/fixtures/subdir2/good.json new file mode 100644 index 00000000..cd1a78b9 --- /dev/null +++ b/test/fixtures/subdir2/good.json @@ -0,0 +1,5 @@ +{ + "test": { + "name": "test" + } +} From 7800a50c809f4e4a99fafeb754a71ee79a9fc4a7 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 20 Nov 2023 08:25:42 -0800 Subject: [PATCH 06/48] Update grouping order and update readme Updated the groupings to be done in reverse order. Updated the readme with information on the groupby command --- README.md | 12 ++++++++++-- pkg/cli/group_output.go | 6 ++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d5bedaa2..a1161d48 100644 --- a/README.md +++ b/README.md @@ -103,12 +103,12 @@ optional flags: Subdirectories to exclude when searching for configuration files -exclude-file-types string A comma separated list of file types to ignore + -groupby string + Group the output by filetype, pass/fail, or directory -reporter string Format of the printed report. Options are standard and json (default "standard") -version Version prints the release version of validator - -groupby string - Group the output by file type, pass/fail, or directory ``` @@ -165,6 +165,14 @@ validator --reporter=json /path/to/search ![Exclude File Types Run](./img/custom_reporter.png) +### Group report output +Group the report output by file type, directory, or pass/fail. Supports one or more groupings. + +``` +validator -groupby filetype +validator -groupby directory,pass/fail +``` + #### Container Run ``` diff --git a/pkg/cli/group_output.go b/pkg/cli/group_output.go index 208ca2a0..d19b8d68 100644 --- a/pkg/cli/group_output.go +++ b/pkg/cli/group_output.go @@ -77,8 +77,10 @@ func GroupByDirectory(reports []reporter.Report) []reporter.Report { } func GroupBy(reports []reporter.Report, groupBy []string) []reporter.Report { - for _, group := range groupBy { - switch group { + // Iterate through groupBy in reverse order + // This will make the first command the primary grouping + for i := len(groupBy)-1; i >= 0; i-- { + switch groupBy[i] { case "pass/fail": reports = GroupByPassFail(reports) case "filetype": From 853efbd041cc7b3277b91e3283d39c4144caccc7 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 20 Nov 2023 08:45:11 -0800 Subject: [PATCH 07/48] Fix groupby directory Fixed the groupby directory function to group by the last directory in the path --- cmd/validator/validator.go | 16 ++++++++-------- pkg/cli/group_output.go | 3 ++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/cmd/validator/validator.go b/cmd/validator/validator.go index 98106b93..746f9eb5 100644 --- a/cmd/validator/validator.go +++ b/cmd/validator/validator.go @@ -99,15 +99,16 @@ func getFlags() (validatorConfig, error) { 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"} - groupByUserInput := cleanMultiInputCommandString("groupby",",") if groupOutputPtr != nil && isFlagSet("groupby") { 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, or none") + return validatorConfig{}, errors.New("Wrong parameter value for groupby, only supports filetype, directory, pass/fail") } } } @@ -149,13 +150,12 @@ func getReporter(reportType *string) reporter.Reporter { } } -// cleanMultiInputCommandString takes a command string and a split string +// cleanString takes a command string and a split string // and returns a slice of strings -func cleanMultiInputCommandString(command, split string) []string { - commandValue := flag.Lookup(command).Value.String() - commandValue = strings.ToLower(commandValue) - commandValue = strings.TrimSpace(commandValue) - cleanedString := strings.Split(commandValue, split) +func cleanString(command string) string { + cleanedString := flag.Lookup(command).Value.String() + cleanedString = strings.ToLower(cleanedString) + cleanedString = strings.TrimSpace(cleanedString) return cleanedString } diff --git a/pkg/cli/group_output.go b/pkg/cli/group_output.go index d19b8d68..4bbb7659 100644 --- a/pkg/cli/group_output.go +++ b/pkg/cli/group_output.go @@ -61,7 +61,8 @@ func GroupByDirectory(reports []reporter.Report) []reporter.Report { reportByDirectory := []reporter.Report{} for _, report := range reports { - directory := strings.Split(report.FilePath, "/")[1] + directoryPaths := strings.Split(report.FilePath, "/") + directory := directoryPaths[len(directoryPaths)-2] if mapFiles[directory] == nil { mapFiles[directory] = []reporter.Report{report} } else { From bd749410b322c297fa1891b3de2fa3f64b238620 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 20 Nov 2023 08:57:40 -0800 Subject: [PATCH 08/48] Update Tests Updated CLI tests --- cmd/validator/validator_test.go | 4 ++-- pkg/cli/cli_test.go | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cmd/validator/validator_test.go b/cmd/validator/validator_test.go index 2e85fd38..4cc16961 100644 --- a/cmd/validator/validator_test.go +++ b/cmd/validator/validator_test.go @@ -24,8 +24,8 @@ func Test_flags(t *testing.T) { {"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}, - {"incorrect group", []string{"--groupby=badgroup", "."}, 1}, - {"correct group", []string{"--groupby=directory", "."}, 0}, + {"incorrect group", []string{"-groupby=badgroup", "."}, 1}, + {"correct group", []string{"-groupby=directory", "."}, 0}, } for _, tc := range cases { // this call is required because otherwise flags panics, diff --git a/pkg/cli/cli_test.go b/pkg/cli/cli_test.go index 7b3186d2..b10a98ec 100644 --- a/pkg/cli/cli_test.go +++ b/pkg/cli/cli_test.go @@ -1,7 +1,6 @@ package cli import ( - "fmt" "testing" "github.com/Boeing/config-file-validator/pkg/finder" @@ -11,6 +10,7 @@ import ( func Test_CLI(t *testing.T) { searchPath := "../../test" excludeDirs := []string{"subdir", "subdir2"} + groupBy := []string{} stdoutReporter := reporter.StdoutReporter{} fsFinder := finder.FileSystemFinderInit( @@ -20,6 +20,7 @@ func Test_CLI(t *testing.T) { cli := Init( WithFinder(fsFinder), WithReporter(stdoutReporter), + WithGroupOutput(groupBy), ) exitStatus, err := cli.Run() @@ -72,10 +73,10 @@ func Test_CLIBadPath(t *testing.T) { } } -func Test_AllGroupedCLI(t *testing.T) { +func Test_CLIWithGroup(t *testing.T) { searchPath := "../../test" excludeDirs := []string{"subdir", "subdir2"} - groupOutput := []string{"pass/fail", "directory", "file"} + groupOutput := []string{"pass/fail", "directory", "filetype"} stdoutReporter := reporter.StdoutReporter{} fsFinder := finder.FileSystemFinderInit( From ca546e45d74454a5e7788336fec620999b475ae7 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 20 Nov 2023 09:08:48 -0800 Subject: [PATCH 09/48] Fix Comment Fixed the cleanString funciton comment --- cmd/validator/validator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/validator/validator.go b/cmd/validator/validator.go index 746f9eb5..6c080a77 100644 --- a/cmd/validator/validator.go +++ b/cmd/validator/validator.go @@ -151,7 +151,7 @@ func getReporter(reportType *string) reporter.Reporter { } // cleanString takes a command string and a split string -// and returns a slice of strings +// and returns a cleaned string func cleanString(command string) string { cleanedString := flag.Lookup(command).Value.String() cleanedString = strings.ToLower(cleanedString) From e61be6667551b577dba389b3d8d16578af813da2 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 20 Nov 2023 10:54:20 -0800 Subject: [PATCH 10/48] Update README.md Co-authored-by: Jamie Davidson <51518462+jd4235@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a1161d48..7ab0592d 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ There are several ways to install the config file validator tool We offer alpine, ubuntu, and scratch containers -#### Apline +#### Alpine ``` docker pull ghcr.io/boeing/config-file-validator:v1.5.0 From 1140303e3294d3b748c9c31f21cdbdda88467ff5 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 20 Nov 2023 10:55:45 -0800 Subject: [PATCH 11/48] Update cli_test.go Fixed formatting --- pkg/cli/cli_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/cli/cli_test.go b/pkg/cli/cli_test.go index b10a98ec..ee35e85f 100644 --- a/pkg/cli/cli_test.go +++ b/pkg/cli/cli_test.go @@ -10,7 +10,7 @@ import ( func Test_CLI(t *testing.T) { searchPath := "../../test" excludeDirs := []string{"subdir", "subdir2"} - groupBy := []string{} + groupBy := []string{} stdoutReporter := reporter.StdoutReporter{} fsFinder := finder.FileSystemFinderInit( @@ -20,7 +20,7 @@ func Test_CLI(t *testing.T) { cli := Init( WithFinder(fsFinder), WithReporter(stdoutReporter), - WithGroupOutput(groupBy), + WithGroupOutput(groupBy), ) exitStatus, err := cli.Run() From b333ed20959ff7409669d87b27bacad07f754a1c Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 20 Nov 2023 10:57:07 -0800 Subject: [PATCH 12/48] Update validator.go Update pass/fail to pass-fail for validation checks --- cmd/validator/validator.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/validator/validator.go b/cmd/validator/validator.go index 6c080a77..1ffe4e15 100644 --- a/cmd/validator/validator.go +++ b/cmd/validator/validator.go @@ -101,14 +101,14 @@ func getFlags() (validatorConfig, error) { groupByCleanString := cleanString("groupby") groupByUserInput := strings.Split(groupByCleanString, ",") - groupByAllowedValues := []string{"filetype", "directory", "pass/fail"} + groupByAllowedValues := []string{"filetype", "directory", "pass-fail"} if groupOutputPtr != nil && isFlagSet("groupby") { for _, groupBy := range groupByUserInput { if !slices.Contains(groupByAllowedValues, groupBy) { - fmt.Println("Wrong parameter value for groupby, only supports filetype, directory, pass/fail") + 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") + return validatorConfig{}, errors.New("Wrong parameter value for groupby, only supports filetype, directory, pass-fail") } } } From 42e0c504e902561afab1ce239c2146d5c5eac2f1 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 20 Nov 2023 10:57:43 -0800 Subject: [PATCH 13/48] Update validator_test.go Fixed formatting indentation --- cmd/validator/validator_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/validator/validator_test.go b/cmd/validator/validator_test.go index 4cc16961..596fc199 100644 --- a/cmd/validator/validator_test.go +++ b/cmd/validator/validator_test.go @@ -24,8 +24,8 @@ func Test_flags(t *testing.T) { {"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}, - {"incorrect group", []string{"-groupby=badgroup", "."}, 1}, - {"correct group", []string{"-groupby=directory", "."}, 0}, + {"incorrect group", []string{"-groupby=badgroup", "."}, 1}, + {"correct group", []string{"-groupby=directory", "."}, 0}, } for _, tc := range cases { // this call is required because otherwise flags panics, From 1264e9946ba3df5fc10783ba58b21ae21a57aabe Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 20 Nov 2023 10:58:41 -0800 Subject: [PATCH 14/48] Update group_output.go Changed pass/fail to pass-fail for GroupBy routing --- pkg/cli/group_output.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cli/group_output.go b/pkg/cli/group_output.go index 4bbb7659..1bc901fc 100644 --- a/pkg/cli/group_output.go +++ b/pkg/cli/group_output.go @@ -82,7 +82,7 @@ func GroupBy(reports []reporter.Report, groupBy []string) []reporter.Report { // This will make the first command the primary grouping for i := len(groupBy)-1; i >= 0; i-- { switch groupBy[i] { - case "pass/fail": + case "pass-fail": reports = GroupByPassFail(reports) case "filetype": reports = GroupByFile(reports) From 49de011768337ba101c48d394f25b12836ad98eb Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 20 Nov 2023 10:59:46 -0800 Subject: [PATCH 15/48] Update README.md Changed pass/fail to pass-fail for documentation --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7ab0592d..2a722294 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ optional flags: -exclude-file-types string A comma separated list of file types to ignore -groupby string - Group the output by filetype, pass/fail, or directory + Group the output by filetype, pass-fail, or directory -reporter string Format of the printed report. Options are standard and json (default "standard") -version @@ -166,11 +166,11 @@ validator --reporter=json /path/to/search ![Exclude File Types Run](./img/custom_reporter.png) ### Group report output -Group the report output by file type, directory, or pass/fail. Supports one or more groupings. +Group the report output by file type, directory, or pass-fail. Supports one or more groupings. ``` validator -groupby filetype -validator -groupby directory,pass/fail +validator -groupby directory,pass-fail ``` From 89718be63496d443d67421ec65fec043697e99a7 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 20 Nov 2023 11:05:21 -0800 Subject: [PATCH 16/48] Update validator.go Fixed formatting for groupBy string cleansing --- cmd/validator/validator.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/validator/validator.go b/cmd/validator/validator.go index 1ffe4e15..d1df57a1 100644 --- a/cmd/validator/validator.go +++ b/cmd/validator/validator.go @@ -99,9 +99,9 @@ func getFlags() (validatorConfig, error) { 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"} + groupByCleanString := cleanString("groupby") + groupByUserInput := strings.Split(groupByCleanString, ",") + groupByAllowedValues := []string{"filetype", "directory", "pass-fail"} if groupOutputPtr != nil && isFlagSet("groupby") { for _, groupBy := range groupByUserInput { From 367bd4943af68b0cf13daced8ee2f0ce997c666f Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 20 Nov 2023 11:08:56 -0800 Subject: [PATCH 17/48] Update group_output.go Updated indentation --- pkg/cli/group_output.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/cli/group_output.go b/pkg/cli/group_output.go index 1bc901fc..b41886b3 100644 --- a/pkg/cli/group_output.go +++ b/pkg/cli/group_output.go @@ -62,7 +62,7 @@ func GroupByDirectory(reports []reporter.Report) []reporter.Report { for _, report := range reports { directoryPaths := strings.Split(report.FilePath, "/") - directory := directoryPaths[len(directoryPaths)-2] + directory := directoryPaths[len(directoryPaths)-2] if mapFiles[directory] == nil { mapFiles[directory] = []reporter.Report{report} } else { @@ -78,9 +78,9 @@ func GroupByDirectory(reports []reporter.Report) []reporter.Report { } func GroupBy(reports []reporter.Report, groupBy []string) []reporter.Report { - // Iterate through groupBy in reverse order - // This will make the first command the primary grouping - for i := len(groupBy)-1; i >= 0; i-- { + // Iterate through groupBy in reverse order + // This will make the first command the primary grouping + for i := len(groupBy)-1; i >= 0; i-- { switch groupBy[i] { case "pass-fail": reports = GroupByPassFail(reports) @@ -89,6 +89,6 @@ func GroupBy(reports []reporter.Report, groupBy []string) []reporter.Report { case "directory": reports = GroupByDirectory(reports) } - } + } return reports } From 438275f7a692f806a3eedf0434903e68954e9d48 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 20 Nov 2023 11:27:08 -0800 Subject: [PATCH 18/48] Update validator.go Update flag to pass-fail --- cmd/validator/validator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/validator/validator.go b/cmd/validator/validator.go index d1df57a1..9b782cc6 100644 --- a/cmd/validator/validator.go +++ b/cmd/validator/validator.go @@ -73,7 +73,7 @@ func getFlags() (validatorConfig, error) { excludeFileTypesPtr := flag.String("exclude-file-types", "", "A comma separated list of file types to ignore") depthPtr := flag.Int("depth", 0, "Depth of recursion for the provided search paths. Set depth to 0 to disable recursive path traversal") versionPtr := flag.Bool("version", false, "Version prints the release version of validator") - groupOutputPtr := flag.String("groupby", "", "Group output by file type, directory, pass/fail") + groupOutputPtr := flag.String("groupby", "", "Group output by file type, directory, pass-fail") flag.Parse() searchPaths := make([]string, 0) From 741a1ca5ffec4f0838a80ebf1d0cbbc2c5d6a11b Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 20 Nov 2023 11:28:39 -0800 Subject: [PATCH 19/48] Update cli_test.go Update pass/fail to pass-fail --- pkg/cli/cli_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cli/cli_test.go b/pkg/cli/cli_test.go index ee35e85f..a41a7902 100644 --- a/pkg/cli/cli_test.go +++ b/pkg/cli/cli_test.go @@ -76,7 +76,7 @@ func Test_CLIBadPath(t *testing.T) { func Test_CLIWithGroup(t *testing.T) { searchPath := "../../test" excludeDirs := []string{"subdir", "subdir2"} - groupOutput := []string{"pass/fail", "directory", "filetype"} + groupOutput := []string{"pass-fail", "directory", "filetype"} stdoutReporter := reporter.StdoutReporter{} fsFinder := finder.FileSystemFinderInit( From 1f21c258c1e67e915161a4d7bad8b23ef2389130 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 20 Nov 2023 11:30:26 -0800 Subject: [PATCH 20/48] Update group_output.go Update GroupByPassFail comment to be consistent with pass-fail --- pkg/cli/group_output.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cli/group_output.go b/pkg/cli/group_output.go index b41886b3..171185cf 100644 --- a/pkg/cli/group_output.go +++ b/pkg/cli/group_output.go @@ -27,7 +27,7 @@ func GroupByFile(reports []reporter.Report) []reporter.Report { return reportByFile } -// Group Files by Pass/Fail +// Group Files by Pass-Fail func GroupByPassFail(reports []reporter.Report) []reporter.Report { mapFiles := make(map[string][]reporter.Report) reportByPassOrFail := []reporter.Report{} From 8dc47c63077697aac08713aad7cc284c1b5e680a Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 20 Nov 2023 18:30:56 -0800 Subject: [PATCH 21/48] Formatting fix Update to formatting --- cmd/validator/validator.go | 6 ++-- cmd/validator/validator_test.go | 4 +-- pkg/cli/cli_test.go | 50 ++++++++++++++++----------------- pkg/cli/group_output.go | 10 +++---- 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/cmd/validator/validator.go b/cmd/validator/validator.go index 9b782cc6..2dd8adfd 100644 --- a/cmd/validator/validator.go +++ b/cmd/validator/validator.go @@ -99,9 +99,9 @@ func getFlags() (validatorConfig, error) { 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"} + groupByCleanString := cleanString("groupby") + groupByUserInput := strings.Split(groupByCleanString, ",") + groupByAllowedValues := []string{"filetype", "directory", "pass-fail"} if groupOutputPtr != nil && isFlagSet("groupby") { for _, groupBy := range groupByUserInput { diff --git a/cmd/validator/validator_test.go b/cmd/validator/validator_test.go index 596fc199..bbacd511 100644 --- a/cmd/validator/validator_test.go +++ b/cmd/validator/validator_test.go @@ -24,8 +24,8 @@ func Test_flags(t *testing.T) { {"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}, - {"incorrect group", []string{"-groupby=badgroup", "."}, 1}, - {"correct group", []string{"-groupby=directory", "."}, 0}, + {"incorrect group", []string{"-groupby=badgroup", "."}, 1}, + {"correct group", []string{"-groupby=directory", "."}, 0}, } for _, tc := range cases { // this call is required because otherwise flags panics, diff --git a/pkg/cli/cli_test.go b/pkg/cli/cli_test.go index a41a7902..dbd810af 100644 --- a/pkg/cli/cli_test.go +++ b/pkg/cli/cli_test.go @@ -10,7 +10,7 @@ import ( func Test_CLI(t *testing.T) { searchPath := "../../test" excludeDirs := []string{"subdir", "subdir2"} - groupBy := []string{} + groupBy := []string{} stdoutReporter := reporter.StdoutReporter{} fsFinder := finder.FileSystemFinderInit( @@ -20,7 +20,7 @@ func Test_CLI(t *testing.T) { cli := Init( WithFinder(fsFinder), WithReporter(stdoutReporter), - WithGroupOutput(groupBy), + WithGroupOutput(groupBy), ) exitStatus, err := cli.Run() @@ -74,27 +74,27 @@ func Test_CLIBadPath(t *testing.T) { } func Test_CLIWithGroup(t *testing.T) { - searchPath := "../../test" - excludeDirs := []string{"subdir", "subdir2"} - groupOutput := []string{"pass-fail", "directory", "filetype"} - stdoutReporter := reporter.StdoutReporter{} - - fsFinder := finder.FileSystemFinderInit( - finder.WithPathRoots(searchPath), - finder.WithExcludeDirs(excludeDirs), - ) - cli := Init( - WithFinder(fsFinder), - WithReporter(stdoutReporter), - WithGroupOutput(groupOutput), - ) - exitStatus, err := cli.Run() - - if err != nil { - t.Errorf("An error was returned: %v", err) - } - - if exitStatus != 0 { - t.Errorf("Exit status was not 0") - } + searchPath := "../../test" + excludeDirs := []string{"subdir", "subdir2"} + groupOutput := []string{"pass-fail", "directory", "filetype"} + stdoutReporter := reporter.StdoutReporter{} + + fsFinder := finder.FileSystemFinderInit( + finder.WithPathRoots(searchPath), + finder.WithExcludeDirs(excludeDirs), + ) + cli := Init( + WithFinder(fsFinder), + WithReporter(stdoutReporter), + WithGroupOutput(groupOutput), + ) + exitStatus, err := cli.Run() + + if err != nil { + t.Errorf("An error was returned: %v", err) + } + + if exitStatus != 0 { + t.Errorf("Exit status was not 0") + } } diff --git a/pkg/cli/group_output.go b/pkg/cli/group_output.go index 171185cf..247a290f 100644 --- a/pkg/cli/group_output.go +++ b/pkg/cli/group_output.go @@ -62,7 +62,7 @@ func GroupByDirectory(reports []reporter.Report) []reporter.Report { for _, report := range reports { directoryPaths := strings.Split(report.FilePath, "/") - directory := directoryPaths[len(directoryPaths)-2] + directory := directoryPaths[len(directoryPaths)-2] if mapFiles[directory] == nil { mapFiles[directory] = []reporter.Report{report} } else { @@ -78,9 +78,9 @@ func GroupByDirectory(reports []reporter.Report) []reporter.Report { } func GroupBy(reports []reporter.Report, groupBy []string) []reporter.Report { - // Iterate through groupBy in reverse order - // This will make the first command the primary grouping - for i := len(groupBy)-1; i >= 0; i-- { + // Iterate through groupBy in reverse order + // This will make the first command the primary grouping + for i := len(groupBy) - 1; i >= 0; i-- { switch groupBy[i] { case "pass-fail": reports = GroupByPassFail(reports) @@ -89,6 +89,6 @@ func GroupBy(reports []reporter.Report, groupBy []string) []reporter.Report { case "directory": reports = GroupByDirectory(reports) } - } + } return reports } From a90a8883f4c8469d16c7d677a0e51d175cd42819 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 20 Nov 2023 18:47:35 -0800 Subject: [PATCH 22/48] Add Group output Organized output for when groupby flag is set --- pkg/cli/cli.go | 10 +++-- pkg/cli/group_output.go | 69 ++++++++++++++------------------- pkg/reporter/json_reporter.go | 5 +++ pkg/reporter/reporter.go | 1 + pkg/reporter/stdout_reporter.go | 18 +++++++++ 5 files changed, 59 insertions(+), 44 deletions(-) diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index 554adcb7..5a140a71 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -97,10 +97,12 @@ func (c CLI) Run() (int, error) { } // Group the output if the user specified a group by option - if len(GroupOutput) > 0 { - reports = GroupBy(reports, GroupOutput) - } - c.Reporter.Print(reports) + if GroupOutput[0] != "" { + groupReports := GroupBy(reports, GroupOutput) + c.Reporter.PrintGroup(groupReports) + } else { + c.Reporter.Print(reports) + } if errorFound { return 1, nil diff --git a/pkg/cli/group_output.go b/pkg/cli/group_output.go index 247a290f..3da7fa8a 100644 --- a/pkg/cli/group_output.go +++ b/pkg/cli/group_output.go @@ -7,88 +7,77 @@ import ( ) // Group Files by File Type -func GroupByFile(reports []reporter.Report) []reporter.Report { - mapFiles := make(map[string][]reporter.Report) - reportByFile := []reporter.Report{} +func GroupByFile(reports []reporter.Report) map[string][]reporter.Report { + reportByFile := make(map[string][]reporter.Report) for _, report := range reports { fileType := strings.Split(report.FileName, ".")[1] - if mapFiles[fileType] == nil { - mapFiles[fileType] = []reporter.Report{report} + if fileType == "yml" && reportByFile["yaml"] == nil { + reportByFile["yaml"] = []reporter.Report{report} + } else if fileType == "yml" && reportByFile["yaml"] != nil { + reportByFile["yaml"] = append(reportByFile["yaml"], report) + } else if reportByFile[fileType] == nil { + reportByFile[fileType] = []reporter.Report{report} } else { - mapFiles[fileType] = append(mapFiles[fileType], report) + reportByFile[fileType] = append(reportByFile[fileType], report) } } - for _, reports := range mapFiles { - reportByFile = append(reportByFile, reports...) - } - return reportByFile } // Group Files by Pass-Fail -func GroupByPassFail(reports []reporter.Report) []reporter.Report { - mapFiles := make(map[string][]reporter.Report) - reportByPassOrFail := []reporter.Report{} +func GroupByPassFail(reports []reporter.Report) map[string][]reporter.Report { + reportByPassOrFail := make(map[string][]reporter.Report) for _, report := range reports { if report.IsValid { - if mapFiles["pass"] == nil { - mapFiles["pass"] = []reporter.Report{report} + if reportByPassOrFail["Passed"] == nil { + reportByPassOrFail["Passed"] = []reporter.Report{report} } else { - mapFiles["pass"] = append(mapFiles["pass"], report) + reportByPassOrFail["Passed"] = append(reportByPassOrFail["Passed"], report) } + } else if reportByPassOrFail["Failed"] == nil { + reportByPassOrFail["Failed"] = []reporter.Report{report} } else { - if mapFiles["fail"] == nil { - mapFiles["fail"] = []reporter.Report{report} - } else { - mapFiles["fail"] = append(mapFiles["fail"], report) - } + reportByPassOrFail["Failed"] = append(reportByPassOrFail["Failed"], report) } - } - for _, reports := range mapFiles { - reportByPassOrFail = append(reportByPassOrFail, reports...) } return reportByPassOrFail } // Group Files by Directory -func GroupByDirectory(reports []reporter.Report) []reporter.Report { - mapFiles := make(map[string][]reporter.Report) - reportByDirectory := []reporter.Report{} - +func GroupByDirectory(reports []reporter.Report) map[string][]reporter.Report { + reportByDirectory := make(map[string][]reporter.Report) for _, report := range reports { directoryPaths := strings.Split(report.FilePath, "/") directory := directoryPaths[len(directoryPaths)-2] - if mapFiles[directory] == nil { - mapFiles[directory] = []reporter.Report{report} + if reportByDirectory[directory] == nil { + reportByDirectory[directory] = []reporter.Report{report} } else { - mapFiles[directory] = append(mapFiles[directory], report) + reportByDirectory[directory] = append(reportByDirectory[directory], report) } } - for _, reports := range mapFiles { - reportByDirectory = append(reportByDirectory, reports...) - } - return reportByDirectory } -func GroupBy(reports []reporter.Report, groupBy []string) []reporter.Report { +func GroupBy(reports []reporter.Report, groupBy []string) map[string][]reporter.Report { // Iterate through groupBy in reverse order // This will make the first command the primary grouping + groupReports := make(map[string][]reporter.Report) + for i := len(groupBy) - 1; i >= 0; i-- { switch groupBy[i] { case "pass-fail": - reports = GroupByPassFail(reports) + groupReports = GroupByPassFail(reports) case "filetype": - reports = GroupByFile(reports) + groupReports = GroupByFile(reports) case "directory": - reports = GroupByDirectory(reports) + groupReports = GroupByDirectory(reports) } } - return reports + return groupReports } diff --git a/pkg/reporter/json_reporter.go b/pkg/reporter/json_reporter.go index 18655e11..56f2f6d2 100644 --- a/pkg/reporter/json_reporter.go +++ b/pkg/reporter/json_reporter.go @@ -67,3 +67,8 @@ func (jr JsonReporter) Print(reports []Report) error { fmt.Println(string(jsonBytes)) return nil } + +func (jr JsonReporter) PrintGroup(reports map[string][]Report) error { + //TODO + return nil +} diff --git a/pkg/reporter/reporter.go b/pkg/reporter/reporter.go index 4b48269a..e92016ec 100644 --- a/pkg/reporter/reporter.go +++ b/pkg/reporter/reporter.go @@ -16,4 +16,5 @@ type Report struct { // files, etc type Reporter interface { Print(reports []Report) error + PrintGroup(reports map[string][]Report) error } diff --git a/pkg/reporter/stdout_reporter.go b/pkg/reporter/stdout_reporter.go index f57d5e96..8537f31d 100644 --- a/pkg/reporter/stdout_reporter.go +++ b/pkg/reporter/stdout_reporter.go @@ -31,6 +31,24 @@ func (sr StdoutReporter) Print(reports []Report) error { return nil } +func (sr StdoutReporter) PrintGroup(groupReports map[string][]Report) error { + for key, reports := range groupReports { + fmt.Println(key) + for _, report := range reports { + if !report.IsValid { + color.Set(color.FgRed) + fmt.Println(" × " + report.FilePath) + paddedString := sr.padErrorString(report.ValidationError.Error()) + fmt.Printf(" error: %v\n", paddedString) + color.Unset() + } else { + color.Green(" ✓ " + report.FilePath) + } + } + } + return nil +} + // padErrorString adds padding to every newline in the error // string, except the first line and removes any trailing newlines // or spaces From a7b3335601ead0bebbde8a9a2c2dbb1ef07fb094 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Tue, 21 Nov 2023 19:43:57 -0800 Subject: [PATCH 23/48] Implement Group Output standard out Implementation of standard out using single and double groupbys --- pkg/cli/cli.go | 17 ++- pkg/cli/group_output.go | 36 +++--- pkg/cli/group_output_two.go | 200 ++++++++++++++++++++++++++++++++ pkg/reporter/json_reporter.go | 62 +++++++++- pkg/reporter/reporter.go | 3 +- pkg/reporter/stdout_reporter.go | 26 ++++- 6 files changed, 314 insertions(+), 30 deletions(-) create mode 100644 pkg/cli/group_output_two.go diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index 5a140a71..8e95f71b 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -97,13 +97,20 @@ func (c CLI) Run() (int, error) { } // Group the output if the user specified a group by option + // The length of GroupOutput is 1 even when empty. + // Need to review this but it works for now. if GroupOutput[0] != "" { - groupReports := GroupBy(reports, GroupOutput) - c.Reporter.PrintGroup(groupReports) - } else { - c.Reporter.Print(reports) - } + if len(GroupOutput) == 1 { + reportGroup := GroupBySingle(reports, GroupOutput) + c.Reporter.PrintSingleGroup(reportGroup, GroupOutput[0]) + } else if len(GroupOutput) == 2 { + reportGroup := GroupByDouble(reports, GroupOutput) + c.Reporter.PrintDoubleGroup(reportGroup) + } + } else { + c.Reporter.Print(reports) + } if errorFound { return 1, nil } else { diff --git a/pkg/cli/group_output.go b/pkg/cli/group_output.go index 3da7fa8a..7c728cef 100644 --- a/pkg/cli/group_output.go +++ b/pkg/cli/group_output.go @@ -6,17 +6,16 @@ import ( "github.com/Boeing/config-file-validator/pkg/reporter" ) -// Group Files by File Type +// Group Reports by File Type func GroupByFile(reports []reporter.Report) map[string][]reporter.Report { reportByFile := make(map[string][]reporter.Report) for _, report := range reports { fileType := strings.Split(report.FileName, ".")[1] - if fileType == "yml" && reportByFile["yaml"] == nil { - reportByFile["yaml"] = []reporter.Report{report} - } else if fileType == "yml" && reportByFile["yaml"] != nil { - reportByFile["yaml"] = append(reportByFile["yaml"], report) - } else if reportByFile[fileType] == nil { + if fileType == "yml" { + fileType = "yaml" + } + if reportByFile[fileType] == nil { reportByFile[fileType] = []reporter.Report{report} } else { reportByFile[fileType] = append(reportByFile[fileType], report) @@ -26,7 +25,7 @@ func GroupByFile(reports []reporter.Report) map[string][]reporter.Report { return reportByFile } -// Group Files by Pass-Fail +// Group Reports by Pass-Fail func GroupByPassFail(reports []reporter.Report) map[string][]reporter.Report { reportByPassOrFail := make(map[string][]reporter.Report) @@ -48,12 +47,14 @@ func GroupByPassFail(reports []reporter.Report) map[string][]reporter.Report { return reportByPassOrFail } -// Group Files by Directory +// Group Reports by Directory func GroupByDirectory(reports []reporter.Report) map[string][]reporter.Report { reportByDirectory := make(map[string][]reporter.Report) for _, report := range reports { - directoryPaths := strings.Split(report.FilePath, "/") - directory := directoryPaths[len(directoryPaths)-2] + directoryPath := strings.Split(report.FilePath, "/") + directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") + directory = directory + "/" + if reportByDirectory[directory] == nil { reportByDirectory[directory] = []reporter.Report{report} } else { @@ -64,20 +65,19 @@ func GroupByDirectory(reports []reporter.Report) map[string][]reporter.Report { return reportByDirectory } -func GroupBy(reports []reporter.Report, groupBy []string) map[string][]reporter.Report { - // Iterate through groupBy in reverse order - // This will make the first command the primary grouping - groupReports := make(map[string][]reporter.Report) +func GroupBySingle(reports []reporter.Report, groupBy []string) map[string][]reporter.Report { + + var groupReport map[string][]reporter.Report for i := len(groupBy) - 1; i >= 0; i-- { switch groupBy[i] { case "pass-fail": - groupReports = GroupByPassFail(reports) + groupReport = GroupByPassFail(reports) case "filetype": - groupReports = GroupByFile(reports) + groupReport = GroupByFile(reports) case "directory": - groupReports = GroupByDirectory(reports) + groupReport = GroupByDirectory(reports) } } - return groupReports + return groupReport } diff --git a/pkg/cli/group_output_two.go b/pkg/cli/group_output_two.go new file mode 100644 index 00000000..e1180e28 --- /dev/null +++ b/pkg/cli/group_output_two.go @@ -0,0 +1,200 @@ +package cli + +import ( + "strings" + + "github.com/Boeing/config-file-validator/pkg/reporter" +) + +// Group Reports by Pass-Fail and File Extension +func GroupByPassFailFile(reports []reporter.Report) map[string]map[string][]reporter.Report { + reportByPassOrFail := make(map[string]map[string][]reporter.Report) + + for _, report := range reports { + fileExtension := strings.Split(report.FileName, ".")[1] + if report.IsValid { + if reportByPassOrFail["Passed"] == nil { + reportByPassOrFail["Passed"] = make(map[string][]reporter.Report) + reportByPassOrFail["Passed"][fileExtension] = []reporter.Report{report} + } else if reportByPassOrFail["Passed"] != nil && reportByPassOrFail["Passed"][fileExtension] == nil { + reportByPassOrFail["Passed"][fileExtension] = []reporter.Report{report} + } else if reportByPassOrFail["Passed"] != nil && reportByPassOrFail["Passed"][fileExtension] != nil { + reportByPassOrFail["Passed"][fileExtension] = append(reportByPassOrFail["Passed"][fileExtension], report) + } + } else { + if reportByPassOrFail["Failed"] == nil { + reportByPassOrFail["Failed"] = make(map[string][]reporter.Report) + reportByPassOrFail["Failed"][fileExtension] = []reporter.Report{report} + } else if reportByPassOrFail["Failed"] != nil && reportByPassOrFail["Failed"][fileExtension] == nil { + reportByPassOrFail["Failed"][fileExtension] = []reporter.Report{report} + } else if reportByPassOrFail["Failed"] != nil && reportByPassOrFail["Failed"][fileExtension] != nil { + reportByPassOrFail["Failed"][fileExtension] = append(reportByPassOrFail["Failed"][fileExtension], report) + } + } + } + return reportByPassOrFail +} + +// Group Reports by Pass-Fail and Directory +func GroupByPassFailDirectory(reports []reporter.Report) map[string]map[string][]reporter.Report { + reportByPassOrFail := make(map[string]map[string][]reporter.Report) + + for _, report := range reports { + directoryPath := strings.Split(report.FilePath, "/") + directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") + directory = directory + "/" + + if report.IsValid { + if reportByPassOrFail["Passed"] == nil { + reportByPassOrFail["Passed"] = make(map[string][]reporter.Report) + reportByPassOrFail["Passed"][directory] = []reporter.Report{report} + } else if reportByPassOrFail["Passed"] != nil && reportByPassOrFail["Passed"][directory] == nil { + reportByPassOrFail["Passed"][directory] = []reporter.Report{report} + } else if reportByPassOrFail["Passed"] != nil && reportByPassOrFail["Passed"][directory] != nil { + reportByPassOrFail["Passed"][directory] = append(reportByPassOrFail["Passed"][directory], report) + } + } else if reportByPassOrFail["Failed"] == nil && reportByPassOrFail["Failed"][directory] == nil { + reportByPassOrFail["Failed"] = make(map[string][]reporter.Report) + reportByPassOrFail["Failed"][directory] = []reporter.Report{report} + } else if reportByPassOrFail["Failed"] != nil && reportByPassOrFail["Failed"][directory] == nil { + reportByPassOrFail["Failed"][directory] = []reporter.Report{report} + } else if reportByPassOrFail["Failed"] != nil && reportByPassOrFail["Failed"][directory] != nil { + reportByPassOrFail["Failed"][directory] = append(reportByPassOrFail["Failed"][directory], report) + } + + } + + return reportByPassOrFail +} + +// Group Reports by File Extension and Directory +func GroupByFileDirectory(reports []reporter.Report) map[string]map[string][]reporter.Report { + reportByFile := make(map[string]map[string][]reporter.Report) + + for _, report := range reports { + directoryPath := strings.Split(report.FilePath, "/") + directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") + directory = directory + "/" + fileExtension := strings.Split(report.FileName, ".")[1] + if fileExtension == "yml" { + fileExtension = "yaml" + } + if reportByFile[fileExtension] == nil { + reportByFile[fileExtension] = make(map[string][]reporter.Report) + reportByFile[fileExtension][directory] = []reporter.Report{report} + } else if reportByFile[fileExtension] != nil && reportByFile[fileExtension][directory] == nil { + reportByFile[fileExtension][directory] = []reporter.Report{report} + } else if reportByFile[fileExtension] != nil && reportByFile[fileExtension][directory] != nil { + reportByFile[fileExtension][directory] = append(reportByFile[fileExtension][directory], report) + } + } + return reportByFile +} + +// Group Reports by File Extension and Pass-Fail +func GroupByFilePassFail(reports []reporter.Report) map[string]map[string][]reporter.Report { + reportByFile := make(map[string]map[string][]reporter.Report) + + for _, report := range reports { + fileExtension := strings.Split(report.FileName, ".")[1] + if fileExtension == "yml" { + fileExtension = "yaml" + } + if reportByFile[fileExtension] == nil && report.IsValid { + reportByFile[fileExtension] = make(map[string][]reporter.Report) + reportByFile[fileExtension]["Passed"] = []reporter.Report{report} + } else if reportByFile[fileExtension] != nil && reportByFile[fileExtension]["Passed"] == nil && report.IsValid { + reportByFile[fileExtension]["Passed"] = []reporter.Report{report} + } else if reportByFile[fileExtension] != nil && reportByFile[fileExtension]["Passed"] != nil && report.IsValid { + reportByFile[fileExtension]["Passed"] = append(reportByFile[fileExtension]["Passed"], report) + } else if reportByFile[fileExtension] == nil && !report.IsValid { + reportByFile = make(map[string]map[string][]reporter.Report) + reportByFile[fileExtension]["Failed"] = []reporter.Report{report} + } else if reportByFile[fileExtension] != nil && reportByFile[fileExtension]["Failed"] == nil && !report.IsValid { + reportByFile[fileExtension]["Failed"] = []reporter.Report{report} + } else if reportByFile[fileExtension] != nil && reportByFile[fileExtension]["Failed"] != nil && !report.IsValid { + reportByFile[fileExtension]["Failed"] = append(reportByFile[fileExtension]["Failed"], report) + } + + } + + return reportByFile +} + +// Group Reports by Directory and Pass-Fail +func GroupByDirectoryPassFail(reports []reporter.Report) map[string]map[string][]reporter.Report { + reportByDirectory := make(map[string]map[string][]reporter.Report) + for _, report := range reports { + directoryPath := strings.Split(report.FilePath, "/") + directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") + directory = directory + "/" + + if report.IsValid { + if reportByDirectory[directory] == nil { + reportByDirectory[directory] = make(map[string][]reporter.Report) + reportByDirectory[directory]["Passed"] = []reporter.Report{report} + } else if reportByDirectory[directory] != nil && reportByDirectory[directory]["Passed"] == nil { + reportByDirectory[directory]["Passed"] = []reporter.Report{report} + } else if reportByDirectory[directory] != nil && reportByDirectory[directory]["Passed"] != nil { + reportByDirectory[directory]["Passed"] = append(reportByDirectory[directory]["Passed"], report) + } + } else if reportByDirectory[directory] == nil { + reportByDirectory[directory] = make(map[string][]reporter.Report) + reportByDirectory[directory]["Failed"] = []reporter.Report{report} + } else if reportByDirectory[directory] != nil && reportByDirectory[directory]["Failed"] == nil { + reportByDirectory[directory]["Failed"] = []reporter.Report{report} + } else if reportByDirectory[directory] != nil && reportByDirectory[directory]["Failed"] != nil { + reportByDirectory[directory]["Failed"] = append(reportByDirectory[directory]["Failed"], report) + } + } + + return reportByDirectory +} + +// Group Reports by Directory and File Extension +func GroupByDirectoryFile(reports []reporter.Report) map[string]map[string][]reporter.Report { + reportByDirectory := make(map[string]map[string][]reporter.Report) + + for _, report := range reports { + directoryPath := strings.Split(report.FilePath, "/") + directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") + directory = directory + "/" + fileExtension := strings.Split(report.FileName, ".")[1] + + if fileExtension == "yml" { + fileExtension = "yaml" + } + if reportByDirectory[directory] == nil { + reportByDirectory[directory] = make(map[string][]reporter.Report) + reportByDirectory[directory][fileExtension] = []reporter.Report{report} + } else if reportByDirectory[directory] != nil && reportByDirectory[directory][fileExtension] == nil { + reportByDirectory[directory][fileExtension] = []reporter.Report{report} + } else if reportByDirectory[directory][fileExtension] != nil { + reportByDirectory[directory][fileExtension] = append(reportByDirectory[directory][fileExtension], report) + } + + } + + return reportByDirectory +} + +func GroupByDouble(reports []reporter.Report, groupBy []string) map[string]map[string][]reporter.Report { + var groupReport map[string]map[string][]reporter.Report + + switch { + case groupBy[0] == "pass-fail" && groupBy[1] == "filetype": + groupReport = GroupByPassFailFile(reports) + case groupBy[0] == "pass-fail" && groupBy[1] == "directory": + groupReport = GroupByPassFailDirectory(reports) + case groupBy[0] == "filetype" && groupBy[1] == "directory": + groupReport = GroupByFileDirectory(reports) + case groupBy[0] == "filetype" && groupBy[1] == "pass-fail": + groupReport = GroupByFilePassFail(reports) + case groupBy[0] == "directory" && groupBy[1] == "pass-fail": + groupReport = GroupByDirectoryPassFail(reports) + case groupBy[0] == "directory" && groupBy[1] == "filetype": + groupReport = GroupByDirectoryFile(reports) + } + + return groupReport +} diff --git a/pkg/reporter/json_reporter.go b/pkg/reporter/json_reporter.go index 56f2f6d2..9fe1af54 100644 --- a/pkg/reporter/json_reporter.go +++ b/pkg/reporter/json_reporter.go @@ -24,6 +24,11 @@ type reportJSON struct { Summary summary `json:"summary"` } +type groupReportJSON struct { + Files map[string][]reportJSON `json:"files"` + Summary summary `json:"summary"` +} + // Print implements the Reporter interface by outputting // the report content to stdout as JSON func (jr JsonReporter) Print(reports []Report) error { @@ -68,7 +73,58 @@ func (jr JsonReporter) Print(reports []Report) error { return nil } -func (jr JsonReporter) PrintGroup(reports map[string][]Report) error { - //TODO - return nil +func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report, groupOutput string) error { + groupReport := make(map[string][]fileStatus) + + for _, reports := range groupReports { + for _, r := range reports { + status := "passed" + errorStr := "" + if !r.IsValid { + status = "failed" + errorStr = r.ValidationError.Error() + } + + // Convert Windows-style file paths. + if strings.Contains(r.FilePath, "\\") { + r.FilePath = strings.ReplaceAll(r.FilePath, "\\", "/") + } + + fileStatus := fileStatus{ + Path: r.FilePath, + Status: status, + Error: errorStr, + } + + switch groupOutput { + case "filetype": + fileExtension := strings.Split(r.FileName, ".")[1] + if fileExtension == "yml" { + fileExtension = "yaml" + } + groupReport[fileExtension] = append(groupReport[fileExtension], fileStatus) + case "pass-fail": + groupReport[status] = append(groupReport[status], fileStatus) + case "directory": + directoryPath := strings.Split(r.FilePath, "/") + directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") + directory = directory + "/" + groupReport[directory] = append(groupReport[directory], fileStatus) + groupReport[directory] = append(groupReport[directory], fileStatus) + } + } + } + + jsonBytes, err := json.MarshalIndent(groupReport, "", " ") + if err != nil { + return err + } + fmt.Println(string(jsonBytes)) + + return nil +} + +func (jr JsonReporter) PrintDoubleGroup(reports map[string]map[string][]Report) error { + //TODO + return nil } diff --git a/pkg/reporter/reporter.go b/pkg/reporter/reporter.go index e92016ec..49d5dae0 100644 --- a/pkg/reporter/reporter.go +++ b/pkg/reporter/reporter.go @@ -16,5 +16,6 @@ type Report struct { // files, etc type Reporter interface { Print(reports []Report) error - PrintGroup(reports map[string][]Report) error + PrintSingleGroup(map[string][]Report, string) error + PrintDoubleGroup(map[string]map[string][]Report) error } diff --git a/pkg/reporter/stdout_reporter.go b/pkg/reporter/stdout_reporter.go index 8537f31d..f6f5045c 100644 --- a/pkg/reporter/stdout_reporter.go +++ b/pkg/reporter/stdout_reporter.go @@ -31,9 +31,9 @@ func (sr StdoutReporter) Print(reports []Report) error { return nil } -func (sr StdoutReporter) PrintGroup(groupReports map[string][]Report) error { - for key, reports := range groupReports { - fmt.Println(key) +func (sr StdoutReporter) PrintSingleGroup(groupReport map[string][]Report, groupOutput string) error { + for group, reports := range groupReport { + fmt.Printf("%s\n", group) for _, report := range reports { if !report.IsValid { color.Set(color.FgRed) @@ -48,6 +48,26 @@ func (sr StdoutReporter) PrintGroup(groupReports map[string][]Report) error { } return nil } +func (sr StdoutReporter) PrintDoubleGroup(groupReport map[string]map[string][]Report) error { + for group, subGroup := range groupReport { + fmt.Printf("%s\n", group) + for subGroup, reports := range subGroup { + fmt.Printf(" %s\n", subGroup) + for _, report := range reports { + if !report.IsValid { + color.Set(color.FgRed) + fmt.Println(" × " + report.FilePath) + paddedString := sr.padErrorString(report.ValidationError.Error()) + fmt.Printf(" error: %v\n", paddedString) + color.Unset() + } else { + color.Green(" ✓ " + report.FilePath) + } + } + } + } + return nil +} // padErrorString adds padding to every newline in the error // string, except the first line and removes any trailing newlines From 0aa37a3ff734229aa6d10f0f82ef0bd10166d746 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Wed, 22 Nov 2023 09:28:56 -0800 Subject: [PATCH 24/48] Implement Single Groupby JSON Implement the JSON output for a single groupby call --- pkg/reporter/json_reporter.go | 39 ++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/pkg/reporter/json_reporter.go b/pkg/reporter/json_reporter.go index 9fe1af54..4e38a938 100644 --- a/pkg/reporter/json_reporter.go +++ b/pkg/reporter/json_reporter.go @@ -25,7 +25,7 @@ type reportJSON struct { } type groupReportJSON struct { - Files map[string][]reportJSON `json:"files"` + Files map[string][]fileStatus `json:"files"` Summary summary `json:"summary"` } @@ -74,7 +74,7 @@ func (jr JsonReporter) Print(reports []Report) error { } func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report, groupOutput string) error { - groupReport := make(map[string][]fileStatus) + var groupReport groupReportJSON for _, reports := range groupReports { for _, r := range reports { @@ -90,7 +90,7 @@ func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report, groupO r.FilePath = strings.ReplaceAll(r.FilePath, "\\", "/") } - fileStatus := fileStatus{ + file := fileStatus{ Path: r.FilePath, Status: status, Error: errorStr, @@ -102,15 +102,40 @@ func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report, groupO if fileExtension == "yml" { fileExtension = "yaml" } - groupReport[fileExtension] = append(groupReport[fileExtension], fileStatus) + if groupReport.Files == nil { + groupReport.Files = make(map[string][]fileStatus) + groupReport.Files[fileExtension] = []fileStatus{file} + } else { + groupReport.Files[fileExtension] = append(groupReport.Files[fileExtension], file) + } case "pass-fail": - groupReport[status] = append(groupReport[status], fileStatus) + if groupReport.Files == nil { + groupReport.Files = make(map[string][]fileStatus) + groupReport.Files[status] = []fileStatus{file} + } else { + groupReport.Files[status] = append(groupReport.Files[status], file) + } case "directory": directoryPath := strings.Split(r.FilePath, "/") directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") directory = directory + "/" - groupReport[directory] = append(groupReport[directory], fileStatus) - groupReport[directory] = append(groupReport[directory], fileStatus) + if groupReport.Files == nil { + groupReport.Files = make(map[string][]fileStatus) + groupReport.Files[directory] = []fileStatus{file} + } else { + groupReport.Files[directory] = append(groupReport.Files[directory], file) + } + } + } + } + groupReport.Summary.Passed = 0 + groupReport.Summary.Failed = 0 + for _, files := range groupReport.Files { + for _, f := range files { + if f.Status == "passed" { + groupReport.Summary.Passed++ + } else { + groupReport.Summary.Failed++ } } } From 64acf60a646d358411af36fc487d9a48601b2c10 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Wed, 22 Nov 2023 12:28:47 -0800 Subject: [PATCH 25/48] Refactor GroupBy Refactored groupBy when 2 values are passed --- pkg/cli/cli.go | 17 ++- pkg/cli/group_output.go | 7 +- pkg/cli/group_output_test.go | 3 + pkg/cli/group_output_two.go | 233 ++++++------------------------- pkg/cli/group_output_two_test.go | 3 + pkg/reporter/json_reporter.go | 182 +++++++++++++++++++++++- pkg/reporter/reporter.go | 2 +- pkg/reporter/stdout_reporter.go | 3 +- 8 files changed, 246 insertions(+), 204 deletions(-) create mode 100644 pkg/cli/group_output_test.go create mode 100644 pkg/cli/group_output_two_test.go diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index 8e95f71b..ba5cdac0 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -97,17 +97,22 @@ func (c CLI) Run() (int, error) { } // Group the output if the user specified a group by option - // The length of GroupOutput is 1 even when empty. - // Need to review this but it works for now. + // TODO: The length of GroupOutput is 1 even when empty. + // Need to review this but it works for now. if GroupOutput[0] != "" { if len(GroupOutput) == 1 { - reportGroup := GroupBySingle(reports, GroupOutput) + reportGroup, err := GroupBySingle(reports, GroupOutput) + if err != nil { + return 1, fmt.Errorf("unable to group by single: %v", err) + } c.Reporter.PrintSingleGroup(reportGroup, GroupOutput[0]) } else if len(GroupOutput) == 2 { - reportGroup := GroupByDouble(reports, GroupOutput) - c.Reporter.PrintDoubleGroup(reportGroup) + reportGroup, err := GroupByDouble(reports, GroupOutput) + if err != nil { + return 1, fmt.Errorf("unable to group by double: %v", err) + } + c.Reporter.PrintDoubleGroup(reportGroup, GroupOutput) } - } else { c.Reporter.Print(reports) } diff --git a/pkg/cli/group_output.go b/pkg/cli/group_output.go index 7c728cef..a65d89c0 100644 --- a/pkg/cli/group_output.go +++ b/pkg/cli/group_output.go @@ -1,6 +1,7 @@ package cli import ( + "fmt" "strings" "github.com/Boeing/config-file-validator/pkg/reporter" @@ -65,7 +66,7 @@ func GroupByDirectory(reports []reporter.Report) map[string][]reporter.Report { return reportByDirectory } -func GroupBySingle(reports []reporter.Report, groupBy []string) map[string][]reporter.Report { +func GroupBySingle(reports []reporter.Report, groupBy []string) (map[string][]reporter.Report, error) { var groupReport map[string][]reporter.Report @@ -77,7 +78,9 @@ func GroupBySingle(reports []reporter.Report, groupBy []string) map[string][]rep groupReport = GroupByFile(reports) case "directory": groupReport = GroupByDirectory(reports) + default: + return nil, fmt.Errorf("unable to group by %s", groupBy[i]) } } - return groupReport + return groupReport, nil } diff --git a/pkg/cli/group_output_test.go b/pkg/cli/group_output_test.go new file mode 100644 index 00000000..e19fc2d0 --- /dev/null +++ b/pkg/cli/group_output_test.go @@ -0,0 +1,3 @@ +package cli + +// TODO: Add tests diff --git a/pkg/cli/group_output_two.go b/pkg/cli/group_output_two.go index e1180e28..60d3c700 100644 --- a/pkg/cli/group_output_two.go +++ b/pkg/cli/group_output_two.go @@ -1,200 +1,53 @@ package cli import ( - "strings" + "errors" "github.com/Boeing/config-file-validator/pkg/reporter" ) -// Group Reports by Pass-Fail and File Extension -func GroupByPassFailFile(reports []reporter.Report) map[string]map[string][]reporter.Report { - reportByPassOrFail := make(map[string]map[string][]reporter.Report) - - for _, report := range reports { - fileExtension := strings.Split(report.FileName, ".")[1] - if report.IsValid { - if reportByPassOrFail["Passed"] == nil { - reportByPassOrFail["Passed"] = make(map[string][]reporter.Report) - reportByPassOrFail["Passed"][fileExtension] = []reporter.Report{report} - } else if reportByPassOrFail["Passed"] != nil && reportByPassOrFail["Passed"][fileExtension] == nil { - reportByPassOrFail["Passed"][fileExtension] = []reporter.Report{report} - } else if reportByPassOrFail["Passed"] != nil && reportByPassOrFail["Passed"][fileExtension] != nil { - reportByPassOrFail["Passed"][fileExtension] = append(reportByPassOrFail["Passed"][fileExtension], report) - } - } else { - if reportByPassOrFail["Failed"] == nil { - reportByPassOrFail["Failed"] = make(map[string][]reporter.Report) - reportByPassOrFail["Failed"][fileExtension] = []reporter.Report{report} - } else if reportByPassOrFail["Failed"] != nil && reportByPassOrFail["Failed"][fileExtension] == nil { - reportByPassOrFail["Failed"][fileExtension] = []reporter.Report{report} - } else if reportByPassOrFail["Failed"] != nil && reportByPassOrFail["Failed"][fileExtension] != nil { - reportByPassOrFail["Failed"][fileExtension] = append(reportByPassOrFail["Failed"][fileExtension], report) - } - } - } - return reportByPassOrFail -} - -// Group Reports by Pass-Fail and Directory -func GroupByPassFailDirectory(reports []reporter.Report) map[string]map[string][]reporter.Report { - reportByPassOrFail := make(map[string]map[string][]reporter.Report) - - for _, report := range reports { - directoryPath := strings.Split(report.FilePath, "/") - directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") - directory = directory + "/" - - if report.IsValid { - if reportByPassOrFail["Passed"] == nil { - reportByPassOrFail["Passed"] = make(map[string][]reporter.Report) - reportByPassOrFail["Passed"][directory] = []reporter.Report{report} - } else if reportByPassOrFail["Passed"] != nil && reportByPassOrFail["Passed"][directory] == nil { - reportByPassOrFail["Passed"][directory] = []reporter.Report{report} - } else if reportByPassOrFail["Passed"] != nil && reportByPassOrFail["Passed"][directory] != nil { - reportByPassOrFail["Passed"][directory] = append(reportByPassOrFail["Passed"][directory], report) - } - } else if reportByPassOrFail["Failed"] == nil && reportByPassOrFail["Failed"][directory] == nil { - reportByPassOrFail["Failed"] = make(map[string][]reporter.Report) - reportByPassOrFail["Failed"][directory] = []reporter.Report{report} - } else if reportByPassOrFail["Failed"] != nil && reportByPassOrFail["Failed"][directory] == nil { - reportByPassOrFail["Failed"][directory] = []reporter.Report{report} - } else if reportByPassOrFail["Failed"] != nil && reportByPassOrFail["Failed"][directory] != nil { - reportByPassOrFail["Failed"][directory] = append(reportByPassOrFail["Failed"][directory], report) - } - - } - - return reportByPassOrFail -} - -// Group Reports by File Extension and Directory -func GroupByFileDirectory(reports []reporter.Report) map[string]map[string][]reporter.Report { - reportByFile := make(map[string]map[string][]reporter.Report) - - for _, report := range reports { - directoryPath := strings.Split(report.FilePath, "/") - directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") - directory = directory + "/" - fileExtension := strings.Split(report.FileName, ".")[1] - if fileExtension == "yml" { - fileExtension = "yaml" - } - if reportByFile[fileExtension] == nil { - reportByFile[fileExtension] = make(map[string][]reporter.Report) - reportByFile[fileExtension][directory] = []reporter.Report{report} - } else if reportByFile[fileExtension] != nil && reportByFile[fileExtension][directory] == nil { - reportByFile[fileExtension][directory] = []reporter.Report{report} - } else if reportByFile[fileExtension] != nil && reportByFile[fileExtension][directory] != nil { - reportByFile[fileExtension][directory] = append(reportByFile[fileExtension][directory], report) - } - } - return reportByFile -} - -// Group Reports by File Extension and Pass-Fail -func GroupByFilePassFail(reports []reporter.Report) map[string]map[string][]reporter.Report { - reportByFile := make(map[string]map[string][]reporter.Report) - - for _, report := range reports { - fileExtension := strings.Split(report.FileName, ".")[1] - if fileExtension == "yml" { - fileExtension = "yaml" - } - if reportByFile[fileExtension] == nil && report.IsValid { - reportByFile[fileExtension] = make(map[string][]reporter.Report) - reportByFile[fileExtension]["Passed"] = []reporter.Report{report} - } else if reportByFile[fileExtension] != nil && reportByFile[fileExtension]["Passed"] == nil && report.IsValid { - reportByFile[fileExtension]["Passed"] = []reporter.Report{report} - } else if reportByFile[fileExtension] != nil && reportByFile[fileExtension]["Passed"] != nil && report.IsValid { - reportByFile[fileExtension]["Passed"] = append(reportByFile[fileExtension]["Passed"], report) - } else if reportByFile[fileExtension] == nil && !report.IsValid { - reportByFile = make(map[string]map[string][]reporter.Report) - reportByFile[fileExtension]["Failed"] = []reporter.Report{report} - } else if reportByFile[fileExtension] != nil && reportByFile[fileExtension]["Failed"] == nil && !report.IsValid { - reportByFile[fileExtension]["Failed"] = []reporter.Report{report} - } else if reportByFile[fileExtension] != nil && reportByFile[fileExtension]["Failed"] != nil && !report.IsValid { - reportByFile[fileExtension]["Failed"] = append(reportByFile[fileExtension]["Failed"], report) - } - - } - - return reportByFile -} - -// Group Reports by Directory and Pass-Fail -func GroupByDirectoryPassFail(reports []reporter.Report) map[string]map[string][]reporter.Report { - reportByDirectory := make(map[string]map[string][]reporter.Report) - for _, report := range reports { - directoryPath := strings.Split(report.FilePath, "/") - directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") - directory = directory + "/" - - if report.IsValid { - if reportByDirectory[directory] == nil { - reportByDirectory[directory] = make(map[string][]reporter.Report) - reportByDirectory[directory]["Passed"] = []reporter.Report{report} - } else if reportByDirectory[directory] != nil && reportByDirectory[directory]["Passed"] == nil { - reportByDirectory[directory]["Passed"] = []reporter.Report{report} - } else if reportByDirectory[directory] != nil && reportByDirectory[directory]["Passed"] != nil { - reportByDirectory[directory]["Passed"] = append(reportByDirectory[directory]["Passed"], report) - } - } else if reportByDirectory[directory] == nil { - reportByDirectory[directory] = make(map[string][]reporter.Report) - reportByDirectory[directory]["Failed"] = []reporter.Report{report} - } else if reportByDirectory[directory] != nil && reportByDirectory[directory]["Failed"] == nil { - reportByDirectory[directory]["Failed"] = []reporter.Report{report} - } else if reportByDirectory[directory] != nil && reportByDirectory[directory]["Failed"] != nil { - reportByDirectory[directory]["Failed"] = append(reportByDirectory[directory]["Failed"], report) - } - } - - return reportByDirectory -} - -// Group Reports by Directory and File Extension -func GroupByDirectoryFile(reports []reporter.Report) map[string]map[string][]reporter.Report { - reportByDirectory := make(map[string]map[string][]reporter.Report) - - for _, report := range reports { - directoryPath := strings.Split(report.FilePath, "/") - directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") - directory = directory + "/" - fileExtension := strings.Split(report.FileName, ".")[1] - - if fileExtension == "yml" { - fileExtension = "yaml" - } - if reportByDirectory[directory] == nil { - reportByDirectory[directory] = make(map[string][]reporter.Report) - reportByDirectory[directory][fileExtension] = []reporter.Report{report} - } else if reportByDirectory[directory] != nil && reportByDirectory[directory][fileExtension] == nil { - reportByDirectory[directory][fileExtension] = []reporter.Report{report} - } else if reportByDirectory[directory][fileExtension] != nil { - reportByDirectory[directory][fileExtension] = append(reportByDirectory[directory][fileExtension], report) - } - - } - - return reportByDirectory -} - -func GroupByDouble(reports []reporter.Report, groupBy []string) map[string]map[string][]reporter.Report { - var groupReport map[string]map[string][]reporter.Report - - switch { - case groupBy[0] == "pass-fail" && groupBy[1] == "filetype": - groupReport = GroupByPassFailFile(reports) - case groupBy[0] == "pass-fail" && groupBy[1] == "directory": - groupReport = GroupByPassFailDirectory(reports) - case groupBy[0] == "filetype" && groupBy[1] == "directory": - groupReport = GroupByFileDirectory(reports) - case groupBy[0] == "filetype" && groupBy[1] == "pass-fail": - groupReport = GroupByFilePassFail(reports) - case groupBy[0] == "directory" && groupBy[1] == "pass-fail": - groupReport = GroupByDirectoryPassFail(reports) - case groupBy[0] == "directory" && groupBy[1] == "filetype": - groupReport = GroupByDirectoryFile(reports) +func GroupByDouble(reports []reporter.Report, groupBy []string) (map[string]map[string][]reporter.Report, error) { + groupReport := make(map[string]map[string][]reporter.Report) + + if groupBy[0] == "pass-fail" && groupBy[1] == "filetype" { + passFail := GroupByPassFail(reports) + for key := range passFail { + groupReport[key] = make(map[string][]reporter.Report) + groupReport[key] = GroupByFile(passFail[key]) + } + } else if groupBy[0] == "pass-fail" && groupBy[1] == "directory" { + passFail := GroupByPassFail(reports) + for key := range passFail { + groupReport[key] = make(map[string][]reporter.Report) + groupReport[key] = GroupByDirectory(passFail[key]) + } + } else if groupBy[0] == "filetype" && groupBy[1] == "pass-fail" { + fileType := GroupByFile(reports) + for key := range fileType { + groupReport[key] = make(map[string][]reporter.Report) + groupReport[key] = GroupByPassFail(fileType[key]) + } + } else if groupBy[0] == "filetype" && groupBy[1] == "directory" { + fileType := GroupByFile(reports) + for key := range fileType { + groupReport[key] = make(map[string][]reporter.Report) + groupReport[key] = GroupByDirectory(fileType[key]) + } + } else if groupBy[0] == "directory" && groupBy[1] == "pass-fail" { + directory := GroupByDirectory(reports) + for key := range directory { + groupReport[key] = make(map[string][]reporter.Report) + groupReport[key] = GroupByPassFail(directory[key]) + } + } else if groupBy[0] == "directory" && groupBy[1] == "filetype" { + directory := GroupByDirectory(reports) + for key := range directory { + groupReport[key] = make(map[string][]reporter.Report) + groupReport[key] = GroupByFile(directory[key]) + } + } else { + return nil, errors.New("Invalid group by option") } - return groupReport + return groupReport, nil } diff --git a/pkg/cli/group_output_two_test.go b/pkg/cli/group_output_two_test.go new file mode 100644 index 00000000..e19fc2d0 --- /dev/null +++ b/pkg/cli/group_output_two_test.go @@ -0,0 +1,3 @@ +package cli + +// TODO: Add tests diff --git a/pkg/reporter/json_reporter.go b/pkg/reporter/json_reporter.go index 4e38a938..1af2262b 100644 --- a/pkg/reporter/json_reporter.go +++ b/pkg/reporter/json_reporter.go @@ -24,11 +24,16 @@ type reportJSON struct { Summary summary `json:"summary"` } -type groupReportJSON struct { +type singleGroupReportJSON struct { Files map[string][]fileStatus `json:"files"` Summary summary `json:"summary"` } +type doubleGroupReportJSON struct { + Files map[string]map[string][]fileStatus `json:"files"` + Summary summary `json:"summary"` +} + // Print implements the Reporter interface by outputting // the report content to stdout as JSON func (jr JsonReporter) Print(reports []Report) error { @@ -74,7 +79,7 @@ func (jr JsonReporter) Print(reports []Report) error { } func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report, groupOutput string) error { - var groupReport groupReportJSON + var groupReport singleGroupReportJSON for _, reports := range groupReports { for _, r := range reports { @@ -96,6 +101,7 @@ func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report, groupO Error: errorStr, } + // May be worthwhile to abstract this out into a function. switch groupOutput { case "filetype": fileExtension := strings.Split(r.FileName, ".")[1] @@ -125,6 +131,8 @@ func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report, groupO } else { groupReport.Files[directory] = append(groupReport.Files[directory], file) } + default: + return fmt.Errorf("Invalid group output: %s", groupOutput) } } } @@ -149,7 +157,173 @@ func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report, groupO return nil } -func (jr JsonReporter) PrintDoubleGroup(reports map[string]map[string][]Report) error { - //TODO +func (jr JsonReporter) PrintDoubleGroup(reports map[string]map[string][]Report, groupOutput []string) error { + var groupReport doubleGroupReportJSON + for _, subGroup := range reports { + for _, reports := range subGroup { + for _, r := range reports { + status := "passed" + errorStr := "" + if !r.IsValid { + status = "failed" + errorStr = r.ValidationError.Error() + } + + // Convert Windows-style file paths. + if strings.Contains(r.FilePath, "\\") { + r.FilePath = strings.ReplaceAll(r.FilePath, "\\", "/") + } + + file := fileStatus{ + Path: r.FilePath, + Status: status, + Error: errorStr, + } + // TODO: Lifetime issue. Need to fix. + err := error(nil) + groupReport, err = doubleGroupBySwitch(file, groupOutput, &groupReport, r, status) + if err != nil { + return err + } + } + } + } + + groupReport.Summary.Passed = 0 + groupReport.Summary.Failed = 0 + for _, subGroup := range groupReport.Files { + for _, files := range subGroup { + for _, f := range files { + if f.Status == "passed" { + groupReport.Summary.Passed++ + } else { + groupReport.Summary.Failed++ + } + } + } + } + + jsonBytes, err := json.MarshalIndent(groupReport, "", " ") + if err != nil { + return err + } + + fmt.Println(string(jsonBytes)) return nil } + +func doubleGroupBySwitch(file fileStatus, groupOutput []string, groupReport *doubleGroupReportJSON, r Report, status string) (doubleGroupReportJSON, error) { + switch { + case groupOutput[0] == "filetype" && groupOutput[1] == "pass-fail": + fileExtension := strings.Split(r.FileName, ".")[1] + if fileExtension == "yml" { + fileExtension = "yaml" + } + if groupReport.Files == nil { + groupReport.Files = make(map[string]map[string][]fileStatus) + groupReport.Files[fileExtension] = make(map[string][]fileStatus) + groupReport.Files[fileExtension][status] = []fileStatus{file} + } else { + if groupReport.Files[fileExtension] == nil { + groupReport.Files[fileExtension] = make(map[string][]fileStatus) + groupReport.Files[fileExtension][status] = []fileStatus{file} + } else { + groupReport.Files[fileExtension][status] = append(groupReport.Files[fileExtension][status], file) + } + } + case groupOutput[0] == "filetype" && groupOutput[1] == "directory": + fileExtension := strings.Split(r.FileName, ".")[1] + if fileExtension == "yml" { + fileExtension = "yaml" + } + directoryPath := strings.Split(r.FilePath, "/") + directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") + directory = directory + "/" + if groupReport.Files == nil { + groupReport.Files = make(map[string]map[string][]fileStatus) + groupReport.Files[fileExtension] = make(map[string][]fileStatus) + groupReport.Files[fileExtension][directory] = []fileStatus{file} + } else { + if groupReport.Files[fileExtension] == nil { + groupReport.Files[fileExtension] = make(map[string][]fileStatus) + groupReport.Files[fileExtension][directory] = []fileStatus{file} + } else { + groupReport.Files[fileExtension][directory] = append(groupReport.Files[fileExtension][directory], file) + } + } + case groupOutput[0] == "pass-fail" && groupOutput[1] == "directory": + directoryPath := strings.Split(r.FilePath, "/") + directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") + directory = directory + "/" + if groupReport.Files == nil { + groupReport.Files = make(map[string]map[string][]fileStatus) + groupReport.Files[status] = make(map[string][]fileStatus) + groupReport.Files[status][directory] = []fileStatus{file} + } else { + if groupReport.Files[status] == nil { + groupReport.Files[status] = make(map[string][]fileStatus) + groupReport.Files[status][directory] = []fileStatus{file} + } else { + groupReport.Files[status][directory] = append(groupReport.Files[status][directory], file) + } + } + case groupOutput[0] == "pass-fail" && groupOutput[1] == "filetype": + fileExtension := strings.Split(r.FileName, ".")[1] + if fileExtension == "yml" { + fileExtension = "yaml" + } + if groupReport.Files == nil { + groupReport.Files = make(map[string]map[string][]fileStatus) + groupReport.Files[status] = make(map[string][]fileStatus) + groupReport.Files[status][fileExtension] = []fileStatus{file} + } else { + if groupReport.Files[status] == nil { + groupReport.Files[status] = make(map[string][]fileStatus) + groupReport.Files[status][fileExtension] = []fileStatus{file} + } else { + groupReport.Files[status][fileExtension] = append(groupReport.Files[status][fileExtension], file) + } + } + case groupOutput[0] == "directory" && groupOutput[1] == "filetype": + fileExtension := strings.Split(r.FileName, ".")[1] + if fileExtension == "yml" { + fileExtension = "yaml" + } + directoryPath := strings.Split(r.FilePath, "/") + directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") + directory = directory + "/" + if groupReport.Files == nil { + groupReport.Files = make(map[string]map[string][]fileStatus) + groupReport.Files[directory] = make(map[string][]fileStatus) + groupReport.Files[directory][fileExtension] = []fileStatus{file} + } else { + if groupReport.Files[directory] == nil { + groupReport.Files[directory] = make(map[string][]fileStatus) + groupReport.Files[directory][fileExtension] = []fileStatus{file} + } else { + groupReport.Files[directory][fileExtension] = append(groupReport.Files[directory][fileExtension], file) + } + } + case groupOutput[0] == "directory" && groupOutput[1] == "pass-fail": + directoryPath := strings.Split(r.FilePath, "/") + directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") + directory = directory + "/" + if groupReport.Files == nil { + groupReport.Files = make(map[string]map[string][]fileStatus) + groupReport.Files[directory] = make(map[string][]fileStatus) + groupReport.Files[directory][status] = []fileStatus{file} + } else { + if groupReport.Files[directory] == nil { + groupReport.Files[directory] = make(map[string][]fileStatus) + groupReport.Files[directory][status] = []fileStatus{file} + } else { + groupReport.Files[directory][status] = append(groupReport.Files[directory][status], file) + } + } + default: + return doubleGroupReportJSON{}, fmt.Errorf("Invalid group output: %s", groupOutput) + } + + return *groupReport, nil + +} diff --git a/pkg/reporter/reporter.go b/pkg/reporter/reporter.go index 49d5dae0..b200194f 100644 --- a/pkg/reporter/reporter.go +++ b/pkg/reporter/reporter.go @@ -17,5 +17,5 @@ type Report struct { type Reporter interface { Print(reports []Report) error PrintSingleGroup(map[string][]Report, string) error - PrintDoubleGroup(map[string]map[string][]Report) error + PrintDoubleGroup(map[string]map[string][]Report, []string) error } diff --git a/pkg/reporter/stdout_reporter.go b/pkg/reporter/stdout_reporter.go index f6f5045c..c8975d51 100644 --- a/pkg/reporter/stdout_reporter.go +++ b/pkg/reporter/stdout_reporter.go @@ -48,7 +48,8 @@ func (sr StdoutReporter) PrintSingleGroup(groupReport map[string][]Report, group } return nil } -func (sr StdoutReporter) PrintDoubleGroup(groupReport map[string]map[string][]Report) error { + +func (sr StdoutReporter) PrintDoubleGroup(groupReport map[string]map[string][]Report, groupOutput []string) error { for group, subGroup := range groupReport { fmt.Printf("%s\n", group) for subGroup, reports := range subGroup { From 2429073bc51bcc58ffd78437166eaab2f0418f82 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Wed, 22 Nov 2023 13:11:38 -0800 Subject: [PATCH 26/48] Refactor GroupByTwo Refactored groupby when 2 values are passed --- pkg/cli/cli.go | 2 +- pkg/cli/group_output.go | 4 +- pkg/cli/group_output_two.go | 50 ++----- pkg/reporter/json_reporter.go | 253 +--------------------------------- 4 files changed, 17 insertions(+), 292 deletions(-) diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index ba5cdac0..7341aff2 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -101,7 +101,7 @@ func (c CLI) Run() (int, error) { // Need to review this but it works for now. if GroupOutput[0] != "" { if len(GroupOutput) == 1 { - reportGroup, err := GroupBySingle(reports, GroupOutput) + reportGroup, err := GroupBySingle(reports, GroupOutput[0]) if err != nil { return 1, fmt.Errorf("unable to group by single: %v", err) } diff --git a/pkg/cli/group_output.go b/pkg/cli/group_output.go index a65d89c0..e38a515e 100644 --- a/pkg/cli/group_output.go +++ b/pkg/cli/group_output.go @@ -66,12 +66,12 @@ func GroupByDirectory(reports []reporter.Report) map[string][]reporter.Report { return reportByDirectory } -func GroupBySingle(reports []reporter.Report, groupBy []string) (map[string][]reporter.Report, error) { +func GroupBySingle(reports []reporter.Report, groupBy string) (map[string][]reporter.Report, error) { var groupReport map[string][]reporter.Report for i := len(groupBy) - 1; i >= 0; i-- { - switch groupBy[i] { + switch groupBy { case "pass-fail": groupReport = GroupByPassFail(reports) case "filetype": diff --git a/pkg/cli/group_output_two.go b/pkg/cli/group_output_two.go index 60d3c700..9985c885 100644 --- a/pkg/cli/group_output_two.go +++ b/pkg/cli/group_output_two.go @@ -1,52 +1,24 @@ package cli import ( - "errors" - "github.com/Boeing/config-file-validator/pkg/reporter" ) +// TODO: Refactor this to be more generic + func GroupByDouble(reports []reporter.Report, groupBy []string) (map[string]map[string][]reporter.Report, error) { groupReport := make(map[string]map[string][]reporter.Report) - if groupBy[0] == "pass-fail" && groupBy[1] == "filetype" { - passFail := GroupByPassFail(reports) - for key := range passFail { - groupReport[key] = make(map[string][]reporter.Report) - groupReport[key] = GroupByFile(passFail[key]) - } - } else if groupBy[0] == "pass-fail" && groupBy[1] == "directory" { - passFail := GroupByPassFail(reports) - for key := range passFail { - groupReport[key] = make(map[string][]reporter.Report) - groupReport[key] = GroupByDirectory(passFail[key]) - } - } else if groupBy[0] == "filetype" && groupBy[1] == "pass-fail" { - fileType := GroupByFile(reports) - for key := range fileType { - groupReport[key] = make(map[string][]reporter.Report) - groupReport[key] = GroupByPassFail(fileType[key]) - } - } else if groupBy[0] == "filetype" && groupBy[1] == "directory" { - fileType := GroupByFile(reports) - for key := range fileType { - groupReport[key] = make(map[string][]reporter.Report) - groupReport[key] = GroupByDirectory(fileType[key]) - } - } else if groupBy[0] == "directory" && groupBy[1] == "pass-fail" { - directory := GroupByDirectory(reports) - for key := range directory { - groupReport[key] = make(map[string][]reporter.Report) - groupReport[key] = GroupByPassFail(directory[key]) - } - } else if groupBy[0] == "directory" && groupBy[1] == "filetype" { - directory := GroupByDirectory(reports) - for key := range directory { - groupReport[key] = make(map[string][]reporter.Report) - groupReport[key] = GroupByFile(directory[key]) + groupTopGroup, err := GroupBySingle(reports, groupBy[0]) + if err != nil { + return nil, err + } + for key := range groupTopGroup { + groupReport[key] = make(map[string][]reporter.Report) + groupReport[key], err = GroupBySingle(groupTopGroup[key], groupBy[1]) + if err != nil { + return nil, err } - } else { - return nil, errors.New("Invalid group by option") } return groupReport, nil diff --git a/pkg/reporter/json_reporter.go b/pkg/reporter/json_reporter.go index 1af2262b..d2910fe4 100644 --- a/pkg/reporter/json_reporter.go +++ b/pkg/reporter/json_reporter.go @@ -24,16 +24,6 @@ type reportJSON struct { Summary summary `json:"summary"` } -type singleGroupReportJSON struct { - Files map[string][]fileStatus `json:"files"` - Summary summary `json:"summary"` -} - -type doubleGroupReportJSON struct { - Files map[string]map[string][]fileStatus `json:"files"` - Summary summary `json:"summary"` -} - // Print implements the Reporter interface by outputting // the report content to stdout as JSON func (jr JsonReporter) Print(reports []Report) error { @@ -79,251 +69,14 @@ func (jr JsonReporter) Print(reports []Report) error { } func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report, groupOutput string) error { - var groupReport singleGroupReportJSON - - for _, reports := range groupReports { - for _, r := range reports { - status := "passed" - errorStr := "" - if !r.IsValid { - status = "failed" - errorStr = r.ValidationError.Error() - } - - // Convert Windows-style file paths. - if strings.Contains(r.FilePath, "\\") { - r.FilePath = strings.ReplaceAll(r.FilePath, "\\", "/") - } - - file := fileStatus{ - Path: r.FilePath, - Status: status, - Error: errorStr, - } - - // May be worthwhile to abstract this out into a function. - switch groupOutput { - case "filetype": - fileExtension := strings.Split(r.FileName, ".")[1] - if fileExtension == "yml" { - fileExtension = "yaml" - } - if groupReport.Files == nil { - groupReport.Files = make(map[string][]fileStatus) - groupReport.Files[fileExtension] = []fileStatus{file} - } else { - groupReport.Files[fileExtension] = append(groupReport.Files[fileExtension], file) - } - case "pass-fail": - if groupReport.Files == nil { - groupReport.Files = make(map[string][]fileStatus) - groupReport.Files[status] = []fileStatus{file} - } else { - groupReport.Files[status] = append(groupReport.Files[status], file) - } - case "directory": - directoryPath := strings.Split(r.FilePath, "/") - directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") - directory = directory + "/" - if groupReport.Files == nil { - groupReport.Files = make(map[string][]fileStatus) - groupReport.Files[directory] = []fileStatus{file} - } else { - groupReport.Files[directory] = append(groupReport.Files[directory], file) - } - default: - return fmt.Errorf("Invalid group output: %s", groupOutput) - } - } - } - groupReport.Summary.Passed = 0 - groupReport.Summary.Failed = 0 - for _, files := range groupReport.Files { - for _, f := range files { - if f.Status == "passed" { - groupReport.Summary.Passed++ - } else { - groupReport.Summary.Failed++ - } - } - } - - jsonBytes, err := json.MarshalIndent(groupReport, "", " ") - if err != nil { - return err - } - fmt.Println(string(jsonBytes)) - return nil } func (jr JsonReporter) PrintDoubleGroup(reports map[string]map[string][]Report, groupOutput []string) error { - var groupReport doubleGroupReportJSON - for _, subGroup := range reports { - for _, reports := range subGroup { - for _, r := range reports { - status := "passed" - errorStr := "" - if !r.IsValid { - status = "failed" - errorStr = r.ValidationError.Error() - } - - // Convert Windows-style file paths. - if strings.Contains(r.FilePath, "\\") { - r.FilePath = strings.ReplaceAll(r.FilePath, "\\", "/") - } - - file := fileStatus{ - Path: r.FilePath, - Status: status, - Error: errorStr, - } - // TODO: Lifetime issue. Need to fix. - err := error(nil) - groupReport, err = doubleGroupBySwitch(file, groupOutput, &groupReport, r, status) - if err != nil { - return err - } - } - } - } - - groupReport.Summary.Passed = 0 - groupReport.Summary.Failed = 0 - for _, subGroup := range groupReport.Files { - for _, files := range subGroup { - for _, f := range files { - if f.Status == "passed" { - groupReport.Summary.Passed++ - } else { - groupReport.Summary.Failed++ - } - } - } - } - - jsonBytes, err := json.MarshalIndent(groupReport, "", " ") - if err != nil { - return err - } - - fmt.Println(string(jsonBytes)) return nil } -func doubleGroupBySwitch(file fileStatus, groupOutput []string, groupReport *doubleGroupReportJSON, r Report, status string) (doubleGroupReportJSON, error) { - switch { - case groupOutput[0] == "filetype" && groupOutput[1] == "pass-fail": - fileExtension := strings.Split(r.FileName, ".")[1] - if fileExtension == "yml" { - fileExtension = "yaml" - } - if groupReport.Files == nil { - groupReport.Files = make(map[string]map[string][]fileStatus) - groupReport.Files[fileExtension] = make(map[string][]fileStatus) - groupReport.Files[fileExtension][status] = []fileStatus{file} - } else { - if groupReport.Files[fileExtension] == nil { - groupReport.Files[fileExtension] = make(map[string][]fileStatus) - groupReport.Files[fileExtension][status] = []fileStatus{file} - } else { - groupReport.Files[fileExtension][status] = append(groupReport.Files[fileExtension][status], file) - } - } - case groupOutput[0] == "filetype" && groupOutput[1] == "directory": - fileExtension := strings.Split(r.FileName, ".")[1] - if fileExtension == "yml" { - fileExtension = "yaml" - } - directoryPath := strings.Split(r.FilePath, "/") - directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") - directory = directory + "/" - if groupReport.Files == nil { - groupReport.Files = make(map[string]map[string][]fileStatus) - groupReport.Files[fileExtension] = make(map[string][]fileStatus) - groupReport.Files[fileExtension][directory] = []fileStatus{file} - } else { - if groupReport.Files[fileExtension] == nil { - groupReport.Files[fileExtension] = make(map[string][]fileStatus) - groupReport.Files[fileExtension][directory] = []fileStatus{file} - } else { - groupReport.Files[fileExtension][directory] = append(groupReport.Files[fileExtension][directory], file) - } - } - case groupOutput[0] == "pass-fail" && groupOutput[1] == "directory": - directoryPath := strings.Split(r.FilePath, "/") - directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") - directory = directory + "/" - if groupReport.Files == nil { - groupReport.Files = make(map[string]map[string][]fileStatus) - groupReport.Files[status] = make(map[string][]fileStatus) - groupReport.Files[status][directory] = []fileStatus{file} - } else { - if groupReport.Files[status] == nil { - groupReport.Files[status] = make(map[string][]fileStatus) - groupReport.Files[status][directory] = []fileStatus{file} - } else { - groupReport.Files[status][directory] = append(groupReport.Files[status][directory], file) - } - } - case groupOutput[0] == "pass-fail" && groupOutput[1] == "filetype": - fileExtension := strings.Split(r.FileName, ".")[1] - if fileExtension == "yml" { - fileExtension = "yaml" - } - if groupReport.Files == nil { - groupReport.Files = make(map[string]map[string][]fileStatus) - groupReport.Files[status] = make(map[string][]fileStatus) - groupReport.Files[status][fileExtension] = []fileStatus{file} - } else { - if groupReport.Files[status] == nil { - groupReport.Files[status] = make(map[string][]fileStatus) - groupReport.Files[status][fileExtension] = []fileStatus{file} - } else { - groupReport.Files[status][fileExtension] = append(groupReport.Files[status][fileExtension], file) - } - } - case groupOutput[0] == "directory" && groupOutput[1] == "filetype": - fileExtension := strings.Split(r.FileName, ".")[1] - if fileExtension == "yml" { - fileExtension = "yaml" - } - directoryPath := strings.Split(r.FilePath, "/") - directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") - directory = directory + "/" - if groupReport.Files == nil { - groupReport.Files = make(map[string]map[string][]fileStatus) - groupReport.Files[directory] = make(map[string][]fileStatus) - groupReport.Files[directory][fileExtension] = []fileStatus{file} - } else { - if groupReport.Files[directory] == nil { - groupReport.Files[directory] = make(map[string][]fileStatus) - groupReport.Files[directory][fileExtension] = []fileStatus{file} - } else { - groupReport.Files[directory][fileExtension] = append(groupReport.Files[directory][fileExtension], file) - } - } - case groupOutput[0] == "directory" && groupOutput[1] == "pass-fail": - directoryPath := strings.Split(r.FilePath, "/") - directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") - directory = directory + "/" - if groupReport.Files == nil { - groupReport.Files = make(map[string]map[string][]fileStatus) - groupReport.Files[directory] = make(map[string][]fileStatus) - groupReport.Files[directory][status] = []fileStatus{file} - } else { - if groupReport.Files[directory] == nil { - groupReport.Files[directory] = make(map[string][]fileStatus) - groupReport.Files[directory][status] = []fileStatus{file} - } else { - groupReport.Files[directory][status] = append(groupReport.Files[directory][status], file) - } - } - default: - return doubleGroupReportJSON{}, fmt.Errorf("Invalid group output: %s", groupOutput) - } - - return *groupReport, nil - +// Need to create a map of file status groups +func createFileStatusGroups(reports map[string]Report, groupOutput string) map[string][]reportJSON { + return nil } From 306097126eb7bb266f70264c03806e149389068b Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Wed, 22 Nov 2023 14:06:15 -0800 Subject: [PATCH 27/48] Update to Stdout Update to standard out print --- pkg/cli/group_output.go | 41 +++++++++++++++++++++++++++++--- pkg/cli/group_output_two.go | 25 ------------------- pkg/cli/group_output_two_test.go | 3 --- pkg/reporter/stdout_reporter.go | 36 ++++++++++++++++++++++++---- 4 files changed, 70 insertions(+), 35 deletions(-) delete mode 100644 pkg/cli/group_output_two.go delete mode 100644 pkg/cli/group_output_two_test.go diff --git a/pkg/cli/group_output.go b/pkg/cli/group_output.go index e38a515e..a37795ef 100644 --- a/pkg/cli/group_output.go +++ b/pkg/cli/group_output.go @@ -67,7 +67,6 @@ func GroupByDirectory(reports []reporter.Report) map[string][]reporter.Report { } func GroupBySingle(reports []reporter.Report, groupBy string) (map[string][]reporter.Report, error) { - var groupReport map[string][]reporter.Report for i := len(groupBy) - 1; i >= 0; i-- { @@ -78,9 +77,45 @@ func GroupBySingle(reports []reporter.Report, groupBy string) (map[string][]repo groupReport = GroupByFile(reports) case "directory": groupReport = GroupByDirectory(reports) - default: - return nil, fmt.Errorf("unable to group by %s", groupBy[i]) + default: + return nil, fmt.Errorf("unable to group by %s", groupBy) } } return groupReport, nil } + +func GroupByDouble(reports []reporter.Report, groupBy []string) (map[string]map[string][]reporter.Report, error) { + groupReport := make(map[string]map[string][]reporter.Report) + + firstGroup, err := GroupBySingle(reports, groupBy[0]) + if err != nil { + return nil, err + } + for key := range firstGroup { + groupReport[key] = make(map[string][]reporter.Report) + groupReport[key], err = GroupBySingle(firstGroup[key], groupBy[1]) + if err != nil { + return nil, err + } + } + + return groupReport, nil +} + +func GroupByTriple(reports []reporter.Report, groupBy []string) (map[string]map[string]map[string][]reporter.Report, error) { + groupReport := make(map[string]map[string]map[string][]reporter.Report) + + firstGroup, err := GroupBySingle(reports, groupBy[0]) + if err != nil { + return nil, err + } + for key := range firstGroup { + groupReport[key] = make(map[string]map[string][]reporter.Report) + groupReport[key], err = GroupByDouble(firstGroup[key], groupBy[1:]) + if err != nil { + return nil, err + } + } + + return groupReport, nil +} diff --git a/pkg/cli/group_output_two.go b/pkg/cli/group_output_two.go deleted file mode 100644 index 9985c885..00000000 --- a/pkg/cli/group_output_two.go +++ /dev/null @@ -1,25 +0,0 @@ -package cli - -import ( - "github.com/Boeing/config-file-validator/pkg/reporter" -) - -// TODO: Refactor this to be more generic - -func GroupByDouble(reports []reporter.Report, groupBy []string) (map[string]map[string][]reporter.Report, error) { - groupReport := make(map[string]map[string][]reporter.Report) - - groupTopGroup, err := GroupBySingle(reports, groupBy[0]) - if err != nil { - return nil, err - } - for key := range groupTopGroup { - groupReport[key] = make(map[string][]reporter.Report) - groupReport[key], err = GroupBySingle(groupTopGroup[key], groupBy[1]) - if err != nil { - return nil, err - } - } - - return groupReport, nil -} diff --git a/pkg/cli/group_output_two_test.go b/pkg/cli/group_output_two_test.go deleted file mode 100644 index e19fc2d0..00000000 --- a/pkg/cli/group_output_two_test.go +++ /dev/null @@ -1,3 +0,0 @@ -package cli - -// TODO: Add tests diff --git a/pkg/reporter/stdout_reporter.go b/pkg/reporter/stdout_reporter.go index c8975d51..ad67d2f6 100644 --- a/pkg/reporter/stdout_reporter.go +++ b/pkg/reporter/stdout_reporter.go @@ -32,8 +32,14 @@ func (sr StdoutReporter) Print(reports []Report) error { } func (sr StdoutReporter) PrintSingleGroup(groupReport map[string][]Report, groupOutput string) error { + var successCount = 0 + var failureCount = 0 + var totalSuccessCount = 0 + var totalFailureCount = 0 for group, reports := range groupReport { fmt.Printf("%s\n", group) + successCount = 0 + failureCount = 0 for _, report := range reports { if !report.IsValid { color.Set(color.FgRed) @@ -41,32 +47,54 @@ func (sr StdoutReporter) PrintSingleGroup(groupReport map[string][]Report, group paddedString := sr.padErrorString(report.ValidationError.Error()) fmt.Printf(" error: %v\n", paddedString) color.Unset() + failureCount = failureCount + 1 + totalFailureCount = totalFailureCount + 1 } else { color.Green(" ✓ " + report.FilePath) + successCount = successCount + 1 + totalSuccessCount = totalSuccessCount + 1 } } + fmt.Printf("Summary: %d succeeded, %d failed\n\n", successCount, failureCount) } + + fmt.Printf("Total Summary: %d succeeded, %d failed\n", totalSuccessCount, totalFailureCount) return nil } func (sr StdoutReporter) PrintDoubleGroup(groupReport map[string]map[string][]Report, groupOutput []string) error { - for group, subGroup := range groupReport { + var successCount = 0 + var failureCount = 0 + var totalSuccessCount = 0 + var totalFailureCount = 0 + + for group, reports := range groupReport { fmt.Printf("%s\n", group) - for subGroup, reports := range subGroup { - fmt.Printf(" %s\n", subGroup) - for _, report := range reports { + for group2, reports2 := range reports { + fmt.Printf(" %s\n", group2) + successCount = 0 + failureCount = 0 + for _, report := range reports2 { if !report.IsValid { color.Set(color.FgRed) fmt.Println(" × " + report.FilePath) paddedString := sr.padErrorString(report.ValidationError.Error()) fmt.Printf(" error: %v\n", paddedString) color.Unset() + failureCount = failureCount + 1 + totalFailureCount = totalFailureCount + 1 } else { color.Green(" ✓ " + report.FilePath) + successCount = successCount + 1 + totalSuccessCount = totalSuccessCount + 1 } } + fmt.Printf(" Summary: %d succeeded, %d failed\n\n", successCount, failureCount) } } + + fmt.Printf("Total Summary: %d succeeded, %d failed\n", totalSuccessCount, totalFailureCount) + return nil } From 16e341a89aca18aa41e8b346312c46111684e20d Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Wed, 22 Nov 2023 16:29:43 -0800 Subject: [PATCH 28/48] Implement JSON single group Implement output for JSON when single group is passed --- pkg/cli/cli.go | 6 ++- pkg/cli/cli_test.go | 6 +-- pkg/cli/group_output_test.go | 2 + pkg/reporter/json_reporter.go | 68 +++++++++++++++++++++++++++++++++ pkg/reporter/stdout_reporter.go | 7 +++- 5 files changed, 82 insertions(+), 7 deletions(-) diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index 7341aff2..671b90ae 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -8,6 +8,8 @@ import ( "github.com/Boeing/config-file-validator/pkg/reporter" ) +// GroupOutput is a global variable that is used to +// store the group by options that the user specifies var GroupOutput []string type CLI struct { @@ -97,8 +99,8 @@ func (c CLI) Run() (int, error) { } // Group the output if the user specified a group by option - // TODO: The length of GroupOutput is 1 even when empty. - // Need to review this but it works for now. + // Causing panic during tests + if GroupOutput[0] != "" { if len(GroupOutput) == 1 { reportGroup, err := GroupBySingle(reports, GroupOutput[0]) diff --git a/pkg/cli/cli_test.go b/pkg/cli/cli_test.go index dbd810af..7ffe4467 100644 --- a/pkg/cli/cli_test.go +++ b/pkg/cli/cli_test.go @@ -10,7 +10,7 @@ import ( func Test_CLI(t *testing.T) { searchPath := "../../test" excludeDirs := []string{"subdir", "subdir2"} - groupBy := []string{} + groupOutput := []string{""} stdoutReporter := reporter.StdoutReporter{} fsFinder := finder.FileSystemFinderInit( @@ -20,7 +20,7 @@ func Test_CLI(t *testing.T) { cli := Init( WithFinder(fsFinder), WithReporter(stdoutReporter), - WithGroupOutput(groupBy), + WithGroupOutput(groupOutput), ) exitStatus, err := cli.Run() @@ -76,7 +76,7 @@ func Test_CLIBadPath(t *testing.T) { func Test_CLIWithGroup(t *testing.T) { searchPath := "../../test" excludeDirs := []string{"subdir", "subdir2"} - groupOutput := []string{"pass-fail", "directory", "filetype"} + groupOutput := []string{"pass-fail", "directory"} stdoutReporter := reporter.StdoutReporter{} fsFinder := finder.FileSystemFinderInit( diff --git a/pkg/cli/group_output_test.go b/pkg/cli/group_output_test.go index e19fc2d0..ed822337 100644 --- a/pkg/cli/group_output_test.go +++ b/pkg/cli/group_output_test.go @@ -1,3 +1,5 @@ package cli // TODO: Add tests + + diff --git a/pkg/reporter/json_reporter.go b/pkg/reporter/json_reporter.go index d2910fe4..3b2996d1 100644 --- a/pkg/reporter/json_reporter.go +++ b/pkg/reporter/json_reporter.go @@ -24,6 +24,13 @@ type reportJSON struct { Summary summary `json:"summary"` } +type groupReportJSON struct { + Files map[string][]fileStatus `json:"files"` + Summary map[string][]summary `json:"summary"` + TotalPassed int `json:"totalPassed"` + TotalFailed int `json:"totalFailed"` +} + // Print implements the Reporter interface by outputting // the report content to stdout as JSON func (jr JsonReporter) Print(reports []Report) error { @@ -68,11 +75,72 @@ func (jr JsonReporter) Print(reports []Report) error { return nil } +// Tried to pass the Print function to this function but it didn't work +// Header of JSON would be generic and not specific to the group +// I.e it would be "files" instead of listing the file extensions func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report, groupOutput string) error { + var report groupReportJSON + currentPassed := 0 + currentFailed := 0 + totalPassed := 0 + totalFailed := 0 + report.Files = make(map[string][]fileStatus) + report.Summary = make(map[string][]summary) + + for group, reports := range groupReports { + report.Files[group] = make([]fileStatus, 0) + report.Summary[group] = make([]summary, 0) + currentPassed = 0 + currentFailed = 0 + for _, r := range reports { + status := "passed" + errorStr := "" + if !r.IsValid { + status = "failed" + errorStr = r.ValidationError.Error() + } + + // Convert Windows-style file paths. + if strings.Contains(r.FilePath, "\\") { + r.FilePath = strings.ReplaceAll(r.FilePath, "\\", "/") + } + + report.Files[group] = append(report.Files[group], fileStatus{ + Path: r.FilePath, + Status: status, + Error: errorStr, + }) + } + + for _, f := range report.Files[group] { + if f.Status == "passed" { + currentPassed++ + totalPassed++ + } else { + currentFailed++ + totalFailed++ + } + } + report.Summary[group] = append(report.Summary[group], summary{ + Passed: currentPassed, + Failed: currentFailed, + }) + } + + report.TotalPassed = totalPassed + report.TotalFailed = totalFailed + + jsonBytes, err := json.MarshalIndent(report, "", " ") + if err != nil { + return err + } + + fmt.Println(string(jsonBytes)) return nil } func (jr JsonReporter) PrintDoubleGroup(reports map[string]map[string][]Report, groupOutput []string) error { + return nil } diff --git a/pkg/reporter/stdout_reporter.go b/pkg/reporter/stdout_reporter.go index ad67d2f6..22df976f 100644 --- a/pkg/reporter/stdout_reporter.go +++ b/pkg/reporter/stdout_reporter.go @@ -31,6 +31,9 @@ func (sr StdoutReporter) Print(reports []Report) error { return nil } +// There is repeated code in the following two functions. Trying to consolidate +// the code into one function is difficult because of the output format +// Need to investigate further func (sr StdoutReporter) PrintSingleGroup(groupReport map[string][]Report, groupOutput string) error { var successCount = 0 var failureCount = 0 @@ -55,7 +58,7 @@ func (sr StdoutReporter) PrintSingleGroup(groupReport map[string][]Report, group totalSuccessCount = totalSuccessCount + 1 } } - fmt.Printf("Summary: %d succeeded, %d failed\n\n", successCount, failureCount) + fmt.Printf(" Summary: %d succeeded, %d failed\n\n", successCount, failureCount) } fmt.Printf("Total Summary: %d succeeded, %d failed\n", totalSuccessCount, totalFailureCount) @@ -89,7 +92,7 @@ func (sr StdoutReporter) PrintDoubleGroup(groupReport map[string]map[string][]Re totalSuccessCount = totalSuccessCount + 1 } } - fmt.Printf(" Summary: %d succeeded, %d failed\n\n", successCount, failureCount) + fmt.Printf(" Summary: %d succeeded, %d failed\n\n", successCount, failureCount) } } From 01ddc540aacc90b3ad395fa97d29b68b609b28d1 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Wed, 22 Nov 2023 18:30:22 -0800 Subject: [PATCH 29/48] Implement JSON double group and tests Implemented the JSON output for when two groupbys are passed. Also added test cases in the CLI path --- pkg/cli/cli.go | 34 ++--- pkg/cli/group_output_test.go | 227 ++++++++++++++++++++++++++++++++ pkg/reporter/json_reporter.go | 73 +++++++++- pkg/reporter/reporter.go | 1 + pkg/reporter/stdout_reporter.go | 4 + 5 files changed, 320 insertions(+), 19 deletions(-) diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index 671b90ae..7ef8f897 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -99,25 +99,29 @@ func (c CLI) Run() (int, error) { } // Group the output if the user specified a group by option - // Causing panic during tests - - if GroupOutput[0] != "" { - if len(GroupOutput) == 1 { - reportGroup, err := GroupBySingle(reports, GroupOutput[0]) - if err != nil { - return 1, fmt.Errorf("unable to group by single: %v", err) - } - c.Reporter.PrintSingleGroup(reportGroup, GroupOutput[0]) - } else if len(GroupOutput) == 2 { - reportGroup, err := GroupByDouble(reports, GroupOutput) - if err != nil { - return 1, fmt.Errorf("unable to group by double: %v", err) - } - c.Reporter.PrintDoubleGroup(reportGroup, GroupOutput) + // Length is equal to one when empty as it contains an empty string + if len(GroupOutput) == 1 && GroupOutput[0] != "" { + reportGroup, err := GroupBySingle(reports, GroupOutput[0]) + if err != nil { + return 1, fmt.Errorf("unable to group by single value: %v", err) + } + c.Reporter.PrintSingleGroup(reportGroup, GroupOutput[0]) + } else if len(GroupOutput) == 2 { + reportGroup, err := GroupByDouble(reports, GroupOutput) + if err != nil { + return 1, fmt.Errorf("unable to group by double value: %v", err) } + c.Reporter.PrintDoubleGroup(reportGroup, GroupOutput) + } else if len(GroupOutput) == 3 { + reportGroup, err := GroupByTriple(reports, GroupOutput) + if err != nil { + return 1, fmt.Errorf("unable to group by triple value: %v", err) + } + c.Reporter.PrintTripleGroup(reportGroup, GroupOutput) } else { c.Reporter.Print(reports) } + if errorFound { return 1, nil } else { diff --git a/pkg/cli/group_output_test.go b/pkg/cli/group_output_test.go index ed822337..ea014206 100644 --- a/pkg/cli/group_output_test.go +++ b/pkg/cli/group_output_test.go @@ -1,5 +1,232 @@ package cli +import ( + "testing" + + "github.com/Boeing/config-file-validator/pkg/finder" + "github.com/Boeing/config-file-validator/pkg/reporter" +) + // TODO: Add tests +func Test_NoGroupOutput(t *testing.T) { + searchPath := "../../test" + excludeDirs := []string{"subdir", "subdir2"} + groupOutput := map[string][]string{ + "test": {}, + "test2": {}, + "test3": {}, + } + stdoutReporter := reporter.StdoutReporter{} + + for i := range groupOutput { + fsFinder := finder.FileSystemFinderInit( + finder.WithPathRoots(searchPath), + finder.WithExcludeDirs(excludeDirs), + ) + cli := Init( + WithFinder(fsFinder), + WithReporter(stdoutReporter), + WithGroupOutput(groupOutput[i]), + ) + exitStatus, err := cli.Run() + + if err != nil { + t.Errorf("An error was returned: %v", err) + } + + if exitStatus != 0 { + t.Errorf("Exit status was not 0") + } + } +} + +func Test_SingleGroupOutput(t *testing.T) { + searchPath := "../../test" + excludeDirs := []string{"subdir", "subdir2"} + groupOutput := map[string][]string{ + "test": {"directory"}, + "test2": {"filetype"}, + "test3": {"pass-fail"}, + } + stdoutReporter := reporter.StdoutReporter{} + + for i := range groupOutput { + fsFinder := finder.FileSystemFinderInit( + finder.WithPathRoots(searchPath), + finder.WithExcludeDirs(excludeDirs), + ) + cli := Init( + WithFinder(fsFinder), + WithReporter(stdoutReporter), + WithGroupOutput(groupOutput[i]), + ) + exitStatus, err := cli.Run() + + if err != nil { + t.Errorf("An error was returned: %v", err) + } + + if exitStatus != 0 { + t.Errorf("Exit status was not 0") + } + } +} + +func Test_DoubleGroupOutput(t *testing.T) { + searchPath := "../../test" + excludeDirs := []string{"subdir", "subdir2"} + groupOutput := map[string][]string{ + "test": {"directory", "pass-fail"}, + "test2": {"filetype", "directory"}, + "test3": {"pass-fail", "filetype"}, + } + stdoutReporter := reporter.StdoutReporter{} + + for i := range groupOutput { + fsFinder := finder.FileSystemFinderInit( + finder.WithPathRoots(searchPath), + finder.WithExcludeDirs(excludeDirs), + ) + cli := Init( + WithFinder(fsFinder), + WithReporter(stdoutReporter), + WithGroupOutput(groupOutput[i]), + ) + exitStatus, err := cli.Run() + + if err != nil { + t.Errorf("An error was returned: %v", err) + } + + if exitStatus != 0 { + t.Errorf("Exit status was not 0") + } + } +} + +func Test_TripleGroupOutput(t *testing.T) { + searchPath := "../../test" + excludeDirs := []string{"subdir", "subdir2"} + groupOutput := map[string][]string{ + "test": {"directory", "pass-fail", "filetype"}, + "test2": {"filetype", "directory", "pass-fail"}, + "test3": {"pass-fail", "filetype", "directory"}, + } + stdoutReporter := reporter.StdoutReporter{} + + for i := range groupOutput { + fsFinder := finder.FileSystemFinderInit( + finder.WithPathRoots(searchPath), + finder.WithExcludeDirs(excludeDirs), + ) + cli := Init( + WithFinder(fsFinder), + WithReporter(stdoutReporter), + WithGroupOutput(groupOutput[i]), + ) + exitStatus, err := cli.Run() + + if err != nil { + t.Errorf("An error was returned: %v", err) + } + + if exitStatus != 0 { + t.Errorf("Exit status was not 0") + } + } +} + +func Test_IncorrectSingleGroupOutput(t *testing.T) { + searchPath := "../../test" + excludeDirs := []string{"subdir", "subdir2"} + groupOutput := map[string][]string{ + "test": {"bad"}, + "test2": {"more bad"}, + "test3": {"most bad"}, + } + stdoutReporter := reporter.StdoutReporter{} + + for i := range groupOutput { + fsFinder := finder.FileSystemFinderInit( + finder.WithPathRoots(searchPath), + finder.WithExcludeDirs(excludeDirs), + ) + cli := Init( + WithFinder(fsFinder), + WithReporter(stdoutReporter), + WithGroupOutput(groupOutput[i]), + ) + exitStatus, err := cli.Run() + + if err == nil { + t.Errorf("An error was not returned") + } + + if exitStatus != 1 { + t.Errorf("Exit status was not 1") + } + } +} +func Test_IncorrectDoubleGroupOutput(t *testing.T) { + searchPath := "../../test" + excludeDirs := []string{"subdir", "subdir2"} + groupOutput := map[string][]string{ + "test": {"directory", "bad"}, + "test2": {"bad", "directory"}, + "test3": {"pass-fail", "bad"}, + } + stdoutReporter := reporter.StdoutReporter{} + + for i := range groupOutput { + fsFinder := finder.FileSystemFinderInit( + finder.WithPathRoots(searchPath), + finder.WithExcludeDirs(excludeDirs), + ) + cli := Init( + WithFinder(fsFinder), + WithReporter(stdoutReporter), + WithGroupOutput(groupOutput[i]), + ) + exitStatus, err := cli.Run() + + if err == nil { + t.Errorf("An error was not returned") + } + + if exitStatus != 1 { + t.Errorf("Exit status was not 1") + } + } +} +func Test_IncorrectTripleGroupOutput(t *testing.T) { + searchPath := "../../test" + excludeDirs := []string{"subdir", "subdir2"} + groupOutput := map[string][]string{ + "test": {"bad", "pass-fail", "filetype"}, + "test2": {"filetype", "bad", "directory"}, + "test3": {"pass-fail", "filetype", "bad"}, + } + stdoutReporter := reporter.StdoutReporter{} + + for i := range groupOutput { + fsFinder := finder.FileSystemFinderInit( + finder.WithPathRoots(searchPath), + finder.WithExcludeDirs(excludeDirs), + ) + cli := Init( + WithFinder(fsFinder), + WithReporter(stdoutReporter), + WithGroupOutput(groupOutput[i]), + ) + exitStatus, err := cli.Run() + + if err == nil { + t.Errorf("An error was not returned") + } + if exitStatus != 1 { + t.Errorf("Exit status was not 0") + } + } +} diff --git a/pkg/reporter/json_reporter.go b/pkg/reporter/json_reporter.go index 3b2996d1..0f16103c 100644 --- a/pkg/reporter/json_reporter.go +++ b/pkg/reporter/json_reporter.go @@ -31,6 +31,13 @@ type groupReportJSON struct { TotalFailed int `json:"totalFailed"` } +type doubleGroupReportJSON struct { + Files map[string]map[string][]fileStatus `json:"files"` + Summary map[string]map[string][]summary `json:"summary"` + TotalPassed int `json:"totalPassed"` + TotalFailed int `json:"totalFailed"` +} + // Print implements the Reporter interface by outputting // the report content to stdout as JSON func (jr JsonReporter) Print(reports []Report) error { @@ -139,12 +146,70 @@ func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report, groupO return nil } -func (jr JsonReporter) PrintDoubleGroup(reports map[string]map[string][]Report, groupOutput []string) error { +func (jr JsonReporter) PrintDoubleGroup(groupReports map[string]map[string][]Report, groupOutput []string) error { + var report doubleGroupReportJSON + currentPassed := 0 + currentFailed := 0 + totalPassed := 0 + totalFailed := 0 + report.Files = make(map[string]map[string][]fileStatus) + report.Summary = make(map[string]map[string][]summary) + + for group, group2 := range groupReports { + report.Files[group] = make(map[string][]fileStatus, 0) + report.Summary[group] = make(map[string][]summary, 0) + for group2, reports := range group2 { + currentPassed = 0 + currentFailed = 0 + report.Files[group][group2] = make([]fileStatus, 0) + report.Summary[group][group2] = make([]summary, 0) + for _, r := range reports { + status := "passed" + errorStr := "" + if !r.IsValid { + status = "failed" + errorStr = r.ValidationError.Error() + } + + // Convert Windows-style file paths. + if strings.Contains(r.FilePath, "\\") { + r.FilePath = strings.ReplaceAll(r.FilePath, "\\", "/") + } + + report.Files[group][group2] = append(report.Files[group][group2], fileStatus{ + Path: r.FilePath, + Status: status, + Error: errorStr, + }) + } + + for _, f := range report.Files[group][group2] { + if f.Status == "passed" { + currentPassed++ + totalPassed++ + } else { + currentFailed++ + totalFailed++ + } + } + report.Summary[group][group2] = append(report.Summary[group][group2], summary{ + Passed: currentPassed, + Failed: currentFailed, + }) + } + } + report.TotalPassed = totalPassed + report.TotalFailed = totalFailed + + jsonBytes, err := json.MarshalIndent(report, "", " ") + if err != nil { + return err + } + fmt.Println(string(jsonBytes)) return nil } -// Need to create a map of file status groups -func createFileStatusGroups(reports map[string]Report, groupOutput string) map[string][]reportJSON { - return nil +func (jr JsonReporter) PrintTripleGroup(groupReports map[string]map[string]map[string][]Report, groupOutput []string) error { + return nil } diff --git a/pkg/reporter/reporter.go b/pkg/reporter/reporter.go index b200194f..4f78b49b 100644 --- a/pkg/reporter/reporter.go +++ b/pkg/reporter/reporter.go @@ -18,4 +18,5 @@ type Reporter interface { Print(reports []Report) error PrintSingleGroup(map[string][]Report, string) error PrintDoubleGroup(map[string]map[string][]Report, []string) error + PrintTripleGroup(map[string]map[string]map[string][]Report, []string) error } diff --git a/pkg/reporter/stdout_reporter.go b/pkg/reporter/stdout_reporter.go index 22df976f..a261e3bc 100644 --- a/pkg/reporter/stdout_reporter.go +++ b/pkg/reporter/stdout_reporter.go @@ -101,6 +101,10 @@ func (sr StdoutReporter) PrintDoubleGroup(groupReport map[string]map[string][]Re return nil } +func (sr StdoutReporter) PrintTripleGroup(groupReport map[string]map[string]map[string][]Report, groupOutput []string) error { + return nil +} + // padErrorString adds padding to every newline in the error // string, except the first line and removes any trailing newlines // or spaces From d3391a13be7f4ae1e3948989249f75196cad6855 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Wed, 22 Nov 2023 18:32:49 -0800 Subject: [PATCH 30/48] Update go fmt Updated running go fmt --- pkg/cli/cli_test.go | 4 +-- pkg/cli/group_output_test.go | 56 ++++++++++++++++----------------- pkg/reporter/json_reporter.go | 32 +++++++++---------- pkg/reporter/reporter.go | 2 +- pkg/reporter/stdout_reporter.go | 2 +- 5 files changed, 48 insertions(+), 48 deletions(-) diff --git a/pkg/cli/cli_test.go b/pkg/cli/cli_test.go index 7ffe4467..3562c2c4 100644 --- a/pkg/cli/cli_test.go +++ b/pkg/cli/cli_test.go @@ -10,7 +10,7 @@ import ( func Test_CLI(t *testing.T) { searchPath := "../../test" excludeDirs := []string{"subdir", "subdir2"} - groupOutput := []string{""} + groupOutput := []string{""} stdoutReporter := reporter.StdoutReporter{} fsFinder := finder.FileSystemFinderInit( @@ -20,7 +20,7 @@ func Test_CLI(t *testing.T) { cli := Init( WithFinder(fsFinder), WithReporter(stdoutReporter), - WithGroupOutput(groupOutput), + WithGroupOutput(groupOutput), ) exitStatus, err := cli.Run() diff --git a/pkg/cli/group_output_test.go b/pkg/cli/group_output_test.go index ea014206..7b56748c 100644 --- a/pkg/cli/group_output_test.go +++ b/pkg/cli/group_output_test.go @@ -10,35 +10,35 @@ import ( // TODO: Add tests func Test_NoGroupOutput(t *testing.T) { - searchPath := "../../test" + searchPath := "../../test" excludeDirs := []string{"subdir", "subdir2"} - groupOutput := map[string][]string{ - "test": {}, - "test2": {}, - "test3": {}, - } - stdoutReporter := reporter.StdoutReporter{} - - for i := range groupOutput { - fsFinder := finder.FileSystemFinderInit( - finder.WithPathRoots(searchPath), - finder.WithExcludeDirs(excludeDirs), - ) - cli := Init( - WithFinder(fsFinder), - WithReporter(stdoutReporter), - WithGroupOutput(groupOutput[i]), - ) - exitStatus, err := cli.Run() - - if err != nil { - t.Errorf("An error was returned: %v", err) - } - - if exitStatus != 0 { - t.Errorf("Exit status was not 0") - } - } + groupOutput := map[string][]string{ + "test": {}, + "test2": {}, + "test3": {}, + } + stdoutReporter := reporter.StdoutReporter{} + + for i := range groupOutput { + fsFinder := finder.FileSystemFinderInit( + finder.WithPathRoots(searchPath), + finder.WithExcludeDirs(excludeDirs), + ) + cli := Init( + WithFinder(fsFinder), + WithReporter(stdoutReporter), + WithGroupOutput(groupOutput[i]), + ) + exitStatus, err := cli.Run() + + if err != nil { + t.Errorf("An error was returned: %v", err) + } + + if exitStatus != 0 { + t.Errorf("Exit status was not 0") + } + } } func Test_SingleGroupOutput(t *testing.T) { diff --git a/pkg/reporter/json_reporter.go b/pkg/reporter/json_reporter.go index 0f16103c..08c91672 100644 --- a/pkg/reporter/json_reporter.go +++ b/pkg/reporter/json_reporter.go @@ -159,8 +159,8 @@ func (jr JsonReporter) PrintDoubleGroup(groupReports map[string]map[string][]Rep report.Files[group] = make(map[string][]fileStatus, 0) report.Summary[group] = make(map[string][]summary, 0) for group2, reports := range group2 { - currentPassed = 0 - currentFailed = 0 + currentPassed = 0 + currentFailed = 0 report.Files[group][group2] = make([]fileStatus, 0) report.Summary[group][group2] = make([]summary, 0) for _, r := range reports { @@ -183,19 +183,19 @@ func (jr JsonReporter) PrintDoubleGroup(groupReports map[string]map[string][]Rep }) } - for _, f := range report.Files[group][group2] { - if f.Status == "passed" { - currentPassed++ - totalPassed++ - } else { - currentFailed++ - totalFailed++ - } - } - report.Summary[group][group2] = append(report.Summary[group][group2], summary{ - Passed: currentPassed, - Failed: currentFailed, - }) + for _, f := range report.Files[group][group2] { + if f.Status == "passed" { + currentPassed++ + totalPassed++ + } else { + currentFailed++ + totalFailed++ + } + } + report.Summary[group][group2] = append(report.Summary[group][group2], summary{ + Passed: currentPassed, + Failed: currentFailed, + }) } } @@ -211,5 +211,5 @@ func (jr JsonReporter) PrintDoubleGroup(groupReports map[string]map[string][]Rep } func (jr JsonReporter) PrintTripleGroup(groupReports map[string]map[string]map[string][]Report, groupOutput []string) error { - return nil + return nil } diff --git a/pkg/reporter/reporter.go b/pkg/reporter/reporter.go index 4f78b49b..1839ace0 100644 --- a/pkg/reporter/reporter.go +++ b/pkg/reporter/reporter.go @@ -18,5 +18,5 @@ type Reporter interface { Print(reports []Report) error PrintSingleGroup(map[string][]Report, string) error PrintDoubleGroup(map[string]map[string][]Report, []string) error - PrintTripleGroup(map[string]map[string]map[string][]Report, []string) error + PrintTripleGroup(map[string]map[string]map[string][]Report, []string) error } diff --git a/pkg/reporter/stdout_reporter.go b/pkg/reporter/stdout_reporter.go index a261e3bc..043ef0bc 100644 --- a/pkg/reporter/stdout_reporter.go +++ b/pkg/reporter/stdout_reporter.go @@ -102,7 +102,7 @@ func (sr StdoutReporter) PrintDoubleGroup(groupReport map[string]map[string][]Re } func (sr StdoutReporter) PrintTripleGroup(groupReport map[string]map[string]map[string][]Report, groupOutput []string) error { - return nil + return nil } // padErrorString adds padding to every newline in the error From a190abccf9d6e82b2dee51113a279d94f29d4f64 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Wed, 22 Nov 2023 19:30:46 -0800 Subject: [PATCH 31/48] Implement triple group output Implement output for when 3 groupbys are passed --- cmd/validator/validator.go | 8 ++++ pkg/reporter/json_reporter.go | 80 ++++++++++++++++++++++++++++++++- pkg/reporter/stdout_reporter.go | 34 ++++++++++++++ 3 files changed, 120 insertions(+), 2 deletions(-) diff --git a/cmd/validator/validator.go b/cmd/validator/validator.go index 2dd8adfd..7eb85c84 100644 --- a/cmd/validator/validator.go +++ b/cmd/validator/validator.go @@ -102,7 +102,9 @@ func getFlags() (validatorConfig, error) { 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") { for _, groupBy := range groupByUserInput { if !slices.Contains(groupByAllowedValues, groupBy) { @@ -110,6 +112,12 @@ func getFlags() (validatorConfig, error) { flag.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") + } + seenValues[groupBy] = true } } diff --git a/pkg/reporter/json_reporter.go b/pkg/reporter/json_reporter.go index 08c91672..2a051f01 100644 --- a/pkg/reporter/json_reporter.go +++ b/pkg/reporter/json_reporter.go @@ -38,6 +38,13 @@ type doubleGroupReportJSON struct { TotalFailed int `json:"totalFailed"` } +type tripleGroupReportJSON struct { + Files map[string]map[string]map[string][]fileStatus `json:"files"` + Summary map[string]map[string]map[string][]summary `json:"summary"` + TotalPassed int `json:"totalPassed"` + TotalFailed int `json:"totalFailed"` +} + // Print implements the Reporter interface by outputting // the report content to stdout as JSON func (jr JsonReporter) Print(reports []Report) error { @@ -83,8 +90,8 @@ func (jr JsonReporter) Print(reports []Report) error { } // Tried to pass the Print function to this function but it didn't work -// Header of JSON would be generic and not specific to the group -// I.e it would be "files" instead of listing the file extensions +// We lose the group output when we do that +// TODO: Fix this func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report, groupOutput string) error { var report groupReportJSON currentPassed := 0 @@ -211,5 +218,74 @@ func (jr JsonReporter) PrintDoubleGroup(groupReports map[string]map[string][]Rep } func (jr JsonReporter) PrintTripleGroup(groupReports map[string]map[string]map[string][]Report, groupOutput []string) error { + var report tripleGroupReportJSON + currentPassed := 0 + currentFailed := 0 + totalPassed := 0 + totalFailed := 0 + report.Files = make(map[string]map[string]map[string][]fileStatus) + report.Summary = make(map[string]map[string]map[string][]summary) + + for group, group2 := range groupReports { + report.Files[group] = make(map[string]map[string][]fileStatus, 0) + report.Summary[group] = make(map[string]map[string][]summary, 0) + + for group2, group3 := range group2 { + report.Files[group][group2] = make(map[string][]fileStatus, 0) + report.Summary[group][group2] = make(map[string][]summary, 0) + + for group3, reports := range group3 { + currentPassed = 0 + currentFailed = 0 + report.Files[group][group2][group3] = make([]fileStatus, 0) + report.Summary[group][group2][group3] = make([]summary, 0) + + for _, r := range reports { + status := "passed" + errorStr := "" + if !r.IsValid { + status = "failed" + errorStr = r.ValidationError.Error() + } + + // Convert Windows-style file paths. + if strings.Contains(r.FilePath, "\\") { + r.FilePath = strings.ReplaceAll(r.FilePath, "\\", "/") + } + + report.Files[group][group2][group3] = append(report.Files[group][group2][group3], fileStatus{ + Path: r.FilePath, + Status: status, + Error: errorStr, + }) + + } + + for _, f := range report.Files[group][group2][group3] { + if f.Status == "passed" { + currentPassed++ + totalPassed++ + } else { + currentFailed++ + totalFailed++ + } + } + report.Summary[group][group2][group3] = append(report.Summary[group][group2][group3], summary{ + Passed: currentPassed, + Failed: currentFailed, + }) + } + } + } + + report.TotalPassed = totalPassed + report.TotalFailed = totalFailed + + jsonBytes, err := json.MarshalIndent(report, "", " ") + if err != nil { + return err + } + + fmt.Println(string(jsonBytes)) return nil } diff --git a/pkg/reporter/stdout_reporter.go b/pkg/reporter/stdout_reporter.go index 043ef0bc..e1a0748e 100644 --- a/pkg/reporter/stdout_reporter.go +++ b/pkg/reporter/stdout_reporter.go @@ -102,6 +102,40 @@ func (sr StdoutReporter) PrintDoubleGroup(groupReport map[string]map[string][]Re } func (sr StdoutReporter) PrintTripleGroup(groupReport map[string]map[string]map[string][]Report, groupOutput []string) error { + var successCount = 0 + var failureCount = 0 + var totalSuccessCount = 0 + var totalFailureCount = 0 + + for groupOne, header := range groupReport { + fmt.Printf("%s\n", groupOne) + for groupTwo, subheader := range header { + fmt.Printf(" %s\n", groupTwo) + for groupThree, reports := range subheader { + fmt.Printf(" %s\n", groupThree) + successCount = 0 + failureCount = 0 + for _, report := range reports { + if !report.IsValid { + color.Set(color.FgRed) + fmt.Println(" × " + report.FilePath) + paddedString := sr.padErrorString(report.ValidationError.Error()) + fmt.Printf(" error: %v\n", paddedString) + color.Unset() + failureCount = failureCount + 1 + totalFailureCount = totalFailureCount + 1 + } else { + color.Green(" ✓ " + report.FilePath) + successCount = successCount + 1 + totalSuccessCount = totalSuccessCount + 1 + } + } + fmt.Printf(" Summary: %d succeeded, %d failed\n\n", successCount, failureCount) + } + } + } + + fmt.Printf("Total Summary: %d succeeded, %d failed\n", totalSuccessCount, totalFailureCount) return nil } From f41a5e0b55c32191f633c19663e9dd3ca88cea51 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Wed, 22 Nov 2023 19:46:07 -0800 Subject: [PATCH 32/48] Add Output Tests Added output tests for groupby outputs --- pkg/reporter/reporter_test.go | 216 ++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) diff --git a/pkg/reporter/reporter_test.go b/pkg/reporter/reporter_test.go index fc20da08..70a69006 100644 --- a/pkg/reporter/reporter_test.go +++ b/pkg/reporter/reporter_test.go @@ -66,3 +66,219 @@ func Test_jsonReport(t *testing.T) { t.Errorf("Reporting failed") } } + +func Test_stdoutReportSingleGroup(t *testing.T) { + reportNoValidationError := Report{ + "good.xml", + "/fake/path/good.xml", + true, + nil, + } + + reportWithValidationError := Report{ + "bad.xml", + "/fake/path/bad.xml", + false, + errors.New("Unable to parse bad.xml file"), + } + + reportWithMultiLineValidationError := Report{ + "bad.xml", + "/fake/path/bad.xml", + false, + errors.New("Unable to parse keys:\nkey1\nkey2"), + } + + reports := []Report{reportNoValidationError, reportWithValidationError, reportWithMultiLineValidationError} + + groupOutput := "pass-fail" + + groupReports := map[string][]Report{"pass-fail": reports} + + stdoutReporter := StdoutReporter{} + err := stdoutReporter.PrintSingleGroup(groupReports, groupOutput) + if err != nil { + t.Errorf("Reporting failed") + } +} + +func Test_stdoutReportDoubleGroup(t *testing.T) { + reportNoValidationError := Report{ + "good.xml", + "/fake/path/good.xml", + true, + nil, + } + + reportWithValidationError := Report{ + "bad.xml", + "/fake/path/bad.xml", + false, + errors.New("Unable to parse bad.xml file"), + } + + reportWithMultiLineValidationError := Report{ + "bad.xml", + "/fake/path/bad.xml", + false, + errors.New("Unable to parse keys:\nkey1\nkey2"), + } + + reports := []Report{reportNoValidationError, reportWithValidationError, reportWithMultiLineValidationError} + + groupOutput := []string{"pass-fail", "filetype"} + + groupReports := map[string]map[string][]Report{"pass-fail": {"pass-fail": reports}, "filetype": {"filetype": reports}} + + stdoutReporter := StdoutReporter{} + err := stdoutReporter.PrintDoubleGroup(groupReports, groupOutput) + if err != nil { + t.Errorf("Reporting failed") + } +} + +func Test_stdoutReportTripleGroup(t *testing.T) { + reportNoValidationError := Report{ + "good.xml", + "/fake/path/good.xml", + true, + nil, + } + + reportWithValidationError := Report{ + "bad.xml", + "/fake/path/bad.xml", + false, + errors.New("Unable to parse bad.xml file"), + } + + reportWithMultiLineValidationError := Report{ + "bad.xml", + "/fake/path/bad.xml", + false, + errors.New("Unable to parse keys:\nkey1\nkey2"), + } + + reports := []Report{reportNoValidationError, reportWithValidationError, reportWithMultiLineValidationError} + + groupOutput := []string{"pass-fail", "filetype", "directory"} + + groupReports := map[string]map[string]map[string][]Report{ + "pass-fail": {"directory": {"filetype": reports}}, + "filetype": {"directory": {"pass-fail": reports}}, + "directory": {"filetype": {"pass-fail": reports}}} + + stdoutReporter := StdoutReporter{} + err := stdoutReporter.PrintTripleGroup(groupReports, groupOutput) + if err != nil { + t.Errorf("Reporting failed") + } +} + +func Test_jsonReportSingleGroup(t *testing.T) { + reportNoValidationError := Report{ + "good.xml", + "/fake/path/good.xml", + true, + nil, + } + + reportWithValidationError := Report{ + "bad.xml", + "/fake/path/bad.xml", + false, + errors.New("Unable to parse bad.xml file"), + } + + reportWithMultiLineValidationError := Report{ + "bad.xml", + "/fake/path/bad.xml", + false, + errors.New("Unable to parse keys:\nkey1\nkey2"), + } + + reports := []Report{reportNoValidationError, reportWithValidationError, reportWithMultiLineValidationError} + + groupOutput := "pass-fail" + + groupReports := map[string][]Report{"pass-fail": reports} + + stdoutReporter := JsonReporter{} + err := stdoutReporter.PrintSingleGroup(groupReports, groupOutput) + if err != nil { + t.Errorf("Reporting failed") + } +} + +func Test_jsonReportDoubleGroup(t *testing.T) { + reportNoValidationError := Report{ + "good.xml", + "/fake/path/good.xml", + true, + nil, + } + + reportWithValidationError := Report{ + "bad.xml", + "/fake/path/bad.xml", + false, + errors.New("Unable to parse bad.xml file"), + } + + reportWithMultiLineValidationError := Report{ + "bad.xml", + "/fake/path/bad.xml", + false, + errors.New("Unable to parse keys:\nkey1\nkey2"), + } + + reports := []Report{reportNoValidationError, reportWithValidationError, reportWithMultiLineValidationError} + + groupOutput := []string{"pass-fail", "filetype"} + + groupReports := map[string]map[string][]Report{"pass-fail": {"pass-fail": reports}, "filetype": {"filetype": reports}} + + stdoutReporter := JsonReporter{} + err := stdoutReporter.PrintDoubleGroup(groupReports, groupOutput) + if err != nil { + t.Errorf("Reporting failed") + } +} + +func Test_jsonReportTripleGroup(t *testing.T) { + reportNoValidationError := Report{ + "good.xml", + "/fake/path/good.xml", + true, + nil, + } + + reportWithValidationError := Report{ + "bad.xml", + "/fake/path/bad.xml", + false, + errors.New("Unable to parse bad.xml file"), + } + + reportWithMultiLineValidationError := Report{ + "bad.xml", + "/fake/path/bad.xml", + false, + errors.New("Unable to parse keys:\nkey1\nkey2"), + } + + reports := []Report{reportNoValidationError, reportWithValidationError, reportWithMultiLineValidationError} + + groupOutput := []string{"pass-fail", "filetype", "directory"} + + groupReports := map[string]map[string]map[string][]Report{ + "pass-fail": {"directory": {"filetype": reports}}, + "filetype": {"directory": {"pass-fail": reports}}, + "directory": {"filetype": {"pass-fail": reports}}} + + stdoutReporter := JsonReporter{} + err := stdoutReporter.PrintTripleGroup(groupReports, groupOutput) + if err != nil { + t.Errorf("Reporting failed") + } +} From 888f74ab40adbac75cda0df07984c9886b5ef591 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Wed, 22 Nov 2023 19:54:36 -0800 Subject: [PATCH 33/48] Clean comments Cleaned up comments --- pkg/cli/group_output.go | 5 +++++ pkg/cli/group_output_test.go | 2 -- pkg/reporter/json_reporter.go | 4 +++- pkg/reporter/stdout_reporter.go | 1 - 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pkg/cli/group_output.go b/pkg/cli/group_output.go index a37795ef..123ed3cd 100644 --- a/pkg/cli/group_output.go +++ b/pkg/cli/group_output.go @@ -66,9 +66,12 @@ func GroupByDirectory(reports []reporter.Report) map[string][]reporter.Report { return reportByDirectory } +// Group Reports by single grouping func GroupBySingle(reports []reporter.Report, groupBy string) (map[string][]reporter.Report, error) { var groupReport map[string][]reporter.Report + // Group by the groupings in reverse order + // This allows for the first grouping to be the outermost grouping for i := len(groupBy) - 1; i >= 0; i-- { switch groupBy { case "pass-fail": @@ -84,6 +87,7 @@ func GroupBySingle(reports []reporter.Report, groupBy string) (map[string][]repo return groupReport, nil } +// Group Reports for two groupings func GroupByDouble(reports []reporter.Report, groupBy []string) (map[string]map[string][]reporter.Report, error) { groupReport := make(map[string]map[string][]reporter.Report) @@ -102,6 +106,7 @@ func GroupByDouble(reports []reporter.Report, groupBy []string) (map[string]map[ return groupReport, nil } +// Group Reports for three groupings func GroupByTriple(reports []reporter.Report, groupBy []string) (map[string]map[string]map[string][]reporter.Report, error) { groupReport := make(map[string]map[string]map[string][]reporter.Report) diff --git a/pkg/cli/group_output_test.go b/pkg/cli/group_output_test.go index 7b56748c..cbc5f298 100644 --- a/pkg/cli/group_output_test.go +++ b/pkg/cli/group_output_test.go @@ -7,8 +7,6 @@ import ( "github.com/Boeing/config-file-validator/pkg/reporter" ) -// TODO: Add tests - func Test_NoGroupOutput(t *testing.T) { searchPath := "../../test" excludeDirs := []string{"subdir", "subdir2"} diff --git a/pkg/reporter/json_reporter.go b/pkg/reporter/json_reporter.go index 2a051f01..d3dad500 100644 --- a/pkg/reporter/json_reporter.go +++ b/pkg/reporter/json_reporter.go @@ -91,7 +91,9 @@ func (jr JsonReporter) Print(reports []Report) error { // Tried to pass the Print function to this function but it didn't work // We lose the group output when we do that -// TODO: Fix this +// Possible solution: create functions to handle each grouping +// and pass the Print function to those functions +// Similiar to how the group_output.go file is structured func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report, groupOutput string) error { var report groupReportJSON currentPassed := 0 diff --git a/pkg/reporter/stdout_reporter.go b/pkg/reporter/stdout_reporter.go index e1a0748e..8f260969 100644 --- a/pkg/reporter/stdout_reporter.go +++ b/pkg/reporter/stdout_reporter.go @@ -33,7 +33,6 @@ func (sr StdoutReporter) Print(reports []Report) error { // There is repeated code in the following two functions. Trying to consolidate // the code into one function is difficult because of the output format -// Need to investigate further func (sr StdoutReporter) PrintSingleGroup(groupReport map[string][]Report, groupOutput string) error { var successCount = 0 var failureCount = 0 From 6898103ef65860a7dca03df36f392818e6b87470 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Wed, 22 Nov 2023 20:07:23 -0800 Subject: [PATCH 34/48] Changed Summary Format Changed the summary per group to be aligned with the inner most group rather than the tests --- pkg/reporter/stdout_reporter.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/reporter/stdout_reporter.go b/pkg/reporter/stdout_reporter.go index 8f260969..4c806a99 100644 --- a/pkg/reporter/stdout_reporter.go +++ b/pkg/reporter/stdout_reporter.go @@ -57,7 +57,7 @@ func (sr StdoutReporter) PrintSingleGroup(groupReport map[string][]Report, group totalSuccessCount = totalSuccessCount + 1 } } - fmt.Printf(" Summary: %d succeeded, %d failed\n\n", successCount, failureCount) + fmt.Printf("Summary: %d succeeded, %d failed\n\n", successCount, failureCount) } fmt.Printf("Total Summary: %d succeeded, %d failed\n", totalSuccessCount, totalFailureCount) @@ -91,7 +91,7 @@ func (sr StdoutReporter) PrintDoubleGroup(groupReport map[string]map[string][]Re totalSuccessCount = totalSuccessCount + 1 } } - fmt.Printf(" Summary: %d succeeded, %d failed\n\n", successCount, failureCount) + fmt.Printf(" Summary: %d succeeded, %d failed\n\n", successCount, failureCount) } } @@ -129,7 +129,7 @@ func (sr StdoutReporter) PrintTripleGroup(groupReport map[string]map[string]map[ totalSuccessCount = totalSuccessCount + 1 } } - fmt.Printf(" Summary: %d succeeded, %d failed\n\n", successCount, failureCount) + fmt.Printf(" Summary: %d succeeded, %d failed\n\n", successCount, failureCount) } } } From 8452661f852449e8c4176d3e0f5691e14ec21d46 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Thu, 30 Nov 2023 13:44:45 -0800 Subject: [PATCH 35/48] Update README.md Co-authored-by: Clayton Kehoe <118750525+kehoecj@users.noreply.github.com> --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 2a722294..6327f7f0 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,6 @@ optional flags: Format of the printed report. Options are standard and json (default "standard") -version Version prints the release version of validator - ``` ### Examples From 5bb439c69e25fda0b3e5dfe3ece7821207b385d1 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Thu, 30 Nov 2023 13:45:23 -0800 Subject: [PATCH 36/48] Update cmd/validator/validator.go Update file type to filetype to avoid input confusion Co-authored-by: Clayton Kehoe <118750525+kehoecj@users.noreply.github.com> --- cmd/validator/validator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/validator/validator.go b/cmd/validator/validator.go index 7eb85c84..c7928c76 100644 --- a/cmd/validator/validator.go +++ b/cmd/validator/validator.go @@ -73,7 +73,7 @@ func getFlags() (validatorConfig, error) { excludeFileTypesPtr := flag.String("exclude-file-types", "", "A comma separated list of file types to ignore") depthPtr := flag.Int("depth", 0, "Depth of recursion for the provided search paths. Set depth to 0 to disable recursive path traversal") versionPtr := flag.Bool("version", false, "Version prints the release version of validator") - groupOutputPtr := flag.String("groupby", "", "Group output by file type, directory, pass-fail") + groupOutputPtr := flag.String("groupby", "", "Group output by filetype, directory, pass-fail") flag.Parse() searchPaths := make([]string, 0) From e893ee0da02d84bf53b2a302d5bdcca478c9f5bc Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 4 Dec 2023 07:51:35 -0800 Subject: [PATCH 37/48] Add Header Comments Added header comments to the stdout and json reporters --- pkg/reporter/json_reporter.go | 2 ++ pkg/reporter/stdout_reporter.go | 2 ++ 2 files changed, 4 insertions(+) diff --git a/pkg/reporter/json_reporter.go b/pkg/reporter/json_reporter.go index d3dad500..b766dfd0 100644 --- a/pkg/reporter/json_reporter.go +++ b/pkg/reporter/json_reporter.go @@ -155,6 +155,7 @@ func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report, groupO return nil } +// Prints the report for when two groups are passed in the groupby flag func (jr JsonReporter) PrintDoubleGroup(groupReports map[string]map[string][]Report, groupOutput []string) error { var report doubleGroupReportJSON currentPassed := 0 @@ -219,6 +220,7 @@ func (jr JsonReporter) PrintDoubleGroup(groupReports map[string]map[string][]Rep return nil } +// Prinnts the report for when three groups are passed in the groupby flag func (jr JsonReporter) PrintTripleGroup(groupReports map[string]map[string]map[string][]Report, groupOutput []string) error { var report tripleGroupReportJSON currentPassed := 0 diff --git a/pkg/reporter/stdout_reporter.go b/pkg/reporter/stdout_reporter.go index 4c806a99..94bf0bcd 100644 --- a/pkg/reporter/stdout_reporter.go +++ b/pkg/reporter/stdout_reporter.go @@ -64,6 +64,7 @@ func (sr StdoutReporter) PrintSingleGroup(groupReport map[string][]Report, group return nil } +// Prints the report for when two groups are passed in the groupby flag func (sr StdoutReporter) PrintDoubleGroup(groupReport map[string]map[string][]Report, groupOutput []string) error { var successCount = 0 var failureCount = 0 @@ -100,6 +101,7 @@ func (sr StdoutReporter) PrintDoubleGroup(groupReport map[string]map[string][]Re return nil } +// Prints the report for when three groups are passed in the groupby flag func (sr StdoutReporter) PrintTripleGroup(groupReport map[string]map[string]map[string][]Report, groupOutput []string) error { var successCount = 0 var failureCount = 0 From 4fdb83556fd18aa7474c7340e34e75fca70aba0d Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 4 Dec 2023 09:27:22 -0800 Subject: [PATCH 38/48] Fix Naming Conflict Fixed a naming conflict in the json reporter groupby when 3 groups are passed --- pkg/reporter/json_reporter.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pkg/reporter/json_reporter.go b/pkg/reporter/json_reporter.go index b766dfd0..c9e3679f 100644 --- a/pkg/reporter/json_reporter.go +++ b/pkg/reporter/json_reporter.go @@ -238,11 +238,11 @@ func (jr JsonReporter) PrintTripleGroup(groupReports map[string]map[string]map[s report.Files[group][group2] = make(map[string][]fileStatus, 0) report.Summary[group][group2] = make(map[string][]summary, 0) - for group3, reports := range group3 { + for group4, reports := range group3 { currentPassed = 0 currentFailed = 0 - report.Files[group][group2][group3] = make([]fileStatus, 0) - report.Summary[group][group2][group3] = make([]summary, 0) + report.Files[group][group2][group4] = make([]fileStatus, 0) + report.Summary[group][group2][group4] = make([]summary, 0) for _, r := range reports { status := "passed" @@ -257,7 +257,7 @@ func (jr JsonReporter) PrintTripleGroup(groupReports map[string]map[string]map[s r.FilePath = strings.ReplaceAll(r.FilePath, "\\", "/") } - report.Files[group][group2][group3] = append(report.Files[group][group2][group3], fileStatus{ + report.Files[group][group2][group4] = append(report.Files[group][group2][group4], fileStatus{ Path: r.FilePath, Status: status, Error: errorStr, @@ -265,7 +265,7 @@ func (jr JsonReporter) PrintTripleGroup(groupReports map[string]map[string]map[s } - for _, f := range report.Files[group][group2][group3] { + for _, f := range report.Files[group][group2][group4] { if f.Status == "passed" { currentPassed++ totalPassed++ @@ -274,7 +274,7 @@ func (jr JsonReporter) PrintTripleGroup(groupReports map[string]map[string]map[s totalFailed++ } } - report.Summary[group][group2][group3] = append(report.Summary[group][group2][group3], summary{ + report.Summary[group][group2][group4] = append(report.Summary[group][group2][group4], summary{ Passed: currentPassed, Failed: currentFailed, }) @@ -293,3 +293,4 @@ func (jr JsonReporter) PrintTripleGroup(groupReports map[string]map[string]map[s fmt.Println(string(jsonBytes)) return nil } + From a084cc7fdcf2c841946f6af33421130ec98426bf Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Tue, 5 Dec 2023 10:06:51 -0800 Subject: [PATCH 39/48] Add Util function for Json Reporter Added a utility function to the JSON reporter to reduce duplicated code. --- pkg/cli/cli.go | 6 +- pkg/reporter/json_reporter.go | 238 +++++++++++++------------------- pkg/reporter/reporter.go | 6 +- pkg/reporter/stdout_reporter.go | 6 +- 4 files changed, 103 insertions(+), 153 deletions(-) diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index 7ef8f897..6b224181 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -105,19 +105,19 @@ func (c CLI) Run() (int, error) { if err != nil { return 1, fmt.Errorf("unable to group by single value: %v", err) } - c.Reporter.PrintSingleGroup(reportGroup, GroupOutput[0]) + c.Reporter.PrintSingleGroup(reportGroup) } else if len(GroupOutput) == 2 { reportGroup, err := GroupByDouble(reports, GroupOutput) if err != nil { return 1, fmt.Errorf("unable to group by double value: %v", err) } - c.Reporter.PrintDoubleGroup(reportGroup, GroupOutput) + c.Reporter.PrintDoubleGroup(reportGroup) } else if len(GroupOutput) == 3 { reportGroup, err := GroupByTriple(reports, GroupOutput) if err != nil { return 1, fmt.Errorf("unable to group by triple value: %v", err) } - c.Reporter.PrintTripleGroup(reportGroup, GroupOutput) + c.Reporter.PrintTripleGroup(reportGroup) } else { c.Reporter.Print(reports) } diff --git a/pkg/reporter/json_reporter.go b/pkg/reporter/json_reporter.go index c9e3679f..73f18f0c 100644 --- a/pkg/reporter/json_reporter.go +++ b/pkg/reporter/json_reporter.go @@ -89,64 +89,32 @@ func (jr JsonReporter) Print(reports []Report) error { return nil } -// Tried to pass the Print function to this function but it didn't work -// We lose the group output when we do that -// Possible solution: create functions to handle each grouping -// and pass the Print function to those functions -// Similiar to how the group_output.go file is structured -func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report, groupOutput string) error { - var report groupReportJSON - currentPassed := 0 - currentFailed := 0 +// Prints the report for when one group is passed in the groupby flag +func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report) error { + var jsonReport groupReportJSON totalPassed := 0 totalFailed := 0 - report.Files = make(map[string][]fileStatus) - report.Summary = make(map[string][]summary) + jsonReport.Files = make(map[string][]fileStatus) + jsonReport.Summary = make(map[string][]summary) for group, reports := range groupReports { - report.Files[group] = make([]fileStatus, 0) - report.Summary[group] = make([]summary, 0) - currentPassed = 0 - currentFailed = 0 - for _, r := range reports { - status := "passed" - errorStr := "" - if !r.IsValid { - status = "failed" - errorStr = r.ValidationError.Error() - } + report, err := createSingleGroupJson(reports, group) + if err != nil { + return err + } - // Convert Windows-style file paths. - if strings.Contains(r.FilePath, "\\") { - r.FilePath = strings.ReplaceAll(r.FilePath, "\\", "/") - } + jsonReport.Files[group] = report.Files + jsonReport.Summary[group] = append(jsonReport.Summary[group], report.Summary) - report.Files[group] = append(report.Files[group], fileStatus{ - Path: r.FilePath, - Status: status, - Error: errorStr, - }) - } + totalPassed += report.Summary.Passed + totalFailed += report.Summary.Failed - for _, f := range report.Files[group] { - if f.Status == "passed" { - currentPassed++ - totalPassed++ - } else { - currentFailed++ - totalFailed++ - } - } - report.Summary[group] = append(report.Summary[group], summary{ - Passed: currentPassed, - Failed: currentFailed, - }) } - report.TotalPassed = totalPassed - report.TotalFailed = totalFailed + jsonReport.TotalPassed = totalPassed + jsonReport.TotalFailed = totalFailed - jsonBytes, err := json.MarshalIndent(report, "", " ") + jsonBytes, err := json.MarshalIndent(jsonReport, "", " ") if err != nil { return err } @@ -156,63 +124,35 @@ func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report, groupO } // Prints the report for when two groups are passed in the groupby flag -func (jr JsonReporter) PrintDoubleGroup(groupReports map[string]map[string][]Report, groupOutput []string) error { - var report doubleGroupReportJSON - currentPassed := 0 - currentFailed := 0 +func (jr JsonReporter) PrintDoubleGroup(groupReports map[string]map[string][]Report) error { + var jsonReport doubleGroupReportJSON totalPassed := 0 totalFailed := 0 - report.Files = make(map[string]map[string][]fileStatus) - report.Summary = make(map[string]map[string][]summary) + jsonReport.Files = make(map[string]map[string][]fileStatus) + jsonReport.Summary = make(map[string]map[string][]summary) for group, group2 := range groupReports { - report.Files[group] = make(map[string][]fileStatus, 0) - report.Summary[group] = make(map[string][]summary, 0) + jsonReport.Files[group] = make(map[string][]fileStatus, 0) + jsonReport.Summary[group] = make(map[string][]summary, 0) for group2, reports := range group2 { - currentPassed = 0 - currentFailed = 0 - report.Files[group][group2] = make([]fileStatus, 0) - report.Summary[group][group2] = make([]summary, 0) - for _, r := range reports { - status := "passed" - errorStr := "" - if !r.IsValid { - status = "failed" - errorStr = r.ValidationError.Error() - } + report, err := createSingleGroupJson(reports, group) + if err != nil { + return err + } - // Convert Windows-style file paths. - if strings.Contains(r.FilePath, "\\") { - r.FilePath = strings.ReplaceAll(r.FilePath, "\\", "/") - } + jsonReport.Files[group][group2] = report.Files + jsonReport.Summary[group][group2] = append(jsonReport.Summary[group][group2], report.Summary) - report.Files[group][group2] = append(report.Files[group][group2], fileStatus{ - Path: r.FilePath, - Status: status, - Error: errorStr, - }) - } + totalPassed += report.Summary.Passed + totalFailed += report.Summary.Failed - for _, f := range report.Files[group][group2] { - if f.Status == "passed" { - currentPassed++ - totalPassed++ - } else { - currentFailed++ - totalFailed++ - } - } - report.Summary[group][group2] = append(report.Summary[group][group2], summary{ - Passed: currentPassed, - Failed: currentFailed, - }) } } - report.TotalPassed = totalPassed - report.TotalFailed = totalFailed + jsonReport.TotalPassed = totalPassed + jsonReport.TotalFailed = totalFailed - jsonBytes, err := json.MarshalIndent(report, "", " ") + jsonBytes, err := json.MarshalIndent(jsonReport, "", " ") if err != nil { return err } @@ -221,71 +161,42 @@ func (jr JsonReporter) PrintDoubleGroup(groupReports map[string]map[string][]Rep } // Prinnts the report for when three groups are passed in the groupby flag -func (jr JsonReporter) PrintTripleGroup(groupReports map[string]map[string]map[string][]Report, groupOutput []string) error { - var report tripleGroupReportJSON - currentPassed := 0 - currentFailed := 0 +func (jr JsonReporter) PrintTripleGroup(groupReports map[string]map[string]map[string][]Report) error { + var jsonReport tripleGroupReportJSON totalPassed := 0 totalFailed := 0 - report.Files = make(map[string]map[string]map[string][]fileStatus) - report.Summary = make(map[string]map[string]map[string][]summary) + jsonReport.Files = make(map[string]map[string]map[string][]fileStatus) + jsonReport.Summary = make(map[string]map[string]map[string][]summary) for group, group2 := range groupReports { - report.Files[group] = make(map[string]map[string][]fileStatus, 0) - report.Summary[group] = make(map[string]map[string][]summary, 0) + jsonReport.Files[group] = make(map[string]map[string][]fileStatus, 0) + jsonReport.Summary[group] = make(map[string]map[string][]summary, 0) for group2, group3 := range group2 { - report.Files[group][group2] = make(map[string][]fileStatus, 0) - report.Summary[group][group2] = make(map[string][]summary, 0) - - for group4, reports := range group3 { - currentPassed = 0 - currentFailed = 0 - report.Files[group][group2][group4] = make([]fileStatus, 0) - report.Summary[group][group2][group4] = make([]summary, 0) - - for _, r := range reports { - status := "passed" - errorStr := "" - if !r.IsValid { - status = "failed" - errorStr = r.ValidationError.Error() - } - - // Convert Windows-style file paths. - if strings.Contains(r.FilePath, "\\") { - r.FilePath = strings.ReplaceAll(r.FilePath, "\\", "/") - } - - report.Files[group][group2][group4] = append(report.Files[group][group2][group4], fileStatus{ - Path: r.FilePath, - Status: status, - Error: errorStr, - }) + jsonReport.Files[group][group2] = make(map[string][]fileStatus, 0) + jsonReport.Summary[group][group2] = make(map[string][]summary, 0) + for group3, reports := range group3 { + report, err := createSingleGroupJson(reports, group) + if err != nil { + return err } - for _, f := range report.Files[group][group2][group4] { - if f.Status == "passed" { - currentPassed++ - totalPassed++ - } else { - currentFailed++ - totalFailed++ - } - } - report.Summary[group][group2][group4] = append(report.Summary[group][group2][group4], summary{ - Passed: currentPassed, - Failed: currentFailed, - }) + jsonReport.Files[group][group2][group3] = report.Files + jsonReport.Summary[group][group2][group3] = append(jsonReport.Summary[group][group2][group3], report.Summary) + + totalPassed += report.Summary.Passed + totalFailed += report.Summary.Failed + } + } } - report.TotalPassed = totalPassed - report.TotalFailed = totalFailed + jsonReport.TotalPassed = totalPassed + jsonReport.TotalFailed = totalFailed - jsonBytes, err := json.MarshalIndent(report, "", " ") + jsonBytes, err := json.MarshalIndent(jsonReport, "", " ") if err != nil { return err } @@ -294,3 +205,42 @@ func (jr JsonReporter) PrintTripleGroup(groupReports map[string]map[string]map[s return nil } +func createSingleGroupJson(reports []Report, groupOutput string) (reportJSON, error) { + var jsonReport reportJSON + + for _, report := range reports { + status := "passed" + errorStr := "" + if !report.IsValid { + status = "failed" + errorStr = report.ValidationError.Error() + } + + // Convert Windows-style file paths. + if strings.Contains(report.FilePath, "\\") { + report.FilePath = strings.ReplaceAll(report.FilePath, "\\", "/") + } + + jsonReport.Files = append(jsonReport.Files, fileStatus{ + Path: report.FilePath, + Status: status, + Error: errorStr, + }) + + currentPassed := 0 + currentFailed := 0 + for _, f := range jsonReport.Files { + if f.Status == "passed" { + currentPassed++ + } else { + currentFailed++ + } + } + + jsonReport.Summary.Passed = currentPassed + jsonReport.Summary.Failed = currentFailed + } + + return jsonReport, nil + +} diff --git a/pkg/reporter/reporter.go b/pkg/reporter/reporter.go index 1839ace0..182b202b 100644 --- a/pkg/reporter/reporter.go +++ b/pkg/reporter/reporter.go @@ -16,7 +16,7 @@ type Report struct { // files, etc type Reporter interface { Print(reports []Report) error - PrintSingleGroup(map[string][]Report, string) error - PrintDoubleGroup(map[string]map[string][]Report, []string) error - PrintTripleGroup(map[string]map[string]map[string][]Report, []string) error + PrintSingleGroup(map[string][]Report) error + PrintDoubleGroup(map[string]map[string][]Report) error + PrintTripleGroup(map[string]map[string]map[string][]Report) error } diff --git a/pkg/reporter/stdout_reporter.go b/pkg/reporter/stdout_reporter.go index 94bf0bcd..ebb18ff4 100644 --- a/pkg/reporter/stdout_reporter.go +++ b/pkg/reporter/stdout_reporter.go @@ -33,7 +33,7 @@ func (sr StdoutReporter) Print(reports []Report) error { // There is repeated code in the following two functions. Trying to consolidate // the code into one function is difficult because of the output format -func (sr StdoutReporter) PrintSingleGroup(groupReport map[string][]Report, groupOutput string) error { +func (sr StdoutReporter) PrintSingleGroup(groupReport map[string][]Report) error { var successCount = 0 var failureCount = 0 var totalSuccessCount = 0 @@ -65,7 +65,7 @@ func (sr StdoutReporter) PrintSingleGroup(groupReport map[string][]Report, group } // Prints the report for when two groups are passed in the groupby flag -func (sr StdoutReporter) PrintDoubleGroup(groupReport map[string]map[string][]Report, groupOutput []string) error { +func (sr StdoutReporter) PrintDoubleGroup(groupReport map[string]map[string][]Report) error { var successCount = 0 var failureCount = 0 var totalSuccessCount = 0 @@ -102,7 +102,7 @@ func (sr StdoutReporter) PrintDoubleGroup(groupReport map[string]map[string][]Re } // Prints the report for when three groups are passed in the groupby flag -func (sr StdoutReporter) PrintTripleGroup(groupReport map[string]map[string]map[string][]Report, groupOutput []string) error { +func (sr StdoutReporter) PrintTripleGroup(groupReport map[string]map[string]map[string][]Report) error { var successCount = 0 var failureCount = 0 var totalSuccessCount = 0 From 1a3db987dfc65e1d181810bc8ca0db2830e1145d Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Tue, 5 Dec 2023 10:08:19 -0800 Subject: [PATCH 40/48] Rename Utility Function Renamed the utility function and added a header comment --- pkg/reporter/json_reporter.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/reporter/json_reporter.go b/pkg/reporter/json_reporter.go index 73f18f0c..236848a6 100644 --- a/pkg/reporter/json_reporter.go +++ b/pkg/reporter/json_reporter.go @@ -205,7 +205,8 @@ func (jr JsonReporter) PrintTripleGroup(groupReports map[string]map[string]map[s return nil } -func createSingleGroupJson(reports []Report, groupOutput string) (reportJSON, error) { +// Creates the json report +func createJsonReport(reports []Report, groupOutput string) (reportJSON, error) { var jsonReport reportJSON for _, report := range reports { From eb2dfc107db7e5366f5f0e205c94961684962df4 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Tue, 5 Dec 2023 10:09:21 -0800 Subject: [PATCH 41/48] Rename Utility Function Calls Renamed the utility function calls to the correct name --- pkg/reporter/json_reporter.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/reporter/json_reporter.go b/pkg/reporter/json_reporter.go index 236848a6..3af0331c 100644 --- a/pkg/reporter/json_reporter.go +++ b/pkg/reporter/json_reporter.go @@ -98,7 +98,7 @@ func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report) error jsonReport.Summary = make(map[string][]summary) for group, reports := range groupReports { - report, err := createSingleGroupJson(reports, group) + report, err := createJsonReport(reports, group) if err != nil { return err } @@ -135,7 +135,7 @@ func (jr JsonReporter) PrintDoubleGroup(groupReports map[string]map[string][]Rep jsonReport.Files[group] = make(map[string][]fileStatus, 0) jsonReport.Summary[group] = make(map[string][]summary, 0) for group2, reports := range group2 { - report, err := createSingleGroupJson(reports, group) + report, err := createJsonReport(reports, group) if err != nil { return err } @@ -177,7 +177,7 @@ func (jr JsonReporter) PrintTripleGroup(groupReports map[string]map[string]map[s jsonReport.Summary[group][group2] = make(map[string][]summary, 0) for group3, reports := range group3 { - report, err := createSingleGroupJson(reports, group) + report, err := createJsonReport(reports, group) if err != nil { return err } From bb5f191781dc21a0bc3ce9eeec1b31b102f04866 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Tue, 5 Dec 2023 10:15:02 -0800 Subject: [PATCH 42/48] Update JSON Print Updated the JSON print to use the utility function --- pkg/reporter/json_reporter.go | 40 +++++------------------------------ 1 file changed, 5 insertions(+), 35 deletions(-) diff --git a/pkg/reporter/json_reporter.go b/pkg/reporter/json_reporter.go index 3af0331c..c066dc44 100644 --- a/pkg/reporter/json_reporter.go +++ b/pkg/reporter/json_reporter.go @@ -48,37 +48,7 @@ type tripleGroupReportJSON struct { // Print implements the Reporter interface by outputting // the report content to stdout as JSON func (jr JsonReporter) Print(reports []Report) error { - var report reportJSON - - for _, r := range reports { - status := "passed" - errorStr := "" - if !r.IsValid { - status = "failed" - errorStr = r.ValidationError.Error() - } - - // Convert Windows-style file paths. - if strings.Contains(r.FilePath, "\\") { - r.FilePath = strings.ReplaceAll(r.FilePath, "\\", "/") - } - - report.Files = append(report.Files, fileStatus{ - Path: r.FilePath, - Status: status, - Error: errorStr, - }) - } - - report.Summary.Passed = 0 - report.Summary.Failed = 0 - for _, f := range report.Files { - if f.Status == "passed" { - report.Summary.Passed++ - } else { - report.Summary.Failed++ - } - } + report, err := createJsonReport(reports) jsonBytes, err := json.MarshalIndent(report, "", " ") if err != nil { @@ -98,7 +68,7 @@ func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report) error jsonReport.Summary = make(map[string][]summary) for group, reports := range groupReports { - report, err := createJsonReport(reports, group) + report, err := createJsonReport(reports) if err != nil { return err } @@ -135,7 +105,7 @@ func (jr JsonReporter) PrintDoubleGroup(groupReports map[string]map[string][]Rep jsonReport.Files[group] = make(map[string][]fileStatus, 0) jsonReport.Summary[group] = make(map[string][]summary, 0) for group2, reports := range group2 { - report, err := createJsonReport(reports, group) + report, err := createJsonReport(reports) if err != nil { return err } @@ -177,7 +147,7 @@ func (jr JsonReporter) PrintTripleGroup(groupReports map[string]map[string]map[s jsonReport.Summary[group][group2] = make(map[string][]summary, 0) for group3, reports := range group3 { - report, err := createJsonReport(reports, group) + report, err := createJsonReport(reports) if err != nil { return err } @@ -206,7 +176,7 @@ func (jr JsonReporter) PrintTripleGroup(groupReports map[string]map[string]map[s } // Creates the json report -func createJsonReport(reports []Report, groupOutput string) (reportJSON, error) { +func createJsonReport(reports []Report) (reportJSON, error) { var jsonReport reportJSON for _, report := range reports { From e26c7cc418af9dd04c8296f0b3d2dbf47633055c Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 11 Dec 2023 07:36:01 -0800 Subject: [PATCH 43/48] Update STD Reporter Test Updated the standard reporter tests to align with groupby function changes --- pkg/reporter/reporter_test.go | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/pkg/reporter/reporter_test.go b/pkg/reporter/reporter_test.go index 70a69006..d234c282 100644 --- a/pkg/reporter/reporter_test.go +++ b/pkg/reporter/reporter_test.go @@ -91,12 +91,11 @@ func Test_stdoutReportSingleGroup(t *testing.T) { reports := []Report{reportNoValidationError, reportWithValidationError, reportWithMultiLineValidationError} - groupOutput := "pass-fail" groupReports := map[string][]Report{"pass-fail": reports} stdoutReporter := StdoutReporter{} - err := stdoutReporter.PrintSingleGroup(groupReports, groupOutput) + err := stdoutReporter.PrintSingleGroup(groupReports) if err != nil { t.Errorf("Reporting failed") } @@ -126,12 +125,11 @@ func Test_stdoutReportDoubleGroup(t *testing.T) { reports := []Report{reportNoValidationError, reportWithValidationError, reportWithMultiLineValidationError} - groupOutput := []string{"pass-fail", "filetype"} groupReports := map[string]map[string][]Report{"pass-fail": {"pass-fail": reports}, "filetype": {"filetype": reports}} stdoutReporter := StdoutReporter{} - err := stdoutReporter.PrintDoubleGroup(groupReports, groupOutput) + err := stdoutReporter.PrintDoubleGroup(groupReports) if err != nil { t.Errorf("Reporting failed") } @@ -161,7 +159,6 @@ func Test_stdoutReportTripleGroup(t *testing.T) { reports := []Report{reportNoValidationError, reportWithValidationError, reportWithMultiLineValidationError} - groupOutput := []string{"pass-fail", "filetype", "directory"} groupReports := map[string]map[string]map[string][]Report{ "pass-fail": {"directory": {"filetype": reports}}, @@ -169,7 +166,7 @@ func Test_stdoutReportTripleGroup(t *testing.T) { "directory": {"filetype": {"pass-fail": reports}}} stdoutReporter := StdoutReporter{} - err := stdoutReporter.PrintTripleGroup(groupReports, groupOutput) + err := stdoutReporter.PrintTripleGroup(groupReports) if err != nil { t.Errorf("Reporting failed") } @@ -199,12 +196,11 @@ func Test_jsonReportSingleGroup(t *testing.T) { reports := []Report{reportNoValidationError, reportWithValidationError, reportWithMultiLineValidationError} - groupOutput := "pass-fail" groupReports := map[string][]Report{"pass-fail": reports} stdoutReporter := JsonReporter{} - err := stdoutReporter.PrintSingleGroup(groupReports, groupOutput) + err := stdoutReporter.PrintSingleGroup(groupReports) if err != nil { t.Errorf("Reporting failed") } @@ -234,12 +230,11 @@ func Test_jsonReportDoubleGroup(t *testing.T) { reports := []Report{reportNoValidationError, reportWithValidationError, reportWithMultiLineValidationError} - groupOutput := []string{"pass-fail", "filetype"} groupReports := map[string]map[string][]Report{"pass-fail": {"pass-fail": reports}, "filetype": {"filetype": reports}} stdoutReporter := JsonReporter{} - err := stdoutReporter.PrintDoubleGroup(groupReports, groupOutput) + err := stdoutReporter.PrintDoubleGroup(groupReports) if err != nil { t.Errorf("Reporting failed") } @@ -269,7 +264,6 @@ func Test_jsonReportTripleGroup(t *testing.T) { reports := []Report{reportNoValidationError, reportWithValidationError, reportWithMultiLineValidationError} - groupOutput := []string{"pass-fail", "filetype", "directory"} groupReports := map[string]map[string]map[string][]Report{ "pass-fail": {"directory": {"filetype": reports}}, @@ -277,7 +271,7 @@ func Test_jsonReportTripleGroup(t *testing.T) { "directory": {"filetype": {"pass-fail": reports}}} stdoutReporter := JsonReporter{} - err := stdoutReporter.PrintTripleGroup(groupReports, groupOutput) + err := stdoutReporter.PrintTripleGroup(groupReports) if err != nil { t.Errorf("Reporting failed") } From 3bf77dbbf2f14357f832c4213580ecca825cfba6 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 11 Dec 2023 13:29:08 -0800 Subject: [PATCH 44/48] Refactor Reporter Refactored the print groupBy functions to be removed from the Reporter Interface --- README.md | 2 +- cmd/validator/validator.go | 14 +++++++++----- pkg/cli/cli.go | 20 +++++++++++++++++--- pkg/reporter/json_reporter.go | 6 +++--- pkg/reporter/reporter.go | 3 --- pkg/reporter/reporter_test.go | 20 +++++++------------- pkg/reporter/stdout_reporter.go | 9 ++++++--- 7 files changed, 43 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index fb078b07..1c79bed7 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ optional flags: -exclude-file-types string A comma separated list of file types to ignore -groupby string - Group the output by filetype, pass-fail, or directory + Group the output by filetype, pass-fail, or directory. Supported Reporters are Standard and JSON -reporter string Format of the printed report. Options are standard and json (default "standard") -version diff --git a/cmd/validator/validator.go b/cmd/validator/validator.go index b0e3703a..4f0e946c 100644 --- a/cmd/validator/validator.go +++ b/cmd/validator/validator.go @@ -73,7 +73,7 @@ func getFlags() (validatorConfig, error) { excludeFileTypesPtr := flag.String("exclude-file-types", "", "A comma separated list of file types to ignore") depthPtr := flag.Int("depth", 0, "Depth of recursion for the provided search paths. Set depth to 0 to disable recursive path traversal") versionPtr := flag.Bool("version", false, "Version prints the release version of validator") - groupOutputPtr := flag.String("groupby", "", "Group output by filetype, directory, pass-fail") + groupOutputPtr := flag.String("groupby", "", "Group output by filetype, directory, pass-fail. Supported for Standard and JSON reports") flag.Parse() searchPaths := make([]string, 0) @@ -93,6 +93,12 @@ func getFlags() (validatorConfig, error) { return validatorConfig{}, errors.New("Wrong parameter value for reporter, only supports standard, json or junit") } + if *reportTypePtr == "junit" && *groupOutputPtr != "" { + 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") + } + if depthPtr != nil && isFlagSet("depth") && *depthPtr < 0 { fmt.Println("Wrong parameter value for depth, value cannot be negative.") flag.Usage() @@ -184,13 +190,11 @@ func mainInit() int { // since the exclude dirs are a comma separated string // it needs to be split into a slice of strings excludeDirs := strings.Split(*validatorConfig.excludeDirs, ",") - reporter := getReporter(validatorConfig.reportType) excludeFileTypes := strings.Split(*validatorConfig.excludeFileTypes, ",") - - // since the group output is a comma separated string - // it needs to be split into a slice of strings groupOutput := strings.Split(*validatorConfig.groupOutput, ",") + reporter := getReporter(validatorConfig.reportType) + fsOpts := []finder.FSFinderOptions{finder.WithPathRoots(validatorConfig.searchPaths...), finder.WithExcludeDirs(excludeDirs), finder.WithExcludeFileTypes(excludeFileTypes)} diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go index 6b224181..d8f569c6 100644 --- a/pkg/cli/cli.go +++ b/pkg/cli/cli.go @@ -105,19 +105,33 @@ func (c CLI) Run() (int, error) { if err != nil { return 1, fmt.Errorf("unable to group by single value: %v", err) } - c.Reporter.PrintSingleGroup(reportGroup) + // Check reporter type to determine how to print + if _, ok := c.Reporter.(reporter.JsonReporter); ok { + reporter.PrintSingleGroupJson(reportGroup) + } else { + reporter.PrintSingleGroupStdout(reportGroup) + } } else if len(GroupOutput) == 2 { reportGroup, err := GroupByDouble(reports, GroupOutput) if err != nil { return 1, fmt.Errorf("unable to group by double value: %v", err) } - c.Reporter.PrintDoubleGroup(reportGroup) + if _, ok := c.Reporter.(reporter.JsonReporter); ok { + reporter.PrintDoubleGroupJson(reportGroup) + } else { + reporter.PrintDoubleGroupStdout(reportGroup) + } + } else if len(GroupOutput) == 3 { reportGroup, err := GroupByTriple(reports, GroupOutput) if err != nil { return 1, fmt.Errorf("unable to group by triple value: %v", err) } - c.Reporter.PrintTripleGroup(reportGroup) + if _, ok := c.Reporter.(reporter.JsonReporter); ok { + reporter.PrintTripleGroupJson(reportGroup) + } else { + reporter.PrintTripleGroupStdout(reportGroup) + } } else { c.Reporter.Print(reports) } diff --git a/pkg/reporter/json_reporter.go b/pkg/reporter/json_reporter.go index c066dc44..aa97bb31 100644 --- a/pkg/reporter/json_reporter.go +++ b/pkg/reporter/json_reporter.go @@ -60,7 +60,7 @@ func (jr JsonReporter) Print(reports []Report) error { } // Prints the report for when one group is passed in the groupby flag -func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report) error { +func PrintSingleGroupJson(groupReports map[string][]Report) error { var jsonReport groupReportJSON totalPassed := 0 totalFailed := 0 @@ -94,7 +94,7 @@ func (jr JsonReporter) PrintSingleGroup(groupReports map[string][]Report) error } // Prints the report for when two groups are passed in the groupby flag -func (jr JsonReporter) PrintDoubleGroup(groupReports map[string]map[string][]Report) error { +func PrintDoubleGroupJson(groupReports map[string]map[string][]Report) error { var jsonReport doubleGroupReportJSON totalPassed := 0 totalFailed := 0 @@ -131,7 +131,7 @@ func (jr JsonReporter) PrintDoubleGroup(groupReports map[string]map[string][]Rep } // Prinnts the report for when three groups are passed in the groupby flag -func (jr JsonReporter) PrintTripleGroup(groupReports map[string]map[string]map[string][]Report) error { +func PrintTripleGroupJson(groupReports map[string]map[string]map[string][]Report) error { var jsonReport tripleGroupReportJSON totalPassed := 0 totalFailed := 0 diff --git a/pkg/reporter/reporter.go b/pkg/reporter/reporter.go index 182b202b..4b48269a 100644 --- a/pkg/reporter/reporter.go +++ b/pkg/reporter/reporter.go @@ -16,7 +16,4 @@ type Report struct { // files, etc type Reporter interface { Print(reports []Report) error - PrintSingleGroup(map[string][]Report) error - PrintDoubleGroup(map[string]map[string][]Report) error - PrintTripleGroup(map[string]map[string]map[string][]Report) error } diff --git a/pkg/reporter/reporter_test.go b/pkg/reporter/reporter_test.go index 807255e0..fd95c3e2 100644 --- a/pkg/reporter/reporter_test.go +++ b/pkg/reporter/reporter_test.go @@ -157,8 +157,7 @@ func Test_stdoutReportSingleGroup(t *testing.T) { groupReports := map[string][]Report{"pass-fail": reports} - stdoutReporter := StdoutReporter{} - err := stdoutReporter.PrintSingleGroup(groupReports) + err := PrintSingleGroupStdout(groupReports) if err != nil { t.Errorf("Reporting failed") } @@ -190,8 +189,7 @@ func Test_stdoutReportDoubleGroup(t *testing.T) { groupReports := map[string]map[string][]Report{"pass-fail": {"pass-fail": reports}, "filetype": {"filetype": reports}} - stdoutReporter := StdoutReporter{} - err := stdoutReporter.PrintDoubleGroup(groupReports) + err := PrintDoubleGroupStdout(groupReports) if err != nil { t.Errorf("Reporting failed") } @@ -226,8 +224,7 @@ func Test_stdoutReportTripleGroup(t *testing.T) { "filetype": {"directory": {"pass-fail": reports}}, "directory": {"filetype": {"pass-fail": reports}}} - stdoutReporter := StdoutReporter{} - err := stdoutReporter.PrintTripleGroup(groupReports) + err := PrintTripleGroupStdout(groupReports) if err != nil { t.Errorf("Reporting failed") } @@ -259,8 +256,7 @@ func Test_jsonReportSingleGroup(t *testing.T) { groupReports := map[string][]Report{"pass-fail": reports} - jsonReporter := JsonReporter{} - err := jsonReporter.PrintSingleGroup(groupReports) + err := PrintSingleGroupJson(groupReports) if err != nil { t.Errorf("Reporting failed") } @@ -292,8 +288,7 @@ func Test_jsonReportDoubleGroup(t *testing.T) { groupReports := map[string]map[string][]Report{"pass-fail": {"pass-fail": reports}, "filetype": {"filetype": reports}} - jsonReporter := JsonReporter{} - err := jsonReporter.PrintDoubleGroup(groupReports) + err := PrintDoubleGroupJson(groupReports) if err != nil { t.Errorf("Reporting failed") } @@ -328,9 +323,8 @@ func Test_jsonReportTripleGroup(t *testing.T) { "filetype": {"directory": {"pass-fail": reports}}, "directory": {"filetype": {"pass-fail": reports}}} - jsonReporter := JsonReporter{} - err := jsonReporter.PrintTripleGroup(groupReports) + err := PrintTripleGroupJson(groupReports) if err != nil { t.Errorf("Reporting failed") } -} \ No newline at end of file +} diff --git a/pkg/reporter/stdout_reporter.go b/pkg/reporter/stdout_reporter.go index ebb18ff4..dacc186c 100644 --- a/pkg/reporter/stdout_reporter.go +++ b/pkg/reporter/stdout_reporter.go @@ -33,11 +33,12 @@ func (sr StdoutReporter) Print(reports []Report) error { // There is repeated code in the following two functions. Trying to consolidate // the code into one function is difficult because of the output format -func (sr StdoutReporter) PrintSingleGroup(groupReport map[string][]Report) error { +func PrintSingleGroupStdout(groupReport map[string][]Report) error { var successCount = 0 var failureCount = 0 var totalSuccessCount = 0 var totalFailureCount = 0 + sr := StdoutReporter{} for group, reports := range groupReport { fmt.Printf("%s\n", group) successCount = 0 @@ -65,11 +66,12 @@ func (sr StdoutReporter) PrintSingleGroup(groupReport map[string][]Report) error } // Prints the report for when two groups are passed in the groupby flag -func (sr StdoutReporter) PrintDoubleGroup(groupReport map[string]map[string][]Report) error { +func PrintDoubleGroupStdout(groupReport map[string]map[string][]Report) error { var successCount = 0 var failureCount = 0 var totalSuccessCount = 0 var totalFailureCount = 0 + sr := StdoutReporter{} for group, reports := range groupReport { fmt.Printf("%s\n", group) @@ -102,11 +104,12 @@ func (sr StdoutReporter) PrintDoubleGroup(groupReport map[string]map[string][]Re } // Prints the report for when three groups are passed in the groupby flag -func (sr StdoutReporter) PrintTripleGroup(groupReport map[string]map[string]map[string][]Report) error { +func PrintTripleGroupStdout(groupReport map[string]map[string]map[string][]Report) error { var successCount = 0 var failureCount = 0 var totalSuccessCount = 0 var totalFailureCount = 0 + sr := StdoutReporter{} for groupOne, header := range groupReport { fmt.Printf("%s\n", groupOne) From 627b5c3f273fff33d896ba34ccf6e093c473962c Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 11 Dec 2023 13:41:51 -0800 Subject: [PATCH 45/48] Update GroupBy Filetype Updated grouping for filetypes to group mixed cases --- pkg/cli/group_output.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/cli/group_output.go b/pkg/cli/group_output.go index 123ed3cd..a1f62e41 100644 --- a/pkg/cli/group_output.go +++ b/pkg/cli/group_output.go @@ -13,6 +13,7 @@ func GroupByFile(reports []reporter.Report) map[string][]reporter.Report { for _, report := range reports { fileType := strings.Split(report.FileName, ".")[1] + fileType = strings.ToLower(fileType) if fileType == "yml" { fileType = "yaml" } From 5262344ace7e03810ecb6f110bcf7ef1f04cf06b Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 11 Dec 2023 20:27:14 -0800 Subject: [PATCH 46/48] GoFmt update Updated the group_output.go to align to gofmt standards --- pkg/cli/group_output.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cli/group_output.go b/pkg/cli/group_output.go index a1f62e41..15c45e48 100644 --- a/pkg/cli/group_output.go +++ b/pkg/cli/group_output.go @@ -13,7 +13,7 @@ func GroupByFile(reports []reporter.Report) map[string][]reporter.Report { for _, report := range reports { fileType := strings.Split(report.FileName, ".")[1] - fileType = strings.ToLower(fileType) + fileType = strings.ToLower(fileType) if fileType == "yml" { fileType = "yaml" } From df6ac8ce799d454d431771d47628eff254f144e0 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 18 Dec 2023 09:50:10 -0800 Subject: [PATCH 47/48] Update directory groupby Updated the directory groupby to check if the filepath is in Windows --- pkg/cli/group_output.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/pkg/cli/group_output.go b/pkg/cli/group_output.go index 15c45e48..02249367 100644 --- a/pkg/cli/group_output.go +++ b/pkg/cli/group_output.go @@ -53,9 +53,17 @@ func GroupByPassFail(reports []reporter.Report) map[string][]reporter.Report { func GroupByDirectory(reports []reporter.Report) map[string][]reporter.Report { reportByDirectory := make(map[string][]reporter.Report) for _, report := range reports { - directoryPath := strings.Split(report.FilePath, "/") - directory := strings.Join(directoryPath[:len(directoryPath)-1], "/") - directory = directory + "/" + directory := "" + // Check if the filepath is in Windows format + if strings.Contains(report.FilePath, "\\") { + directoryPath := strings.Split(report.FilePath, "\\") + directory = strings.Join(directoryPath[:len(directoryPath)-1], "\\") + directory = directory + "\\" + } else { + directoryPath := strings.Split(report.FilePath, "/") + directory = strings.Join(directoryPath[:len(directoryPath)-1], "/") + directory = directory + "/" + } if reportByDirectory[directory] == nil { reportByDirectory[directory] = []reporter.Report{report} From 99fb5b812420b17ddb7a5c8c2903bb29af4ac2e2 Mon Sep 17 00:00:00 2001 From: Jake Murphy Date: Mon, 18 Dec 2023 11:52:23 -0800 Subject: [PATCH 48/48] Add GroupBy Directory test Added a test for the GroupBy directory flag for Windows and other directory paths --- pkg/cli/group_output.go | 4 ++-- pkg/cli/group_output_test.go | 39 ++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/pkg/cli/group_output.go b/pkg/cli/group_output.go index 02249367..e5015e85 100644 --- a/pkg/cli/group_output.go +++ b/pkg/cli/group_output.go @@ -8,7 +8,7 @@ import ( ) // Group Reports by File Type -func GroupByFile(reports []reporter.Report) map[string][]reporter.Report { +func GroupByFileType(reports []reporter.Report) map[string][]reporter.Report { reportByFile := make(map[string][]reporter.Report) for _, report := range reports { @@ -86,7 +86,7 @@ func GroupBySingle(reports []reporter.Report, groupBy string) (map[string][]repo case "pass-fail": groupReport = GroupByPassFail(reports) case "filetype": - groupReport = GroupByFile(reports) + groupReport = GroupByFileType(reports) case "directory": groupReport = GroupByDirectory(reports) default: diff --git a/pkg/cli/group_output_test.go b/pkg/cli/group_output_test.go index cbc5f298..3e51023c 100644 --- a/pkg/cli/group_output_test.go +++ b/pkg/cli/group_output_test.go @@ -71,6 +71,45 @@ func Test_SingleGroupOutput(t *testing.T) { } } +func Test_WindowsDirectoryGroupBy(t *testing.T) { + reports := []reporter.Report{ + { + FileName: "test", + FilePath: "test\\test\\test", + }, + { + FileName: "test2", + FilePath: "test2\\test2\\test2", + }, + } + + groupDirectory := GroupByDirectory(reports) + + if len(groupDirectory) != 2 { + t.Errorf("GroupByDirectory did not group correctly") + } + +} + +func Test_DirectoryGroupBy(t *testing.T) { + reports := []reporter.Report{ + { + FileName: "test", + FilePath: "test/test/test", + }, + { + FileName: "test2", + FilePath: "test2/test2/test2", + }, + } + + groupDirectory := GroupByDirectory(reports) + + if len(groupDirectory) != 2 { + t.Errorf("GroupByDirectory did not group correctly") + } + +} func Test_DoubleGroupOutput(t *testing.T) { searchPath := "../../test" excludeDirs := []string{"subdir", "subdir2"}