refactor output

This commit is contained in:
Yann Hamon 2020-10-31 14:29:13 +01:00
parent 456f255478
commit ea8ecafa38
6 changed files with 51 additions and 49 deletions

View file

@ -135,19 +135,6 @@ func (ap *arrayParam) Set(value string) error {
return nil return nil
} }
func getLogger(outputFormat string, printSummary, isStdin, verbose bool) (output.Output, error) {
w := os.Stdout
switch {
case outputFormat == "text":
return output.Text(w, printSummary, isStdin, verbose), nil
case outputFormat == "json":
return output.JSON(w, printSummary, isStdin, verbose), nil
default:
return nil, fmt.Errorf("-output must be text or json")
}
}
func skipKindsMap(skipKindsCSV string) map[string]bool { func skipKindsMap(skipKindsCSV string) map[string]bool {
splitKinds := strings.Split(skipKindsCSV, ",") splitKinds := strings.Split(skipKindsCSV, ",")
skipKinds := map[string]bool{} skipKinds := map[string]bool{}
@ -289,7 +276,7 @@ func realMain() int {
}() }()
var o output.Output var o output.Output
if o, err = getLogger(outputFormat, summary, isStdin, verbose); err != nil { if o, err = output.New(outputFormat, summary, isStdin, verbose); err != nil {
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)
return 1 return 1
} }

View file

