From 09a351677e032c821744bbdd385007c372977eb4 Mon Sep 17 00:00:00 2001 From: realMelTuc Date: Thu, 19 Feb 2026 12:06:11 -0500 Subject: [PATCH] feat: add spinner during analysis in verbose mode When running with --verbose flag, displays a spinner while analysis is running to indicate progress. Spinner shows rotating characters to let users know the analysis is working. Usage: plumber analyze --verbose Closes #64 --- cmd/analyze.go | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/cmd/analyze.go b/cmd/analyze.go index 9e21322..be019c4 100644 --- a/cmd/analyze.go +++ b/cmd/analyze.go @@ -6,6 +6,7 @@ import ( "os" "sort" "strings" + "time" "github.com/getplumber/plumber/configuration" "github.com/getplumber/plumber/control" @@ -218,10 +219,19 @@ func runAnalyze(cmd *cobra.Command, args []string) error { conf.LogLevel = logrus.DebugLevel } - // Run analysis + // Run analysis with spinner fmt.Fprintf(os.Stderr, "Analyzing project: %s on %s\n", projectPath, cleanGitlabURL) - result, err := control.RunAnalysis(conf) + var result *control.AnalysisResult + + // Start spinner in verbose mode (when user wants to see progress) + if verbose { + stopSpinner := startSpinner("Analyzing") + result, err = control.RunAnalysis(conf) + stopSpinner() + } else { + result, err = control.RunAnalysis(conf) + } if err != nil { return fmt.Errorf("analysis failed: %w", err) } @@ -1086,3 +1096,34 @@ func printComplianceTable(controls []controlSummary, overallCompliance, threshol strings.Repeat("═", statusWidth), colorReset) } + +// startSpinner displays a spinner while the analysis is running +// Returns a stop function that should be called when done +func startSpinner(message string) func() { + stop := make(chan bool) + done := make(chan bool) + + go func() { + spinner := []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"} + i := 0 + + for { + select { + case <-stop: + done <- true + return + default: + fmt.Fprintf(os.Stderr, "\r%s %s... ", spinner[i%len(spinner)], message) + i++ + time.Sleep(100 * time.Millisecond) + } + } + }() + + return func() { + stop <- true + <-done + // Clear the spinner line + fmt.Fprintf(os.Stderr, "\r") + } +}