From c965b173c1edf7c72420d8583091f345e9096793 Mon Sep 17 00:00:00 2001 From: Gustav Westling Date: Tue, 3 Jan 2023 10:34:22 +0100 Subject: [PATCH] renderer: override color support logic to add colors on GitHub Actions --- cmd/kube-score/main.go | 45 ++++++++++++++++++++++++++++++++++++++++- go.mod | 2 +- go.sum | 3 +++ renderer/human/human.go | 5 ++++- 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/cmd/kube-score/main.go b/cmd/kube-score/main.go index d4eca8a3..80901ecc 100644 --- a/cmd/kube-score/main.go +++ b/cmd/kube-score/main.go @@ -11,6 +11,7 @@ import ( "os" "path/filepath" + "github.com/mattn/go-isatty" flag "github.com/spf13/pflag" "golang.org/x/term" @@ -106,6 +107,7 @@ func scoreFiles(binName string, args []string) error { printHelp := fs.Bool("help", false, "Print help") outputFormat := fs.StringP("output-format", "o", "human", "Set to 'human', 'json', 'ci' or 'sarif'. If set to ci, kube-score will output the program in a format that is easier to parse by other programs. Sarif output allows for easier integration with CI platforms.") outputVersion := fs.String("output-version", "", "Changes the version of the --output-format. The 'json' format has version 'v2' (default) and 'v1' (deprecated, will be removed in v1.7.0). The 'human' and 'ci' formats has only version 'v1' (default). If not explicitly set, the default version for that particular output format will be used.") + color := fs.String("color", "auto", "If the output should be colored. Set to 'always', 'never' or 'auto'. If set to 'auto', kube-score will try to detect if the current terminal / platform supports colors. If set to 'never', kube-score will not output any colors. If set to 'always', kube-score will output colors even if the current terminal / platform does not support colors.") optionalTests := fs.StringSlice("enable-optional-test", []string{}, "Enable an optional test, can be set multiple times") ignoreTests := fs.StringSlice("ignore-test", []string{}, "Disable a test, can be set multiple times") disableIgnoreChecksAnnotation := fs.Bool("disable-ignore-checks-annotations", false, "Set to true to disable the effect of the 'kube-score/ignore' annotations") @@ -128,6 +130,16 @@ func scoreFiles(binName string, args []string) error { return fmt.Errorf("Error: --output-format must be set to: 'human', 'json', 'sarif' or 'ci'") } + acceptedColors := map[string]bool{ + "auto": true, + "always": true, + "never": true, + } + if !acceptedColors[*color] { + fs.Usage() + return fmt.Errorf("Error: --color must be set to: 'auto', 'always' or 'never'") + } + filesToRead := fs.Args() if len(filesToRead) == 0 { return fmt.Errorf(`Error: No files given as arguments. @@ -220,7 +232,7 @@ Use "-" as filename to read from STDIN.`, execName(binName)) if err != nil { termWidth = 80 } - r, err = human.Human(scoreCard, *verboseOutput, termWidth) + r, err = human.Human(scoreCard, *verboseOutput, termWidth, useColor(*color)) if err != nil { return err } @@ -299,3 +311,34 @@ type namedReader struct { func (n namedReader) Name() string { return n.name } + +func useColor(colorArg string) bool { + // Respect user preference + switch colorArg { + case "always": + return true + case "never": + return false + } + + // If running on Github Actions, use colors + if _, ok := os.LookupEnv("GITHUB_ACTIONS"); ok { + return true + } + + // If NO_COLOR is set, don't use color + if _, ok := os.LookupEnv("NO_COLOR"); ok { + return false + } + + // Dont use color if not a terminal + if os.Getenv("TERM") == "dumb" { + return false + } + if !isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd()) { + return false + } + + // Use colors + return true +} diff --git a/go.mod b/go.mod index 7a97ec3d..916cbf5e 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/google/gofuzz v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mattn/go-colorable v0.1.9 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/go.sum b/go.sum index 45cbbc1b..250b19ff 100644 --- a/go.sum +++ b/go.sum @@ -25,6 +25,8 @@ github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -65,6 +67,7 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= diff --git a/renderer/human/human.go b/renderer/human/human.go index af378683..c1ca0d72 100644 --- a/renderer/human/human.go +++ b/renderer/human/human.go @@ -15,7 +15,7 @@ import ( "github.com/zegl/kube-score/scorecard" ) -func Human(scoreCard *scorecard.Scorecard, verboseOutput int, termWidth int) (io.Reader, error) { +func Human(scoreCard *scorecard.Scorecard, verboseOutput int, termWidth int, useColors bool) (io.Reader, error) { // Print the items sorted by scorecard key var keys []string for k := range *scoreCard { @@ -23,6 +23,9 @@ func Human(scoreCard *scorecard.Scorecard, verboseOutput int, termWidth int) (io } sort.Strings(keys) + // Override usage of colors to our own preference + color.NoColor = !useColors + w := bytes.NewBufferString("") for _, key := range keys {