diff --git a/pkg/config/config.go b/pkg/config/config.go index ede6d3e..6b1232b 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -71,7 +71,7 @@ func FromFlags(progName string, args []string) (Config, string, error) { flags.BoolVar(&c.Summary, "summary", false, "print a summary at the end") flags.IntVar(&c.NumberOfWorkers, "n", 4, "number of goroutines to run concurrently") flags.BoolVar(&c.Strict, "strict", false, "disallow additional properties not in schema") - flags.StringVar(&c.OutputFormat, "output", "text", "output format - text, json") + flags.StringVar(&c.OutputFormat, "output", "text", "output format - json, tap, text") flags.BoolVar(&c.Verbose, "verbose", false, "print results for all resources") flags.BoolVar(&c.SkipTLS, "insecure-skip-tls-verify", false, "disable verification of the server's SSL certificate. This will make your HTTPS connections insecure") flags.BoolVar(&c.Help, "h", false, "show help information") diff --git a/pkg/output/output.go b/pkg/output/output.go index 82b3dd7..3dce1b7 100644 --- a/pkg/output/output.go +++ b/pkg/output/output.go @@ -16,11 +16,13 @@ func New(outputFormat string, printSummary, isStdin, verbose bool) (Output, erro w := os.Stdout switch { - case outputFormat == "text": - return textOutput(w, printSummary, isStdin, verbose), nil case outputFormat == "json": return jsonOutput(w, printSummary, isStdin, verbose), nil + case outputFormat == "tap": + return tapOutput(w, printSummary, isStdin, verbose), nil + case outputFormat == "text": + return textOutput(w, printSummary, isStdin, verbose), nil default: - return nil, fmt.Errorf("`outputFormat` must be 'text' or 'json'") + return nil, fmt.Errorf("`outputFormat` must be 'json', 'tap' or 'text'") } } diff --git a/pkg/output/tap.go b/pkg/output/tap.go new file mode 100644 index 0000000..774f307 --- /dev/null +++ b/pkg/output/tap.go @@ -0,0 +1,67 @@ +package output + +import ( + "fmt" + "io" + + "github.com/yannh/kubeconform/pkg/validator" +) + +type tapo struct { + w io.Writer + withSummary bool + verbose bool + results []validator.Result + nValid, nInvalid, nErrors, nSkipped int +} + +func tapOutput(w io.Writer, withSummary bool, isStdin, verbose bool) Output { + return &tapo{ + w: w, + withSummary: withSummary, + verbose: verbose, + results: []validator.Result{}, + nValid: 0, + nInvalid: 0, + nErrors: 0, + nSkipped: 0, + } +} + +// JSON.Write will only write when JSON.Flush has been called +func (o *tapo) Write(result validator.Result) error { + o.results = append(o.results, result) + return nil +} + +// Flush outputs the results as JSON +func (o *tapo) Flush() error { + var err error + + fmt.Fprintf(o.w, "1..%d\n", len(o.results)) + for i, res := range o.results { + switch res.Status { + case validator.Valid: + sig, _ := res.Resource.Signature() + fmt.Fprintf(o.w, "ok %d - %s (%s)\n", i, res.Resource.Path, sig.Kind) + + case validator.Invalid: + sig, _ := res.Resource.Signature() + fmt.Fprintf(o.w, "not ok %d - %s (%s): %s\n", i, res.Resource.Path, sig.Kind, res.Err.Error()) + + case validator.Empty: + fmt.Fprintf(o.w, "ok %d - %s (empty)\n", i, res.Resource.Path) + + case validator.Error: + fmt.Fprintf(o.w, "not ok %d - %s: %s\n", i, res.Resource.Path, res.Err.Error()) + + case validator.Skipped: + fmt.Fprintf(o.w, "ok %d #skip - %s\n", i, res.Resource.Path) + } + } + if err != nil { + return err + } + + return nil +}