@ -24,7 +24,7 @@ type jsono struct {
} }
// JSON will output the results of the validation as a JSON // JSON will output the results of the validation as a JSON
func JSON(w io.Writer, withSummary bool, isStdin, verbose bool) Output { func jsonOutput(w io.Writer, withSummary bool, isStdin, verbose bool) Output {
return &jsono{ return &jsono{
w: w, w: w,
withSummary: withSummary, withSummary: withSummary,
@ -44,24 +44,24 @@ func (o *jsono) Write(filename, kind, name, version string, err error, skipped b
s := status(kind, name, err, skipped) s := status(kind, name, err, skipped)
switch s { switch s {
case VALID: case statusValid:
st = "VALID" st = "statusValid"
o.nValid++ o.nValid++
case INVALID: case statusInvalid:
st = "INVALID" st = "statusInvalid"
msg = err.Error() msg = err.Error()
o.nInvalid++ o.nInvalid++
case ERROR: case statusError:
st = "ERROR" st = "statusError"
msg = err.Error() msg = err.Error()
o.nErrors++ o.nErrors++
case SKIPPED: case statusSkipped:
st = "SKIPPED" st = "statusSkipped"
o.nSkipped++ o.nSkipped++
case EMPTY: case statusEmpty:
} }
if o.verbose || (s != VALID && s != SKIPPED && s != EMPTY) { if o.verbose || (s != statusValid && s != statusSkipped && s != statusEmpty) {
o.results = append(o.results, result{Filename: filename, Kind: kind, Name: name, Version: version, Status: st, Msg: msg}) o.results = append(o.results, result{Filename: filename, Kind: kind, Name: name, Version: version, Status: st, Msg: msg})
} }

View file

@ -85,7 +85,7 @@ func TestJSONWrite(t *testing.T) {
"kind": "Deployment", "kind": "Deployment",
"name": "my-app", "name": "my-app",
"version": "apps/v1", "version": "apps/v1",
"status": "VALID", "status": "statusValid",
"msg": "" "msg": ""
} }
], ],
@ -100,7 +100,7 @@ func TestJSONWrite(t *testing.T) {
}, },
} { } {
w := new(bytes.Buffer) w := new(bytes.Buffer)
o := JSON(w, testCase.withSummary, false, testCase.verbose) o := jsonOutput(w, testCase.withSummary, false, testCase.verbose)
for _, res := range testCase.res { for _, res := range testCase.res {
o.Write(res.fileName, res.kind, res.name, res.version, res.err, res.skipped) o.Write(res.fileName, res.kind, res.name, res.version, res.err, res.skipped)

View file

@ -1,16 +1,18 @@
package output package output
import ( import (
"fmt"
"github.com/yannh/kubeconform/pkg/validator" "github.com/yannh/kubeconform/pkg/validator"
"os"
) )
const ( const (
_ = iota _ = iota
VALID statusValid
INVALID statusInvalid
ERROR statusError
SKIPPED statusSkipped
EMPTY statusEmpty
) )
type Output interface { type Output interface {
@ -18,21 +20,34 @@ type Output interface {
Flush() error Flush() error
} }
func New(outputFormat string, printSummary, isStdin, verbose bool) (Output, error) {
w := os.Stdout
switch {
case outputFormat == "text":
return textOutput(w, printSummary, isStdin, verbose), nil
case outputFormat == "json":
return jsonOutput(w, printSummary, isStdin, verbose), nil
default:
return nil, fmt.Errorf("`outputFormat` must be 'text' or 'json'")
}
}
func status(kind, name string, err error, skipped bool) int { func status(kind, name string, err error, skipped bool) int {
if name == "" && kind == "" && err == nil && skipped == false { if name == "" && kind == "" && err == nil && skipped == false {
return EMPTY return statusEmpty
} }
if skipped { if skipped {
return SKIPPED return statusSkipped
} }
if err != nil { if err != nil {
if _, ok := err.(validator.InvalidResourceError); ok { if _, ok := err.(validator.InvalidResourceError); ok {
return INVALID return statusInvalid
} }
return ERROR return statusError
} }
return VALID return statusValid
} }

View file

@ -6,7 +6,7 @@ import (
"sync" "sync"
) )
type text struct { type texto struct {
sync.Mutex sync.Mutex
w io.Writer w io.Writer
withSummary bool withSummary bool
@ -16,9 +16,9 @@ type text struct {
nValid, nInvalid, nErrors, nSkipped int nValid, nInvalid, nErrors, nSkipped int
} }
// Text will output the results of the validation as a text // Text will output the results of the validation as a texto
func Text(w io.Writer, withSummary, isStdin, verbose bool) Output { func textOutput(w io.Writer, withSummary, isStdin, verbose bool) Output {
return &text{ return &texto{
w: w, w: w,
withSummary: withSummary, withSummary: withSummary,
isStdin: isStdin, isStdin: isStdin,
@ -31,7 +31,7 @@ func Text(w io.Writer, withSummary, isStdin, verbose bool) Output {
} }
} }
func (o *text) Write(filename, kind, name, version string, reserr error, skipped bool) error { func (o *texto) Write(filename, kind, name, version string, reserr error, skipped bool) error {
o.Lock() o.Lock()
defer o.Unlock() defer o.Unlock()
@ -39,33 +39,33 @@ func (o *text) Write(filename, kind, name, version string, reserr error, skipped
o.files[filename] = true o.files[filename] = true
switch status(kind, name, reserr, skipped) { switch status(kind, name, reserr, skipped) {
case VALID: case statusValid:
if o.verbose { if o.verbose {
_, err = fmt.Fprintf(o.w, "%s - %s %s is valid\n", filename, kind, name) _, err = fmt.Fprintf(o.w, "%s - %s %s is valid\n", filename, kind, name)
} }
o.nValid++ o.nValid++
case INVALID: case statusInvalid:
_, err = fmt.Fprintf(o.w, "%s - %s %s is invalid: %s\n", filename, kind, name, reserr) _, err = fmt.Fprintf(o.w, "%s - %s %s is invalid: %s\n", filename, kind, name, reserr)
o.nInvalid++ o.nInvalid++
case ERROR: case statusError:
if kind != "" && name != "" { if kind != "" && name != "" {
_, err = fmt.Fprintf(o.w, "%s - %s %s failed validation: %s\n", filename, kind, name, reserr) _, err = fmt.Fprintf(o.w, "%s - %s %s failed validation: %s\n", filename, kind, name, reserr)
} else { } else {
_, err = fmt.Fprintf(o.w, "%s - failed validation: %s\n", filename, reserr) _, err = fmt.Fprintf(o.w, "%s - failed validation: %s\n", filename, reserr)
} }
o.nErrors++ o.nErrors++
case SKIPPED: case statusSkipped:
if o.verbose { if o.verbose {
_, err = fmt.Fprintf(o.w, "%s - %s %s skipped\n", filename, name, kind) _, err = fmt.Fprintf(o.w, "%s - %s %s skipped\n", filename, name, kind)
} }
o.nSkipped++ o.nSkipped++
case EMPTY: // sent to ensure we count the filename as parsed case statusEmpty: // sent to ensure we count the filename as parsed
} }
return err return err
} }
func (o *text) Flush() error { func (o *texto) Flush() error {
var err error var err error
if o.withSummary { if o.withSummary {
nFiles := len(o.files) nFiles := len(o.files)

View file

@ -72,7 +72,7 @@ Summary: 1 resource found in 1 file - Valid: 1, Invalid: 0, Errors: 0 Skipped: 0
}, },
} { } {
w := new(bytes.Buffer) w := new(bytes.Buffer)
o := Text(w, testCase.withSummary, false, testCase.verbose) o := textOutput(w, testCase.withSummary, false, testCase.verbose)
for _, res := range testCase.res { for _, res := range testCase.res {
o.Write(res.fileName, res.kind, res.name, res.version, res.err, res.skipped) o.Write(res.fileName, res.kind, res.name, res.version, res.err, res.skipped)