v3.42.32: Add fatih/color for cross-platform terminal colors
All checks were successful
CI/CD / Test (push) Successful in 1m17s
CI/CD / Lint (push) Successful in 1m26s
CI/CD / Build & Release (push) Successful in 3m13s

- Windows-compatible colors via native console API
- Color helper functions: Success(), Error(), Warning(), Info()
- Text styling: Header(), Dim(), Bold(), Green(), Red(), Yellow(), Cyan()
- Logger CleanFormatter uses fatih/color instead of raw ANSI
- All progress indicators use colored [OK]/[FAIL] status
- Automatic color detection for non-TTY environments
This commit is contained in:
2026-01-14 16:13:00 +01:00
parent dc6dfd8b2c
commit 6a24ee39be
8 changed files with 212 additions and 29 deletions

118
internal/logger/colors.go Normal file
View File

@@ -0,0 +1,118 @@
package logger
import (
"fmt"
"os"
"github.com/fatih/color"
)
// CLI output helpers using fatih/color for cross-platform support
// Success prints a success message with green checkmark
func Success(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
SuccessColor.Fprint(os.Stdout, "✓ ")
fmt.Println(msg)
}
// Error prints an error message with red X
func Error(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
ErrorColor.Fprint(os.Stderr, "✗ ")
fmt.Fprintln(os.Stderr, msg)
}
// Warning prints a warning message with yellow exclamation
func Warning(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
WarnColor.Fprint(os.Stdout, "⚠ ")
fmt.Println(msg)
}
// Info prints an info message with blue arrow
func Info(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
InfoColor.Fprint(os.Stdout, "→ ")
fmt.Println(msg)
}
// Header prints a bold header
func Header(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
HighlightColor.Println(msg)
}
// Dim prints dimmed/secondary text
func Dim(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
DimColor.Println(msg)
}
// Bold returns bold text
func Bold(text string) string {
return color.New(color.Bold).Sprint(text)
}
// Green returns green text
func Green(text string) string {
return SuccessColor.Sprint(text)
}
// Red returns red text
func Red(text string) string {
return ErrorColor.Sprint(text)
}
// Yellow returns yellow text
func Yellow(text string) string {
return WarnColor.Sprint(text)
}
// Cyan returns cyan text
func Cyan(text string) string {
return InfoColor.Sprint(text)
}
// StatusLine prints a key-value status line
func StatusLine(key, value string) {
DimColor.Printf(" %s: ", key)
fmt.Println(value)
}
// ProgressStatus prints operation status with timing
func ProgressStatus(operation string, status string, isSuccess bool) {
if isSuccess {
SuccessColor.Print("[OK] ")
} else {
ErrorColor.Print("[FAIL] ")
}
fmt.Printf("%s: %s\n", operation, status)
}
// Table prints a simple formatted table row
func TableRow(cols ...string) {
for i, col := range cols {
if i == 0 {
InfoColor.Printf("%-20s", col)
} else {
fmt.Printf("%-15s", col)
}
}
fmt.Println()
}
// DisableColors disables all color output (for non-TTY or --no-color flag)
func DisableColors() {
color.NoColor = true
}
// EnableColors enables color output
func EnableColors() {
color.NoColor = false
}
// IsColorEnabled returns whether colors are enabled
func IsColorEnabled() bool {
return !color.NoColor
}

View File

@@ -7,9 +7,29 @@ import (
"strings"
"time"
"github.com/fatih/color"
"github.com/sirupsen/logrus"
)
// Color printers for consistent output across the application
var (
// Status colors
SuccessColor = color.New(color.FgGreen, color.Bold)
ErrorColor = color.New(color.FgRed, color.Bold)
WarnColor = color.New(color.FgYellow, color.Bold)
InfoColor = color.New(color.FgCyan)
DebugColor = color.New(color.FgWhite)
// Highlight colors
HighlightColor = color.New(color.FgMagenta, color.Bold)
DimColor = color.New(color.FgHiBlack)
// Data colors
NumberColor = color.New(color.FgYellow)
PathColor = color.New(color.FgBlue, color.Underline)
TimeColor = color.New(color.FgCyan)
)
// Logger defines the interface for logging
type Logger interface {
Debug(msg string, args ...any)
@@ -226,34 +246,32 @@ type CleanFormatter struct{}
func (f *CleanFormatter) Format(entry *logrus.Entry) ([]byte, error) {
timestamp := entry.Time.Format("2006-01-02T15:04:05")
// Color codes for different log levels
var levelColor, levelText string
// Get level color and text using fatih/color
var levelPrinter *color.Color
var levelText string
switch entry.Level {
case logrus.DebugLevel:
levelColor = "\033[36m" // Cyan
levelPrinter = DebugColor
levelText = "DEBUG"
case logrus.InfoLevel:
levelColor = "\033[32m" // Green
levelPrinter = SuccessColor
levelText = "INFO "
case logrus.WarnLevel:
levelColor = "\033[33m" // Yellow
levelPrinter = WarnColor
levelText = "WARN "
case logrus.ErrorLevel:
levelColor = "\033[31m" // Red
levelPrinter = ErrorColor
levelText = "ERROR"
default:
levelColor = "\033[0m" // Reset
levelPrinter = InfoColor
levelText = "INFO "
}
resetColor := "\033[0m"
// Build the message with perfectly aligned columns
var output strings.Builder
// Column 1: Level (with color, fixed width 5 chars)
output.WriteString(levelColor)
output.WriteString(levelText)
output.WriteString(resetColor)
output.WriteString(levelPrinter.Sprint(levelText))
output.WriteString(" ")
// Column 2: Timestamp (fixed format)