diff --git a/main.go b/main.go index 613affd..88abc1f 100644 --- a/main.go +++ b/main.go @@ -65,6 +65,7 @@ func validateFile(f io.Reader, regs []registry.Registry, k8sVersion string, c *c } } + // Cache both found & not found c.Set(cacheKey, schema) if err != nil { // Not found @@ -94,6 +95,7 @@ func realMain() int { var skipKinds, k8sVersion, outputFormat string var printSummary, strict bool var nWorkers int + var quiet bool flag.BoolVar(&printSummary, "printsummary", false, "print a summary at the end") flag.Var(&files, "file", "file to validate (can be specified multiple times)") @@ -104,14 +106,15 @@ func realMain() int { flag.StringVar(&skipKinds, "skipKinds", "", "comma-separated list of kinds to ignore") flag.BoolVar(&strict, "strict", false, "activate strict mode") flag.StringVar(&outputFormat, "output", "text", "output format - text, json") + flag.BoolVar(&quiet, "quiet", false, "quiet output - only print invalid files, and errors") flag.Parse() var o output.Output switch { case outputFormat == "text": - o = output.NewTextOutput(printSummary) + o = output.NewTextOutput(printSummary, quiet) case outputFormat == "json": - o = output.NewJSONOutput(printSummary) + o = output.NewJSONOutput(printSummary, quiet) default: log.Fatalf("-output must be text or json") } diff --git a/pkg/cache/main.go b/pkg/cache/main.go index aef9c9a..f34288a 100644 --- a/pkg/cache/main.go +++ b/pkg/cache/main.go @@ -24,7 +24,7 @@ func Key(resourceKind, resourceAPIVersion, k8sVersion string) string { func (c *SchemaCache) Get(key string) (*gojsonschema.Schema, bool) { c.RLock() defer c.RUnlock() - schema, ok := c.schemas[key] + schema, ok := c.schemas[key] return schema, ok } diff --git a/pkg/output/json.go b/pkg/output/json.go index 357a066..b5a0f1a 100644 --- a/pkg/output/json.go +++ b/pkg/output/json.go @@ -3,6 +3,7 @@ package output import ( "encoding/json" "fmt" + "sync" ) type result struct { @@ -12,35 +13,51 @@ type result struct { } type JSONOutput struct { - withSummary bool - results []result + sync.Mutex + withSummary bool + quiet bool + results []result + nValid, nInvalid, nErrors, nSkipped int } -func NewJSONOutput(withSummary bool) Output { +func NewJSONOutput(withSummary bool, quiet bool) Output { return &JSONOutput{ withSummary: withSummary, + quiet: quiet, results: []result{}, + nValid: 0, + nInvalid: 0, + nErrors: 0, + nSkipped: 0, } } func (o *JSONOutput) Write(filename string, err error, skipped bool) { + o.Lock() + defer o.Unlock() msg, st := "", "" s := status(err, skipped) switch { case s == VALID: st = "VALID" + o.nValid++ case s == INVALID: st = "INVALID" msg = err.Error() + o.nInvalid++ case s == ERROR: st = "ERROR" msg = err.Error() + o.nErrors++ case s == SKIPPED: st = "SKIPPED" + o.nSkipped++ } - o.results = append(o.results, result{Filename: filename, Status: st, Msg: msg}) + if !o.quiet || (s != VALID && s != SKIPPED) { + o.results = append(o.results, result{Filename: filename, Status: st, Msg: msg}) + } } func (o *JSONOutput) Flush() { @@ -58,25 +75,23 @@ func (o *JSONOutput) Flush() { } `json:"summary"` }{ Resources: o.results, - } - - for _, r := range o.results { - switch { - case r.Status == "VALID": - jsonObj.Summary.Valid++ - case r.Status == "INVALID": - jsonObj.Summary.Invalid++ - case r.Status == "ERROR": - jsonObj.Summary.Errors++ - case r.Status == "SKIPPED": - jsonObj.Summary.Skipped++ - } + Summary: struct { + Valid int `json:"valid"` + Invalid int `json:"invalid"` + Errors int `json:"errors"` + Skipped int `json:"skipped"` + }{ + Valid: o.nValid, + Invalid: o.nInvalid, + Errors: o.nErrors, + Skipped: o.nSkipped, + }, } res, err = json.MarshalIndent(jsonObj, "", " ") } else { jsonObj := struct { - Resources []result + Resources []result `json:"resources"` }{ Resources: o.results, } diff --git a/pkg/output/text.go b/pkg/output/text.go index 082cd7e..a1a0a7f 100644 --- a/pkg/output/text.go +++ b/pkg/output/text.go @@ -2,22 +2,37 @@ package output import ( "fmt" + "sync" ) type TextOutput struct { + sync.Mutex withSummary bool + quiet bool nValid, nInvalid, nErrors, nSkipped int } -func NewTextOutput(withSummary bool) Output { - return &TextOutput{withSummary, 0, 0, 0, 0} +func NewTextOutput(withSummary, quiet bool) Output { + return &TextOutput{ + withSummary: withSummary, + quiet: quiet, + nValid: 0, + nInvalid: 0, + nErrors: 0, + nSkipped: 0, + } } func (o *TextOutput) Write(filename string, err error, skipped bool) { + o.Lock() + defer o.Unlock() + s := status(err, skipped) switch { case s == VALID: - fmt.Printf("file %s is valid\n", filename) + if !o.quiet { + fmt.Printf("file %s is valid\n", filename) + } o.nValid++ case s == INVALID: fmt.Printf("invalid resource: %s\n", err) @@ -26,7 +41,9 @@ func (o *TextOutput) Write(filename string, err error, skipped bool) { fmt.Printf("failed validating resource in file %s: %s\n", filename, err) o.nErrors++ case s == SKIPPED: - fmt.Printf("skipping resource\n") + if !o.quiet { + fmt.Printf("skipping resource\n") + } o.nSkipped++ } }