Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cli option to group reporter output. Closes #38 #92

Merged
Merged
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
fb451a1
Add GroupBy command
jcsmurph Nov 19, 2023
fdb4d5f
Add multiple groupby commands and validation
jcsmurph Nov 19, 2023
4e048fd
Add Tests
jcsmurph Nov 19, 2023
5683cb6
Reformat groupBy
jcsmurph Nov 20, 2023
a88b172
Add Test Files
jcsmurph Nov 20, 2023
7800a50
Update grouping order and update readme
jcsmurph Nov 20, 2023
853efbd
Fix groupby directory
jcsmurph Nov 20, 2023
bd74941
Update Tests
jcsmurph Nov 20, 2023
ca546e4
Fix Comment
jcsmurph Nov 20, 2023
e61be66
Update README.md
jcsmurph Nov 20, 2023
1140303
Update cli_test.go
jcsmurph Nov 20, 2023
b333ed2
Update validator.go
jcsmurph Nov 20, 2023
42e0c50
Update validator_test.go
jcsmurph Nov 20, 2023
1264e99
Update group_output.go
jcsmurph Nov 20, 2023
49de011
Update README.md
jcsmurph Nov 20, 2023
89718be
Update validator.go
jcsmurph Nov 20, 2023
367bd49
Update group_output.go
jcsmurph Nov 20, 2023
438275f
Update validator.go
jcsmurph Nov 20, 2023
741a1ca
Update cli_test.go
jcsmurph Nov 20, 2023
1f21c25
Update group_output.go
jcsmurph Nov 20, 2023
8dc47c6
Formatting fix
jcsmurph Nov 21, 2023
a90a888
Add Group output
jcsmurph Nov 21, 2023
a7b3335
Implement Group Output standard out
jcsmurph Nov 22, 2023
0aa37a3
Implement Single Groupby JSON
jcsmurph Nov 22, 2023
64acf60
Refactor GroupBy
jcsmurph Nov 22, 2023
2429073
Refactor GroupByTwo
jcsmurph Nov 22, 2023
3060971
Update to Stdout
jcsmurph Nov 22, 2023
16e341a
Implement JSON single group
jcsmurph Nov 23, 2023
01ddc54
Implement JSON double group and tests
jcsmurph Nov 23, 2023
d3391a1
Update go fmt
jcsmurph Nov 23, 2023
a190abc
Implement triple group output
jcsmurph Nov 23, 2023
f41a5e0
Add Output Tests
jcsmurph Nov 23, 2023
888f74a
Clean comments
jcsmurph Nov 23, 2023
6898103
Changed Summary Format
jcsmurph Nov 23, 2023
8452661
Update README.md
jcsmurph Nov 30, 2023
5bb439c
Update cmd/validator/validator.go
jcsmurph Nov 30, 2023
e893ee0
Add Header Comments
jcsmurph Dec 4, 2023
4fdb835
Fix Naming Conflict
jcsmurph Dec 4, 2023
a084cc7
Add Util function for Json Reporter
jcsmurph Dec 5, 2023
1a3db98
Rename Utility Function
jcsmurph Dec 5, 2023
eb2dfc1
Rename Utility Function Calls
jcsmurph Dec 5, 2023
bb5f191
Update JSON Print
jcsmurph Dec 5, 2023
e26c7cc
Update STD Reporter Test
jcsmurph Dec 11, 2023
fd2c8e8
Merge branch 'main' into Add-CLI-option-to-group-reporter-output-#38
jcsmurph Dec 11, 2023
3bf77db
Refactor Reporter
jcsmurph Dec 11, 2023
627b5c3
Update GroupBy Filetype
jcsmurph Dec 11, 2023
5262344
GoFmt update
jcsmurph Dec 12, 2023
df6ac8c
Update directory groupby
jcsmurph Dec 18, 2023
99fb5b8
Add GroupBy Directory test
jcsmurph Dec 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
@@ -103,6 +103,8 @@ 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. Supported Reporters are Standard and JSON
-reporter string
Format of the printed report. Options are standard and json (default "standard")
-version
@@ -130,7 +132,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 +147,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
@@ -162,6 +164,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
```
@@ -242,4 +252,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
The Config File Validator is released under the [Apache 2.0](/LICENSE) License
47 changes: 46 additions & 1 deletion cmd/validator/validator.go
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@ import (
"fmt"
"log"
"os"
"slices"
"strings"

configfilevalidator "github.com/Boeing/config-file-validator"
@@ -46,6 +47,7 @@ type validatorConfig struct {
reportType *string
depth *int
versionQuery *bool
groupOutput *string
}

// Custom Usage function to cover
@@ -71,6 +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. Supported for Standard and JSON reports")
flag.Parse()

searchPaths := make([]string, 0)
@@ -90,19 +93,48 @@ 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()
return validatorConfig{}, errors.New("Wrong parameter value for depth, value cannot be negative")
}

groupByCleanString := cleanString("groupby")
groupByUserInput := strings.Split(groupByCleanString, ",")
groupByAllowedValues := []string{"filetype", "directory", "pass-fail"}
seenValues := make(map[string]bool)

// Check that the groupby values are valid and not duplicates
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")
}
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
}
}

config := validatorConfig{
searchPaths,
excludeDirsPtr,
excludeFileTypesPtr,
reportTypePtr,
depthPtr,
versionPtr,
groupOutputPtr,
}

return config, nil
@@ -134,6 +166,16 @@ func getReporter(reportType *string) reporter.Reporter {
}
}

// cleanString takes a command string and a split string
// and returns a cleaned string
func cleanString(command string) string {
cleanedString := flag.Lookup(command).Value.String()
cleanedString = strings.ToLower(cleanedString)
cleanedString = strings.TrimSpace(cleanedString)

return cleanedString
}

func mainInit() int {
validatorConfig, err := getFlags()
if err != nil {
@@ -148,8 +190,10 @@ 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, ",")
groupOutput := strings.Split(*validatorConfig.groupOutput, ",")

reporter := getReporter(validatorConfig.reportType)

fsOpts := []finder.FSFinderOptions{finder.WithPathRoots(validatorConfig.searchPaths...),
finder.WithExcludeDirs(excludeDirs),
@@ -166,6 +210,7 @@ func mainInit() int {
cli := cli.Init(
cli.WithReporter(reporter),
cli.WithFinder(fileSystemFinder),
cli.WithGroupOutput(groupOutput),
)

// Run the config file validation
2 changes: 2 additions & 0 deletions cmd/validator/validator_test.go
Original file line number Diff line number Diff line change
@@ -27,6 +27,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,
48 changes: 47 additions & 1 deletion pkg/cli/cli.go
Original file line number Diff line number Diff line change
@@ -8,6 +8,10 @@ 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 {
// FileFinder interface to search for the files
// in the SearchPath
@@ -36,6 +40,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 +98,43 @@ func (c CLI) Run() (int, error) {
reports = append(reports, report)
}

c.Reporter.Print(reports)
// Group the output if the user specified a group by option
// 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)
}
// 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)
}
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)
}
if _, ok := c.Reporter.(reporter.JsonReporter); ok {
reporter.PrintTripleGroupJson(reportGroup)
} else {
reporter.PrintTripleGroupStdout(reportGroup)
}
} else {
c.Reporter.Print(reports)
}

if errorFound {
return 1, nil
28 changes: 28 additions & 0 deletions pkg/cli/cli_test.go
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ import (
func Test_CLI(t *testing.T) {
searchPath := "../../test"
excludeDirs := []string{"subdir", "subdir2"}
groupOutput := []string{""}
stdoutReporter := reporter.StdoutReporter{}

fsFinder := finder.FileSystemFinderInit(
@@ -19,6 +20,7 @@ func Test_CLI(t *testing.T) {
cli := Init(
WithFinder(fsFinder),
WithReporter(stdoutReporter),
WithGroupOutput(groupOutput),
)
exitStatus, err := cli.Run()

@@ -70,3 +72,29 @@ func Test_CLIBadPath(t *testing.T) {
t.Errorf("Exit status was not 1")
}
}

func Test_CLIWithGroup(t *testing.T) {
searchPath := "../../test"
excludeDirs := []string{"subdir", "subdir2"}
groupOutput := []string{"pass-fail", "directory"}
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")
}
}
Loading