Skip to content

Commit

Permalink
Change output to be more line orientated
Browse files Browse the repository at this point in the history
This brings the output inline with the discussions around Conftest. This
makes each line a meaninful error or message, and cuts down on some of
the repeated output. Individual lines can now be parsed as errors or
warnings or passes without knowing the colour.
  • Loading branch information
garethr committed Sep 1, 2019
1 parent 092e382 commit 8c40ed5
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 52 deletions.
30 changes: 15 additions & 15 deletions acceptance.bats
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,49 @@
@test "Pass when parsing a valid Kubernetes config YAML file" {
run bin/kubeval fixtures/valid.yaml
[ "$status" -eq 0 ]
[ "$output" = "The file fixtures/valid.yaml contains a valid ReplicationController" ]
[ "$output" = "PASS - fixtures/valid.yaml contains a valid ReplicationController" ]
}

@test "Pass when parsing a valid Kubernetes config YAML file on stdin" {
run bash -c "cat fixtures/valid.yaml | bin/kubeval"
[ "$status" -eq 0 ]
[ "$output" = "The file stdin contains a valid ReplicationController" ]
[ "$output" = "PASS - stdin contains a valid ReplicationController" ]
}

@test "Pass when parsing a valid Kubernetes config YAML file explicitly on stdin" {
run bash -c "cat fixtures/valid.yaml | bin/kubeval -"
[ "$status" -eq 0 ]
[ "$output" = "The file stdin contains a valid ReplicationController" ]
[ "$output" = "PASS - stdin contains a valid ReplicationController" ]
}

@test "Pass when parsing a valid Kubernetes config JSON file" {
run bin/kubeval fixtures/valid.json
[ "$status" -eq 0 ]
[ "$output" = "The file fixtures/valid.json contains a valid Deployment" ]
[ "$output" = "PASS - fixtures/valid.json contains a valid Deployment" ]
}

@test "Pass when parsing a Kubernetes file with string and integer quantities" {
run bin/kubeval fixtures/quantity.yaml
[ "$status" -eq 0 ]
[ "$output" = "The file fixtures/quantity.yaml contains a valid LimitRange" ]
[ "$output" = "PASS - fixtures/quantity.yaml contains a valid LimitRange" ]
}

@test "Pass when parsing a valid Kubernetes config file with int_to_string vars" {
run bin/kubeval fixtures/int_or_string.yaml
[ "$status" -eq 0 ]
[ "$output" = "The file fixtures/int_or_string.yaml contains a valid Service" ]
[ "$output" = "PASS - fixtures/int_or_string.yaml contains a valid Service" ]
}

@test "Pass when parsing a valid Kubernetes config file with null arrays" {
run bin/kubeval fixtures/null_array.yaml
[ "$status" -eq 0 ]
[ "$output" = "The file fixtures/null_array.yaml contains a valid Deployment" ]
[ "$output" = "PASS - fixtures/null_array.yaml contains a valid Deployment" ]
}

@test "Pass when parsing a valid Kubernetes config file with null strings" {
run bin/kubeval fixtures/null_string.yaml
[ "$status" -eq 0 ]
[ "$output" = "The file fixtures/null_string.yaml contains a valid Service" ]
[ "$output" = "PASS - fixtures/null_string.yaml contains a valid Service" ]
}

