Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 1, 2025

Add help message when pipeline fails

Fixes the issue where users don't know what to do when the pipeline fails because errors are cleaned up and there's no guidance on how to get more diagnostic information.

Problem

When CLI pipeline commands (aspire deploy, aspire publish, aspire do) fail:

  1. There's no output - We don't show outputs from failed CLI commands by default (especially docker buildx)
  2. We don't tell users what to try next - Users aren't aware they can use --log-level debug to get detailed diagnostics

Solution

Modified the pipeline summary to display a helpful message when the pipeline fails, guiding users to add --log-level debug/trace for detailed error information. The message is suppressed when debug or trace logging is already enabled to avoid redundant advice.

Changes Made

  1. ConsoleActivityLogger.cs:

    • Added _isDebugOrTraceLoggingEnabled readonly field, passed via constructor
    • Added _pipelineSucceeded field to track if pipeline succeeded
    • Modified constructor to accept isDebugOrTraceLoggingEnabled parameter
    • Modified SetFinalResult() to store only the succeeded value
    • Updated WriteSummary() to display help message when pipeline fails (only if not already in debug/trace mode)
    • Reorganized fields for better maintainability
  2. PipelineCommandBase.cs:

    • Check if --log-level debug or --log-level trace was passed
    • Updated ConsoleActivityLogger instantiation to pass the debug/trace logging flag
    • Updated call to logger.SetFinalResult() to pass only the succeeded boolean

Example Output

Before (when pipeline fails):

------------------------------------------------------------
✗ 0/1 steps succeeded • ✗ 1 failed • Total time: 5.2s
✗ PIPELINE FAILED
------------------------------------------------------------

After (when pipeline fails without --log-level debug):

------------------------------------------------------------
✗ 0/1 steps succeeded • ✗ 1 failed • Total time: 5.2s
✗ PIPELINE FAILED
For more details, add --log-level debug/trace to the command.
------------------------------------------------------------

After (when pipeline fails WITH --log-level debug/trace):

------------------------------------------------------------
✗ 0/1 steps succeeded • ✗ 1 failed • Total time: 5.2s
✗ PIPELINE FAILED
------------------------------------------------------------

(No help message shown since user already has debug/trace logging enabled)

Implementation Details

  • The help message only appears when:
    1. The pipeline fails (succeeded: false)
    2. User has NOT passed --log-level debug or --log-level trace
  • The message uses dim color (when color is enabled) for better visual hierarchy
  • Message is generic and doesn't include specific command/arguments, avoiding confusion when arguments are passed
  • Works for all pipeline commands: aspire deploy, aspire publish, aspire do <step>
  • Fields are organized logically for better maintainability

Testing

  • ✅ Build succeeds with no compilation errors
  • ✅ Changes are minimal and focused
  • ✅ Follows existing code patterns and conventions
  • ✅ Uses boolean field instead of string Contains check for cleaner logic
  • ✅ Message suppressed when debug/trace logging already enabled
  • ✅ Generic message that works with any arguments
  • ✅ Fields organized logically for better maintainability

<issue_title>When the pipeline fails its hard to see errors</issue_title>

<issue_description>The errors are all cleaned up in the pipeline and we no longer see stack traces of output from other CLIs by default (they are usually debug). The problem is now that it's hard to know what to do when the pipeline fails because:

  1. There's no output - We don't show outputs from failed CLI executed by by default. The worst offender being docker buildx.
  2. We don't tell you what to try next - aspire do {step} --log-level debug. There's nothing that tells you to to do this. </issue_description>

<agent_instructions>In PipelineCommandBase, when rendering the summary, if the pipeline failed, we want to print out a message that tells users to re-run the command using --log-level debug to get more details.</agent_instructions>

Original prompt

This section details on the original issue you should resolve

<issue_title>When the pipeline fails its hard to see errors</issue_title>
<issue_description>The errors are all cleaned up in the pipeline and we no longer see stack traces of output from other CLIs by default (they are usually debug). The problem is now that it's hard to know what to do when the pipeline fails because:

  1. There's no output - We don't show outputs from failed CLI executed by by default. The worst offender being docker buildx.
  2. We don't tell you what to try next - aspire do {step} --log-level debug. There's nothing that tells you to to do this. </issue_description>

