diff --git a/src/Aspire.Cli/Commands/PipelineCommandBase.cs b/src/Aspire.Cli/Commands/PipelineCommandBase.cs index b8f7a14e211..ba3b9f3f314 100644 --- a/src/Aspire.Cli/Commands/PipelineCommandBase.cs +++ b/src/Aspire.Cli/Commands/PipelineCommandBase.cs @@ -224,11 +224,16 @@ protected override async Task ExecuteAsync(ParseResult parseResult, Cancell var publishingActivities = backchannel.GetPublishingActivitiesAsync(cancellationToken); var debugMode = parseResult.GetValue("--debug") ?? false; + + // Check if debug or trace logging is enabled + var logLevel = parseResult.GetValue(_logLevelOption); + var isDebugOrTraceLoggingEnabled = logLevel?.Equals("debug", StringComparison.OrdinalIgnoreCase) == true || + logLevel?.Equals("trace", StringComparison.OrdinalIgnoreCase) == true; var noFailuresReported = debugMode switch { true => await ProcessPublishingActivitiesDebugAsync(publishingActivities, backchannel, cancellationToken), - false => await ProcessAndDisplayPublishingActivitiesAsync(publishingActivities, backchannel, cancellationToken), + false => await ProcessAndDisplayPublishingActivitiesAsync(publishingActivities, backchannel, isDebugOrTraceLoggingEnabled, cancellationToken), }; // Send terminal progress bar stop sequence @@ -406,11 +411,11 @@ public async Task ProcessPublishingActivitiesDebugAsync(IAsyncEnumerable

ProcessAndDisplayPublishingActivitiesAsync(IAsyncEnumerable publishingActivities, IAppHostBackchannel backchannel, CancellationToken cancellationToken) + public async Task ProcessAndDisplayPublishingActivitiesAsync(IAsyncEnumerable publishingActivities, IAppHostBackchannel backchannel, bool isDebugOrTraceLoggingEnabled, CancellationToken cancellationToken) { var stepCounter = 1; var steps = new Dictionary(); - var logger = new ConsoleActivityLogger(_hostEnvironment); + var logger = new ConsoleActivityLogger(_hostEnvironment, isDebugOrTraceLoggingEnabled); logger.StartSpinner(); PublishingActivity? publishingActivity = null; diff --git a/src/Aspire.Cli/Utils/ConsoleActivityLogger.cs b/src/Aspire.Cli/Utils/ConsoleActivityLogger.cs index db66fd54475..5143b0bd3f3 100644 --- a/src/Aspire.Cli/Utils/ConsoleActivityLogger.cs +++ b/src/Aspire.Cli/Utils/ConsoleActivityLogger.cs @@ -18,6 +18,7 @@ internal sealed class ConsoleActivityLogger { private readonly bool _enableColor; private readonly ICliHostEnvironment _hostEnvironment; + private readonly bool _isDebugOrTraceLoggingEnabled; private readonly object _lock = new(); private readonly Stopwatch _stopwatch = Stopwatch.StartNew(); private readonly Dictionary _stepColors = new(); @@ -35,6 +36,9 @@ internal sealed class ConsoleActivityLogger private readonly char[] _spinnerChars = ['|', '/', '-', '\\']; private int _spinnerIndex; + private string? _finalStatusHeader; + private bool _pipelineSucceeded; + // No raw ANSI escape codes; rely on Spectre.Console markup tokens. private const string SuccessSymbol = "✓"; @@ -43,10 +47,11 @@ internal sealed class ConsoleActivityLogger private const string InProgressSymbol = "→"; private const string InfoSymbol = "i"; - public ConsoleActivityLogger(ICliHostEnvironment hostEnvironment, bool? forceColor = null) + public ConsoleActivityLogger(ICliHostEnvironment hostEnvironment, bool isDebugOrTraceLoggingEnabled = false, bool? forceColor = null) { _hostEnvironment = hostEnvironment; _enableColor = forceColor ?? _hostEnvironment.SupportsAnsi; + _isDebugOrTraceLoggingEnabled = isDebugOrTraceLoggingEnabled; // Disable spinner in non-interactive environments if (!_hostEnvironment.SupportsInteractiveOutput) @@ -252,20 +257,28 @@ public void WriteSummary() if (!string.IsNullOrEmpty(_finalStatusHeader)) { AnsiConsole.MarkupLine(_finalStatusHeader!); + + // If pipeline failed and not already in debug/trace mode, show help message about using --log-level debug + if (!_pipelineSucceeded && !_isDebugOrTraceLoggingEnabled) + { + var helpMessage = _enableColor + ? "[dim]For more details, add --log-level debug/trace to the command.[/]" + : "For more details, add --log-level debug/trace to the command."; + AnsiConsole.MarkupLine(helpMessage); + } } AnsiConsole.MarkupLine(line); AnsiConsole.WriteLine(); // Ensure final newline after deployment summary } } - private string? _finalStatusHeader; - ///

/// Sets the final deployment result lines to be displayed in the summary (e.g., DEPLOYMENT FAILED ...). /// Optional usage so existing callers remain compatible. /// public void SetFinalResult(bool succeeded) { + _pipelineSucceeded = succeeded; // Always show only a single final header line with symbol; no per-step duplication. if (succeeded) {