@test "Pass when parsing a multi-document config file" {
Expand All @@ -71,19 +71,19 @@
@test "Return relevant error for non-existent file" {
run bin/kubeval fixtures/not-here
[ "$status" -eq 1 ]
[ $(expr "$output" : "^Could not open file") -ne 0 ]
[ $(expr "$output" : "^ERR - Could not open file") -ne 0 ]
}

@test "Pass when parsing a blank config file" {
run bin/kubeval fixtures/blank.yaml
[ "$status" -eq 0 ]
[ "$output" = "The file fixtures/blank.yaml contains an empty YAML document" ]
[ "$output" = "PASS - fixtures/blank.yaml contains an empty YAML document" ]
}

@test "Pass when parsing a blank config file with a comment" {
run bin/kubeval fixtures/comment.yaml
[ "$status" -eq 0 ]
[ "$output" = "The file fixtures/comment.yaml contains an empty YAML document" ]
[ "$output" = "PASS - fixtures/comment.yaml contains an empty YAML document" ]
}

@test "Return relevant error for YAML missing kind key" {
Expand Down Expand Up @@ -159,13 +159,13 @@
@test "Only prints a single warning when --ignore-missing-schemas is supplied" {
run bin/kubeval --ignore-missing-schemas fixtures/valid.yaml fixtures/valid.yaml
[ "$status" -eq 0 ]
[[ "${lines[0]}" == *"Warning: Set to ignore missing schemas"* ]]
[[ "${lines[1]}" == *"The file fixtures/valid.yaml contains a valid ReplicationController"* ]]
[[ "${lines[2]}" == *"The file fixtures/valid.yaml contains a valid ReplicationController"* ]]
[[ "${lines[0]}" == *"WARN - Set to ignore missing schemas"* ]]
[[ "${lines[1]}" == *"PASS - fixtures/valid.yaml contains a valid ReplicationController"* ]]
[[ "${lines[2]}" == *"PASS - fixtures/valid.yaml contains a valid ReplicationController"* ]]
}

@test "Does not print warnings if --quiet is supplied" {
run bin/kubeval --ignore-missing-schemas --quiet fixtures/valid.yaml
[ "$status" -eq 0 ]
[ "$output" = "The file fixtures/valid.yaml contains a valid ReplicationController" ]
[ "$output" = "PASS - fixtures/valid.yaml contains a valid ReplicationController" ]
}
30 changes: 15 additions & 15 deletions kubeval/kubeval.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,13 @@ func validateResource(data []byte, schemaCache map[string]*gojsonschema.Schema,

kind, err := getString(body, "kind")
if err != nil {
return result, fmt.Errorf("Error with %s: %s", result.FileName, err.Error())
return result, fmt.Errorf("%s: %s", result.FileName, err.Error())
}
result.Kind = kind

apiVersion, err := getString(body, "apiVersion")
if err != nil {
return result, fmt.Errorf("Error with %s: %s", result.FileName, err.Error())
return result, fmt.Errorf("%s: %s", result.FileName, err.Error())
}
result.APIVersion = apiVersion

Expand All @@ -126,7 +126,7 @@ func validateResource(data []byte, schemaCache map[string]*gojsonschema.Schema,

schemaErrors, err := validateAgainstSchema(body, &result, schemaCache, config)
if err != nil {
return result, fmt.Errorf("Error with %s: %s", result.FileName, err.Error())
return result, fmt.Errorf("%s: %s", result.FileName, err.Error())
}
result.Errors = schemaErrors
return result, nil
Expand Down Expand Up @@ -192,11 +192,11 @@ func downloadSchema(resource *ValidationResult, schemaCache map[string]*gojsonsc
errors = multierror.Append(errors, wrappedErr)
}

if errors != nil {
errors.ErrorFormat = singleLineErrorFormat
}
if errors != nil {
errors.ErrorFormat = singleLineErrorFormat
}

// TODO: this currently triggers a segfault in offline cases
// TODO: this currently triggers a segfault in offline cases
// We couldn't find a schema for this resource. Cache it's lack of existence, then stop
//schemaCache[resource.VersionKind()] = nil
return nil, errors.ErrorOrNil()
Expand Down Expand Up @@ -277,16 +277,16 @@ func ValidateWithCache(input []byte, schemaCache map[string]*gojsonschema.Schema
}
}

if errors != nil {
errors.ErrorFormat = singleLineErrorFormat
}
if errors != nil {
errors.ErrorFormat = singleLineErrorFormat
}
return results, errors.ErrorOrNil()
}

func singleLineErrorFormat(es []error) string {
messages := make([]string, len(es))
for i, e := range es {
messages[i] = e.Error()
}
return strings.Join(messages, "\n")
messages := make([]string, len(es))
for i, e := range es {
messages[i] = e.Error()
}
return strings.Join(messages, "\n")
}
9 changes: 4 additions & 5 deletions kubeval/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,15 @@ func newSTDOutputManager() *STDOutputManager {

func (s *STDOutputManager) Put(result ValidationResult) error {
if len(result.Errors) > 0 {
kLog.Warn("The file", result.FileName, "contains an invalid", result.Kind)
for _, desc := range result.Errors {
kLog.Info("--->", desc)
kLog.Warn(result.FileName, "contains an invalid", result.Kind, "-", desc.String())
}
} else if result.Kind == "" {
kLog.Success("The file", result.FileName, "contains an empty YAML document")
kLog.Success(result.FileName, "contains an empty YAML document")
} else if !result.ValidatedAgainstSchema {
kLog.Warn("The file", result.FileName, "containing a", result.Kind, "was not validated against a schema")
kLog.Warn(result.FileName, "containing a", result.Kind, "was not validated against a schema")
} else {
kLog.Success("The file", result.FileName, "contains a valid", result.Kind)
kLog.Success(result.FileName, "contains a valid", result.Kind)
}

return nil
Expand Down
30 changes: 17 additions & 13 deletions log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,29 @@ package log

import (
"fmt"
"strings"

"github.com/fatih/color"
multierror "github.com/hashicorp/go-multierror"
)

func Info(message ...interface{}) {
fmt.Println(message...)
func Success(message ...string) {
green := color.New(color.FgGreen).SprintFunc()
fmt.Printf("%s - %v\n", green("PASS"), strings.Join(message, " "))
}

func Success(message ...interface{}) {
green := color.New(color.FgGreen)
green.Println(message...)
func Warn(message ...string) {
yellow := color.New(color.FgYellow).SprintFunc()
fmt.Printf("%s - %v\n", yellow("WARN"), strings.Join(message, " "))
}

func Warn(message ...interface{}) {
yellow := color.New(color.FgYellow)
yellow.Println(message...)
}

func Error(message ...interface{}) {
red := color.New(color.FgRed)
red.Println(message...)
func Error(message error) {
if merr, ok := message.(*multierror.Error); ok {
for _, serr := range merr.Errors {
Error(serr)
}
} else {
red := color.New(color.FgRed).SprintFunc()
fmt.Printf("%s - %v\n", red("ERR "), message)
}
}
9 changes: 5 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"bufio"
"bytes"
"errors"
"fmt"
"io/ioutil"
"os"
Expand Down Expand Up @@ -40,7 +41,7 @@ var RootCmd = &cobra.Command{
Version: fmt.Sprintf("Version: %s\nCommit: %s\nDate: %s\n", version, commit, date),
Run: func(cmd *cobra.Command, args []string) {
if config.IgnoreMissingSchemas && !config.Quiet {
log.Warn("Warning: Set to ignore missing schemas")
log.Warn("Set to ignore missing schemas")
}
success := true
windowsStdinIssue := false
Expand Down Expand Up @@ -88,13 +89,13 @@ var RootCmd = &cobra.Command{
}
} else {
if len(args) < 1 && len(directories) < 1 {
log.Error("You must pass at least one file as an argument, or at least one directory to the directories flag")
log.Error(errors.New("You must pass at least one file as an argument, or at least one directory to the directories flag"))
os.Exit(1)
}
schemaCache := kubeval.NewSchemaCache()
files, err := aggregateFiles(args)
if err != nil {
log.Error(err.Error())
log.Error(err)
success = false
}

Expand All @@ -103,7 +104,7 @@ var RootCmd = &cobra.Command{
filePath, _ := filepath.Abs(fileName)
fileContents, err := ioutil.ReadFile(filePath)
if err != nil {
log.Error("Could not open file", fileName)
log.Error(fmt.Errorf("Could not open file %v", fileName))
earlyExit()
success = false
continue
Expand Down

0 comments on commit 8c40ed5

Please sign in to comment.