<agent_instructions>In PipelineCommandBase, when rendering the summary, if the pipeline failed, we want to print out a message that tells users to re-run the command using --log-level debug to get more details.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@captainsafia > There's no output - We don't show outputs from failed CLI executed by by default. The worst offender being docker buildx.

If we implement the ExecutablePipelineStep that we've been talking about that provides an easy wrapper around calling an executable on the local machine, we can probably centralize this. Our stderr handling is all over the place depending on who is calling ProcessUtils.Run but we can probably include a sane default that pipes all stderr to debug level logs.

The other challenge with executables is that our ability to provide good errors is limited by the errors the tool itself provides.

We don't tell you what to try next - aspire do {step} --log-level debug. There's nothing that tells you to to do this.

Perhaps a nice increment is to include a message about setting the log verbosity on the PIPELINE FAILED message?</comment_new>
<comment_new>@davidfowl

If we implement the ExecutablePipelineStep that we've been talking about that provides an easy wrapper around calling an executable on the local machine, we can probably centralize this. Our stderr handling is all over the place depending on who is calling ProcessUtils.Run but we can probably include a sane default that pipes all stderr to debug level logs.

This was my thought as well. We might need to expose some minimal API to let people run code before the step completetes with various piece of state (exit code etc).

The other challenge with executables is that our ability to provide good errors is limited by the errors the tool itself provides.

That's why I am a bit torn on if we should spew it by default, but a combination of debug by default and telling users what to do when it does fail might help.</comment_new>


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI self-assigned this Nov 1, 2025
- Modified ConsoleActivityLogger to accept optional commandName in SetFinalResult
- Display help message when pipeline fails with command name
- Updated PipelineCommandBase to pass command name to logger

Co-authored-by: davidfowl <[email protected]>
AnsiConsole.MarkupLine(_finalStatusHeader!);

// If pipeline failed, show help message about using --log-level debug
if (_finalStatusHeader.Contains("PIPELINE FAILED") && !string.IsNullOrEmpty(_commandName))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot instead of doing this crude Contains check, we should store the bool from the call to SetFinalResult in a field and use it here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Changed to use _pipelineSucceeded boolean field instead of string Contains check. (e8bed6c)

Copilot AI changed the title [WIP] Update pipeline to show detailed error messages on failure Show --log-level debug hint when pipeline fails Nov 1, 2025
Copilot AI requested a review from davidfowl November 1, 2025 22:46
@davidfowl
Copy link
Member

@copilot The command name should be passed in the ctor of ConsoleActivityLogger

Store the succeeded value from SetFinalResult in _pipelineSucceeded field
and use !_pipelineSucceeded instead of checking if string contains "PIPELINE FAILED"

Co-authored-by: davidfowl <[email protected]>
Move command name from SetFinalResult parameter to constructor parameter.
This is cleaner since the command name doesn't change throughout the
lifecycle of the logger.

Co-authored-by: davidfowl <[email protected]>
Copy link
Contributor Author

Copilot AI commented Nov 1, 2025

@copilot The command name should be passed in the ctor of ConsoleActivityLogger

Done. Command name is now passed in the constructor and stored as a readonly field. (a2313fd)

@davidfowl
Copy link
Member

@copilot Why is the command name nullable? It should never be null. The other changes look good.

The commandName parameter is always provided from PipelineCommandBase.Name
and should never be null. Changed constructor signature to make it a
required parameter and removed null checks.

Co-authored-by: davidfowl <[email protected]>
Copy link
Contributor Author

Copilot AI commented Nov 1, 2025

@copilot Why is the command name nullable? It should never be null. The other changes look good.

You're right. Made commandName a required non-nullable parameter since it's always provided from this.Name. Removed the null check in WriteSummary(). (d8a8b60)

@davidfowl davidfowl marked this pull request as ready for review November 1, 2025 23:12
Copilot AI review requested due to automatic review settings November 1, 2025 23:12
@github-actions
Copy link
Contributor

github-actions bot commented Nov 1, 2025

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 12603

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 12603"

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR enhances the ConsoleActivityLogger to provide contextual help messages when pipeline commands (deploy, publish, do) fail. The changes enable the logger to display a helpful suggestion to re-run the command with --log-level debug for more diagnostic information.

