From d4243d69d5b36a0751a08143c9b28e8392ed59fb Mon Sep 17 00:00:00 2001 From: Kevin McConnell Date: Thu, 2 Apr 2026 17:23:14 +0100 Subject: [PATCH] Don't show progress when CLI has no TTY --- internal/command/cli_progress.go | 40 ++++++++++++++++++++++++-------- internal/command/deploy.go | 5 +--- internal/command/update.go | 4 +--- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/internal/command/cli_progress.go b/internal/command/cli_progress.go index 38ad0b2..5ea8373 100644 --- a/internal/command/cli_progress.go +++ b/internal/command/cli_progress.go @@ -2,6 +2,7 @@ package command import ( "fmt" + "os" tea "charm.land/bubbletea/v2" "charm.land/lipgloss/v2" @@ -21,8 +22,10 @@ type cliProgress struct { task func(docker.DeployProgressCallback) error } -type cliProgressDoneMsg struct{ err error } -type cliProgressUpdateMsg struct{ p docker.DeployProgress } +type ( + cliProgressDoneMsg struct{ err error } + cliProgressUpdateMsg struct{ p docker.DeployProgress } +) func newCLIProgress(label string, task func(docker.DeployProgressCallback) error) *cliProgress { return &cliProgress{ @@ -34,19 +37,26 @@ func newCLIProgress(label string, task func(docker.DeployProgressCallback) error } } -func (m *cliProgress) Run() error { - _, err := tea.NewProgram(m).Run() - if err != nil { - return err +func runWithProgress(label string, task func(docker.DeployProgressCallback) error) error { + var err error + + if isTerminal() { + p := newCLIProgress(label, task) + if _, runErr := tea.NewProgram(p).Run(); runErr != nil { + return runErr + } + err = p.err + } else { + err = task(func(docker.DeployProgress) {}) } - if m.err != nil { - fmt.Printf("%s: %s\n", m.label, lipgloss.NewStyle().Foreground(lipgloss.Red).Render("failed")) + if err != nil { + fmt.Printf("%s: %s\n", label, lipgloss.NewStyle().Foreground(lipgloss.Red).Render("failed")) } else { - fmt.Printf("%s: %s\n", m.label, lipgloss.NewStyle().Foreground(lipgloss.Green).Render("done")) + fmt.Printf("%s: %s\n", label, lipgloss.NewStyle().Foreground(lipgloss.Green).Render("done")) } - return m.err + return err } func (m *cliProgress) Init() tea.Cmd { @@ -117,3 +127,13 @@ func (m *cliProgress) waitForProgress() tea.Cmd { return cliProgressUpdateMsg{p: p} } } + +// Helpers + +func isTerminal() bool { + fi, err := os.Stdout.Stat() + if err != nil { + return false + } + return fi.Mode()&os.ModeCharDevice != 0 +} diff --git a/internal/command/deploy.go b/internal/command/deploy.go index 03c077f..ec90559 100644 --- a/internal/command/deploy.go +++ b/internal/command/deploy.go @@ -48,7 +48,6 @@ func (d *deployCommand) run(ctx context.Context, ns *docker.Namespace, cmd *cobr } settings, err := d.flags.buildSettings(imageRef, host) - if err != nil { return err } @@ -62,7 +61,7 @@ func (d *deployCommand) run(ctx context.Context, ns *docker.Namespace, cmd *cobr app := docker.NewApplication(ns, settings) - p := newCLIProgress("Deploying "+host, func(progress docker.DeployProgressCallback) error { + return runWithProgress("Deploying "+host, func(progress docker.DeployProgressCallback) error { if err := app.Deploy(ctx, progress); err != nil { if cleanupErr := app.Destroy(context.Background(), true); cleanupErr != nil { slog.Error("Failed to clean up after deploy failure", "app", name, "error", cleanupErr) @@ -76,6 +75,4 @@ func (d *deployCommand) run(ctx context.Context, ns *docker.Namespace, cmd *cobr return nil }) - - return p.Run() } diff --git a/internal/command/update.go b/internal/command/update.go index d42e3ae..e1e2ddb 100644 --- a/internal/command/update.go +++ b/internal/command/update.go @@ -63,13 +63,11 @@ func (u *updateCommand) run(ctx context.Context, ns *docker.Namespace, cmd *cobr oldSettings := app.Settings app.Settings = settings - p := newCLIProgress("Updating "+currentHost, func(progress docker.DeployProgressCallback) error { + return runWithProgress("Updating "+currentHost, func(progress docker.DeployProgressCallback) error { if err := app.Deploy(ctx, progress); err != nil { app.Settings = oldSettings return fmt.Errorf("%w: %w", docker.ErrDeployFailed, err) } return nil }) - - return p.Run() }