diff --git a/cmd/root.go b/cmd/root.go index e4822d03..55bcada6 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -45,13 +45,14 @@ import ( var ( // flags - exitOneOnFailure bool - cfgFile string - debug bool - stdin bool - outputName string - noIgnore bool - disableDefaultRules bool + exitOneOnFailure bool + countOnlyErrorForFailure bool + cfgFile string + debug bool + stdin bool + outputName string + noIgnore bool + disableDefaultRules bool // Version is populated by goreleaser during build // Version... @@ -121,7 +122,7 @@ func rootRunE(cmd *cobra.Command, args []string) error { return err } - findings := p.ParsePaths(print, parseArgs(args)...) + findings := p.ParsePaths(print, countOnlyErrorForFailure, parseArgs(args)...) if exitOneOnFailure && findings > 0 { // We intentionally return an error if exitOneOnFailure is true, but don't want to show usage @@ -150,6 +151,7 @@ func init() { rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "Config file (default is .woke.yaml in current directory, or $HOME)") rootCmd.PersistentFlags().BoolVar(&exitOneOnFailure, "exit-1-on-failure", false, "Exit with exit code 1 on failures") + rootCmd.PersistentFlags().BoolVar(&countOnlyErrorForFailure, "count-only-error-for-failure", false, "Count only error items, not warning and info, for failure") rootCmd.PersistentFlags().BoolVar(&stdin, "stdin", false, "Read from stdin") rootCmd.PersistentFlags().BoolVar(&debug, "debug", false, "Enable debug logging") rootCmd.PersistentFlags().BoolVar(&noIgnore, "no-ignore", false, "Ignored files in .gitignore, .ignore, .wokeignore, .git/info/exclude, and inline ignores are processed") diff --git a/docs/snippets/woke.md b/docs/snippets/woke.md index 0897d148..bff52be6 100644 --- a/docs/snippets/woke.md +++ b/docs/snippets/woke.md @@ -21,14 +21,15 @@ woke [globs ...] [flags] ### Options ``` - -c, --config string Config file (default is .woke.yaml in current directory, or $HOME) - --debug Enable debug logging - --disable-default-rules Disable the default ruleset - --exit-1-on-failure Exit with exit code 1 on failures - -h, --help help for woke - --no-ignore Ignored files in .gitignore, .ignore, .wokeignore, .git/info/exclude, and inline ignores are processed - -o, --output string Output type [text,simple,github-actions,json,sonarqube,checkstyle] (default "text") - --stdin Read from stdin + -c, --config string Config file (default is .woke.yaml in current directory, or $HOME) + --count-only-error-for-failure Count only error items, not warning and info, for failure + --debug Enable debug logging + --disable-default-rules Disable the default ruleset + --exit-1-on-failure Exit with exit code 1 on failures + -h, --help help for woke + --no-ignore Ignored files in .gitignore, .ignore, .wokeignore, .git/info/exclude, and inline ignores are processed + -o, --output string Output type [text,simple,github-actions,json,sonarqube,checkstyle] (default "text") + --stdin Read from stdin ``` ###### Auto generated by spf13/cobra on 18-Mar-2022 diff --git a/pkg/parser/parser.go b/pkg/parser/parser.go index a542b7f3..0d108df5 100644 --- a/pkg/parser/parser.go +++ b/pkg/parser/parser.go @@ -41,7 +41,7 @@ func NewParser(rules []*rule.Rule, ignorer *ignore.Ignore) *Parser { } // ParsePaths parses all files provided and returns the number of files with findings -func (p *Parser) ParsePaths(print printer.Printer, paths ...string) int { +func (p *Parser) ParsePaths(print printer.Printer, countOnlyErrorForFailure bool, paths ...string) int { print.Start() defer print.End() @@ -79,7 +79,9 @@ func (p *Parser) ParsePaths(print printer.Printer, paths ...string) int { for r := range p.rchan { sort.Sort(r) print.Print(&r) - findings++ + if !countOnlyErrorForFailure || r.HasError() { + findings++ + } } return findings } diff --git a/pkg/parser/parser_test.go b/pkg/parser/parser_test.go index 639395e7..ce6acd62 100644 --- a/pkg/parser/parser_test.go +++ b/pkg/parser/parser_test.go @@ -59,7 +59,7 @@ func parsePathTests(t *testing.T) { pr := new(testPrinter) p, err := testParser() assert.NoError(t, err) - findings := p.ParsePaths(pr, f.Name()) + findings := p.ParsePaths(pr, false, f.Name()) assert.Len(t, pr.results, 1) assert.Equal(t, len(pr.results), findings) @@ -96,7 +96,7 @@ func parsePathTests(t *testing.T) { p, err := testParser() assert.NoError(t, err) pr := new(testPrinter) - findings := p.ParsePaths(pr, f.Name()) + findings := p.ParsePaths(pr, false, f.Name()) assert.Len(t, pr.results, 0) assert.Equal(t, len(pr.results), findings) }) @@ -108,7 +108,7 @@ func parsePathTests(t *testing.T) { p, err := testParser() assert.NoError(t, err) pr := new(testPrinter) - findings := p.ParsePaths(pr, f.Name()) + findings := p.ParsePaths(pr, false, f.Name()) assert.Len(t, pr.results, 1) assert.Equal(t, len(pr.results), findings) }) @@ -120,7 +120,7 @@ func parsePathTests(t *testing.T) { p, err := testParser() assert.NoError(t, err) pr := new(testPrinter) - findings := p.ParsePaths(pr, f.Name()) + findings := p.ParsePaths(pr, false, f.Name()) assert.Len(t, pr.results, 0) assert.Equal(t, len(pr.results), findings) }) @@ -135,7 +135,7 @@ func parsePathTests(t *testing.T) { p, err := testParser() assert.NoError(t, err) pr := new(testPrinter) - findings := p.ParsePaths(pr, f1.Name(), f2.Name()) + findings := p.ParsePaths(pr, false, f1.Name(), f2.Name()) assert.Len(t, pr.results, 1) assert.Equal(t, len(pr.results), findings) }) @@ -154,7 +154,7 @@ func parsePathTests(t *testing.T) { p.Ignorer = ignorer pr := new(testPrinter) - findings := p.ParsePaths(pr, f.Name()) + findings := p.ParsePaths(pr, false, f.Name()) assert.Len(t, pr.results, 0) assert.Equal(t, len(pr.results), findings) }) @@ -167,7 +167,7 @@ func parsePathTests(t *testing.T) { assert.NoError(t, err) pr := new(testPrinter) - findings := p.ParsePaths(pr, f.Name()) + findings := p.ParsePaths(pr, false, f.Name()) assert.Len(t, pr.results, 0) assert.Equal(t, len(pr.results), findings) }) @@ -181,7 +181,7 @@ func parsePathTests(t *testing.T) { p.Ignorer = nil pr := new(testPrinter) - findings := p.ParsePaths(pr, f.Name()) + findings := p.ParsePaths(pr, false, f.Name()) assert.Len(t, pr.results, 1) assert.Equal(t, len(pr.results), findings) }) @@ -197,7 +197,7 @@ func parsePathTests(t *testing.T) { assert.NoError(t, err) p.Ignorer = ignorer pr := new(testPrinter) - findings := p.ParsePaths(pr) + findings := p.ParsePaths(pr, false) assert.Equal(t, len(pr.results), findings) assert.Equal(t, len(pr.results), 0) @@ -208,7 +208,7 @@ func parsePathTests(t *testing.T) { p, err := testParser() assert.NoError(t, err) pr := new(testPrinter) - findings := p.ParsePaths(pr, os.Stdin.Name()) + findings := p.ParsePaths(pr, false, os.Stdin.Name()) assert.Len(t, pr.results, 1) assert.Equal(t, len(pr.results), findings) @@ -249,7 +249,7 @@ func parsePathTests(t *testing.T) { p.Rules[0].Note = TestNote p.Rules[0].Options.IncludeNote = nil pr := new(testPrinter) - p.ParsePaths(pr, f.Name()) + p.ParsePaths(pr, false, f.Name()) assert.NotContains(t, pr.results[0].Results[0].Reason(), TestNote) }) @@ -266,7 +266,7 @@ func parsePathTests(t *testing.T) { // Test IncludeNote flag doesn't get overridden with SetIncludeNote method p.Rules[0].SetIncludeNote(false) pr := new(testPrinter) - p.ParsePaths(pr, f.Name()) + p.ParsePaths(pr, false, f.Name()) assert.Contains(t, pr.results[0].Results[0].Reason(), TestNote) }) @@ -323,7 +323,7 @@ func BenchmarkParsePaths(b *testing.B) { p, err := testParser() assert.NoError(b, err) pr := new(testPrinter) - findings := p.ParsePaths(pr, tmpFile.Name()) + findings := p.ParsePaths(pr, false, tmpFile.Name()) assert.Equal(b, 1, findings) } } @@ -338,7 +338,7 @@ func BenchmarkParsePathsRoot(b *testing.B) { pr := new(testPrinter) // Unknown how many findings this will return since it's parsing the whole repo // there's no way to know for sure at any given time, so just check that it doesn't panic - _ = p.ParsePaths(pr, "../..") + _ = p.ParsePaths(pr, false, "../..") }) } } diff --git a/pkg/result/fileresults.go b/pkg/result/fileresults.go index 4f72e578..a720d7c0 100644 --- a/pkg/result/fileresults.go +++ b/pkg/result/fileresults.go @@ -34,3 +34,14 @@ func (fr FileResults) Less(i, j int) bool { return fr.Results[i].GetStartPosition().Line < fr.Results[j].GetStartPosition().Line } + +// Returns true if any of the rule severity for the results is "error". +// Returns false if all the rule severity for the results are "warning" or "info". +func (fr FileResults) HasError() bool { + for _, r := range fr.Results { + if r.GetSeverity().String() == "error" { + return true + } + } + return false +}