Add configurable color output mode (#907)

This commit is contained in:
xiantang
2026-05-19 23:11:11 +08:00
committed by GitHub
parent a45bbfc5e8
commit cc252d618d
3 changed files with 78 additions and 1 deletions
+1 -1
View File
@@ -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
View File
@@ -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
+62
View File
@@ -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")
}
}