Add configurable color output mode (#907)
This commit is contained in:
@@ -136,7 +136,7 @@ func main() {
|
||||
case "auto", "":
|
||||
// do nothing
|
||||
default:
|
||||
log.Fatal("unsupported color mode: use always, never, auto")
|
||||
log.Fatalf("unsupported color mode: %s. Expected always, auto, or never", colorMode)
|
||||
}
|
||||
|
||||
if showVersion {
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"time"
|
||||
|
||||
"dario.cat/mergo"
|
||||
"github.com/fatih/color"
|
||||
"github.com/pelletier/go-toml"
|
||||
)
|
||||
|
||||
@@ -163,6 +164,7 @@ type cfgColor struct {
|
||||
Watcher string `toml:"watcher" usage:"Customize watcher part's color"`
|
||||
Build string `toml:"build" usage:"Customize build part's color"`
|
||||
Runner string `toml:"runner" usage:"Customize runner part's color"`
|
||||
Mode string `toml:"mode" usage:"Colorized output mode, one of always, auto, or never. Defaults to auto"`
|
||||
App string `toml:"app"`
|
||||
}
|
||||
|
||||
@@ -625,6 +627,19 @@ func (c *Config) preprocess(args map[string]TomlInfo) error {
|
||||
}
|
||||
|
||||
c.Build.ExcludeDir = ed
|
||||
|
||||
// Set colorful output, see https://github.com/fatih/color#disableenable-color
|
||||
switch c.Color.Mode {
|
||||
case "always":
|
||||
color.NoColor = false
|
||||
case "never":
|
||||
color.NoColor = true
|
||||
case "auto", "":
|
||||
break
|
||||
default:
|
||||
return fmt.Errorf("unsupported color mode: %s. Expected always, auto, or never", c.Color.Mode)
|
||||
}
|
||||
|
||||
if len(c.Build.FullBin) > 0 {
|
||||
c.Build.Bin = c.Build.FullBin
|
||||
return err
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -1119,3 +1121,63 @@ cmd = "go build -o ./tmp/main ."
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestColorMode(t *testing.T) {
|
||||
// Save and restore the global NoColor state so tests don't bleed into each other.
|
||||
original := color.NoColor
|
||||
t.Cleanup(func() { color.NoColor = original })
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
mode string
|
||||
wantNoColor bool
|
||||
wantErr bool
|
||||
}{
|
||||
{name: "always enables color", mode: "always", wantNoColor: false},
|
||||
{name: "never disables color", mode: "never", wantNoColor: true},
|
||||
{name: "auto leaves default", mode: "auto", wantNoColor: original},
|
||||
{name: "empty leaves default", mode: "", wantNoColor: original},
|
||||
{name: "invalid returns error", mode: "rainbow", wantErr: true},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
color.NoColor = original
|
||||
cfg := defaultConfig()
|
||||
cfg.Color.Mode = tc.mode
|
||||
err := cfg.preprocess(nil)
|
||||
if tc.wantErr {
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "unsupported color mode") {
|
||||
t.Fatalf("unexpected error message: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if color.NoColor != tc.wantNoColor {
|
||||
t.Fatalf("color.NoColor = %v, want %v", color.NoColor, tc.wantNoColor)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestColorModeWithFullBin(t *testing.T) {
|
||||
// Regression: color mode must be applied even when build.full_bin is set,
|
||||
// because preprocess returns early after FullBin is processed.
|
||||
original := color.NoColor
|
||||
t.Cleanup(func() { color.NoColor = original })
|
||||
|
||||
cfg := defaultConfig()
|
||||
cfg.Build.FullBin = "./tmp/main"
|
||||
cfg.Color.Mode = "never"
|
||||
if err := cfg.preprocess(nil); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !color.NoColor {
|
||||
t.Fatal("color.NoColor should be true when mode=never and full_bin is set")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user