From 5d63da03558e83e0c55f7de36ac30de64f7ce3ee Mon Sep 17 00:00:00 2001 From: Fnuworsu Date: Thu, 26 Mar 2026 02:35:04 -0500 Subject: [PATCH 1/2] fix: suppress wait messages and progress bars in quiet mode (#37) Signed-off-by: Fnuworsu --- internal/app/azldev/app.go | 8 ++++---- internal/app/azldev/core/testutils/testenv.go | 2 +- internal/app/azldev/event.go | 9 +++++++++ internal/app/azldev/eventlistener.go | 7 +++++-- testproj/.gitignore | 5 +++++ testproj/azldev.toml | 12 ++++++++++++ 6 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 testproj/.gitignore create mode 100644 testproj/azldev.toml diff --git a/internal/app/azldev/app.go b/internal/app/azldev/app.go index dce4d79..df9084e 100644 --- a/internal/app/azldev/app.go +++ b/internal/app/azldev/app.go @@ -248,7 +248,7 @@ func (a *App) Execute(args []string) int { // stdioLogger := a.initStdioLogging() - if err := setEventListener(stdioLogger, envOptions); err != nil { + if err := setEventListener(stdioLogger, a.quiet, envOptions); err != nil { slog.Error("Error setting event listener.", "err", err) return 1 @@ -357,7 +357,7 @@ func (a *App) reInitLoggingWithLogFile(envOptions *EnvOptions) error { return fmt.Errorf("error re-initializing file logging:\n%w", err) } - err = setEventListener(logger, envOptions) + err = setEventListener(logger, a.quiet, envOptions) if err != nil { return fmt.Errorf("error re-setting event listener:\n%w", err) } @@ -421,8 +421,8 @@ func (a *App) handlePostInitCallbacks(env *Env) error { return nil } -func setEventListener(stdioLogger *slog.Logger, envOptions *EnvOptions) error { - eventListener, err := NewEventListener(stdioLogger) +func setEventListener(stdioLogger *slog.Logger, quiet bool, envOptions *EnvOptions) error { + eventListener, err := NewEventListener(stdioLogger, quiet) if err != nil { return fmt.Errorf("error initializing event listener:\n%w", err) } diff --git a/internal/app/azldev/core/testutils/testenv.go b/internal/app/azldev/core/testutils/testenv.go index 35a996e..6cee8c6 100644 --- a/internal/app/azldev/core/testutils/testenv.go +++ b/internal/app/azldev/core/testutils/testenv.go @@ -97,7 +97,7 @@ func setUpEventListener(t *testing.T, testEnv *TestEnv) { testLogHandler := slogassert.New(t, slog.LevelDebug, nil) testEventLogger := slog.New(testLogHandler) - testEventListener, err := azldev.NewEventListener(testEventLogger) + testEventListener, err := azldev.NewEventListener(testEventLogger, false) require.NoError(t, err) testEnv.EventListener = testEventListener diff --git a/internal/app/azldev/event.go b/internal/app/azldev/event.go index 468394a..027e98d 100644 --- a/internal/app/azldev/event.go +++ b/internal/app/azldev/event.go @@ -18,6 +18,7 @@ type event struct { parentEventListener *appEventListener name string spinner *spinner.Spinner + quiet bool lastReportedCompletionRatio float64 @@ -49,6 +50,10 @@ func (e *event) End() { } func (e *event) SetLongRunning(longRunningText string) { + if e.quiet { + return + } + const percent = 100 // Start an indeterminate spinner to indicate to the user that *something* is happening. @@ -60,6 +65,10 @@ func (e *event) SetLongRunning(longRunningText string) { } func (e *event) SetProgress(unitsComplete int64, totalUnits int64) { + if e.quiet { + return + } + // For now, only update progress visually when the completion ratio has increased by at least 1% // since progress was last rendered. const minRatioIncreaseForUpdate = 0.01 diff --git a/internal/app/azldev/eventlistener.go b/internal/app/azldev/eventlistener.go index 831b822..a809599 100644 --- a/internal/app/azldev/eventlistener.go +++ b/internal/app/azldev/eventlistener.go @@ -16,13 +16,14 @@ import ( type appEventListener struct { eventLevel int eventLogger *slog.Logger + quiet bool } // Ensure [appEventListener] implements [opctx.EventListener]. var _ opctx.EventListener = &appEventListener{} // NewEventListener creates a new event listener for the environment. -func NewEventListener(eventLogger *slog.Logger) (*appEventListener, error) { +func NewEventListener(eventLogger *slog.Logger, quiet bool) (*appEventListener, error) { if eventLogger == nil { return nil, errors.New("event logger cannot be nil") } @@ -30,6 +31,7 @@ func NewEventListener(eventLogger *slog.Logger) (*appEventListener, error) { return &appEventListener{ eventLevel: 0, eventLogger: eventLogger, + quiet: quiet, }, nil } @@ -37,7 +39,7 @@ func NewEventListener(eventLogger *slog.Logger) (*appEventListener, error) { // //nolint:ireturn,nolintlint // We need to return an interface because of the interface definition. func (el *appEventListener) StartEvent(name string, args ...any) opctx.Event { - if name != "" { + if !el.quiet && name != "" { const spacesPerLevel = 2 prefix := strings.Repeat(" ", el.eventLevel*spacesPerLevel) @@ -51,6 +53,7 @@ func (el *appEventListener) StartEvent(name string, args ...any) opctx.Event { return &event{ parentEventListener: el, name: name, + quiet: el.quiet, } } diff --git a/testproj/.gitignore b/testproj/.gitignore new file mode 100644 index 0000000..dd45194 --- /dev/null +++ b/testproj/.gitignore @@ -0,0 +1,5 @@ +# Ignore build log and work dirs +build/ + +# Ignore build output +out/ diff --git a/testproj/azldev.toml b/testproj/azldev.toml new file mode 100644 index 0000000..f14ec98 --- /dev/null +++ b/testproj/azldev.toml @@ -0,0 +1,12 @@ +'$schema' = 'https://raw.githubusercontent.com/microsoft/azure-linux-dev-tools/refs/heads/main/schemas/azldev.schema.json' + +[project] +description = 'testproj' +log-dir = 'build/logs' +work-dir = 'build/work' +output-dir = 'out' + +[component-groups] +[component-groups.default] +specs = ['**/*.spec'] +excluded-paths = ['build/**', 'out/**'] From 8059d61337a5acceafe84761b6e260340ae3be46 Mon Sep 17 00:00:00 2001 From: Fnuworsu Date: Thu, 26 Mar 2026 02:52:49 -0500 Subject: [PATCH 2/2] Add quiet mode event coverage Signed-off-by: Fnuworsu --- internal/app/azldev/event_test.go | 57 ++++++++++++++++++++++++++++ internal/app/azldev/eventlistener.go | 7 +++- testproj/.gitignore | 5 --- testproj/azldev.toml | 12 ------ 4 files changed, 62 insertions(+), 19 deletions(-) create mode 100644 internal/app/azldev/event_test.go delete mode 100644 testproj/.gitignore delete mode 100644 testproj/azldev.toml diff --git a/internal/app/azldev/event_test.go b/internal/app/azldev/event_test.go new file mode 100644 index 0000000..0305882 --- /dev/null +++ b/internal/app/azldev/event_test.go @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +//nolint:testpackage // testing unexported internal types +package azldev + +import ( + "io" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func captureStderr(t *testing.T, action func()) string { + t.Helper() + + originalStderr := os.Stderr + reader, writer, err := os.Pipe() + require.NoError(t, err) + + t.Cleanup(func() { + os.Stderr = originalStderr + _ = writer.Close() + _ = reader.Close() + }) + + os.Stderr = writer + + action() + + require.NoError(t, writer.Close()) + + os.Stderr = originalStderr + + output, err := io.ReadAll(reader) + require.NoError(t, err) + + return string(output) +} + +func TestEvent_QuietModeSkipsLongRunningAndProgressRendering(t *testing.T) { + testEvent := &event{ + quiet: true, + } + + stderrOutput := captureStderr(t, func() { + testEvent.SetLongRunning("working") + testEvent.SetProgress(1, 10) + }) + + assert.Empty(t, stderrOutput) + assert.Nil(t, testEvent.spinner) + assert.False(t, testEvent.initializedProgressBar) + assert.Zero(t, testEvent.lastReportedCompletionRatio) +} diff --git a/internal/app/azldev/eventlistener.go b/internal/app/azldev/eventlistener.go index a809599..4ca926b 100644 --- a/internal/app/azldev/eventlistener.go +++ b/internal/app/azldev/eventlistener.go @@ -39,12 +39,15 @@ func NewEventListener(eventLogger *slog.Logger, quiet bool) (*appEventListener, // //nolint:ireturn,nolintlint // We need to return an interface because of the interface definition. func (el *appEventListener) StartEvent(name string, args ...any) opctx.Event { - if !el.quiet && name != "" { + if name != "" { const spacesPerLevel = 2 prefix := strings.Repeat(" ", el.eventLevel*spacesPerLevel) - fmt.Fprintf(os.Stderr, "\r") + if !el.quiet { + fmt.Fprintf(os.Stderr, "\r") + } + el.eventLogger.Info(prefix+name, args...) } diff --git a/testproj/.gitignore b/testproj/.gitignore deleted file mode 100644 index dd45194..0000000 --- a/testproj/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# Ignore build log and work dirs -build/ - -# Ignore build output -out/ diff --git a/testproj/azldev.toml b/testproj/azldev.toml deleted file mode 100644 index f14ec98..0000000 --- a/testproj/azldev.toml +++ /dev/null @@ -1,12 +0,0 @@ -'$schema' = 'https://raw.githubusercontent.com/microsoft/azure-linux-dev-tools/refs/heads/main/schemas/azldev.schema.json' - -[project] -description = 'testproj' -log-dir = 'build/logs' -work-dir = 'build/work' -output-dir = 'out' - -[component-groups] -[component-groups.default] -specs = ['**/*.spec'] -excluded-paths = ['build/**', 'out/**']