Key changes:

  • Added commandName parameter to ConsoleActivityLogger constructor to track which CLI command is being executed
  • Modified WriteSummary() to display a help message when the pipeline fails, suggesting the user re-run with debug logging enabled
  • Updated field ordering to follow common C# conventions

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/Aspire.Cli/Utils/ConsoleActivityLogger.cs Added _commandName field and parameter, implemented help message display in WriteSummary() when pipeline fails
src/Aspire.Cli/Commands/PipelineCommandBase.cs Updated ConsoleActivityLogger instantiation to pass this.Name as the command name

Comment on lines 21 to 22
private readonly string _commandName;
private readonly object _lock = new();
Copy link

Copilot AI Nov 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The new field _commandName is placed between _hostEnvironment and _lock, disrupting the logical grouping of fields. Consider placing _commandName immediately after _hostEnvironment (line 20) and before _lock to maintain better field organization, as both _hostEnvironment and _commandName are constructor parameters that store configuration, while _lock begins the section of runtime state fields.

Suggested change
private readonly string _commandName;
private readonly object _lock = new();
private readonly object _lock = new();
private readonly string _commandName;

Copilot uses AI. Check for mistakes.
Comment on lines 261 to 273
private string? _finalStatusHeader;
private bool _pipelineSucceeded;
Copy link

Copilot AI Nov 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The _pipelineSucceeded field is placed after _finalStatusHeader but at a different location in the class than where other instance fields are declared (lines 19-37). For consistency and maintainability, consider moving both _finalStatusHeader and _pipelineSucceeded to the top of the class with the other private fields (after line 37, before the constants section starting at line 41).

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Moved _finalStatusHeader and _pipelineSucceeded fields to the top with other private fields for better organization. (47810f2)

Move _finalStatusHeader and _pipelineSucceeded fields to the top with
other private fields for better organization and consistency.

Co-authored-by: davidfowl <[email protected]>
@davidfowl
Copy link
Member

@copilot When I run a command like:

aspire do foo

I see

23:06:32 (pipeline execution) → Starting pipeline execution...
23:06:32 (foo) → Starting foo...
23:06:32 (foo) i [INF] Starting step 'foo'
23:06:32 (foo) ✗ [ERR] Step 'foo' failed.
23:06:32 (foo) ✗ Step 'foo' failed: This is a test exception.
23:06:32 (pipeline execution) ✗ [ERR] Step 'foo' failed: This is a test exception.
23:06:32 (pipeline execution) ✗ Failed

✓ 0/2 steps succeeded • ✗ 2 failed • Total time: 0.0s

Steps Summary:
0.0 s ✗ pipeline execution
0.0 s ✗ foo

✗ PIPELINE FAILED
For more details, re-run with: aspire do --log-level debug

The command has the name but is missing the arguments I passed previously. To rectify this, we an leave the exact command name out of the message and say "For more details, add --log-level debug/trace to the command."

The second problem is if I do pass --log-level it still says "for more details add --log-level debug". In order to rectify this, we can ignore this message if the --log-level flag is being passed with debug or trace.

- Changed message to generic "For more details, add --log-level debug/trace to the command."
- Suppress help message when user already passed --log-level debug or trace
- Replaced commandName parameter with isDebugOrTraceLoggingEnabled flag

Co-authored-by: davidfowl <[email protected]>
Copy link
Contributor Author

Copilot AI commented Nov 2, 2025

@copilot When I run a command like:

aspire do foo...

Done. Changed the message to be generic: "For more details, add --log-level debug/trace to the command." The message is now suppressed when --log-level debug or --log-level trace is already passed. (44ca5e2)

@davidfowl davidfowl merged commit 7186f68 into main Nov 3, 2025
586 of 591 checks passed
@davidfowl davidfowl deleted the copilot/update-pipeline-error-output branch November 3, 2025 01:51
@davidfowl
Copy link
Member

/backport to release/13.0

@dotnet-policy-service dotnet-policy-service bot added this to the 13.1 milestone Nov 3, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Nov 3, 2025

Started backporting to release/13.0: https://github.com/dotnet/aspire/actions/runs/19021647033

@github-actions github-actions bot locked and limited conversation to collaborators Dec 3, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

When the pipeline fails its hard to see errors

3 participants