Skip to content

Add --list-steps flag to aspire do command#16085

Merged
mitchdenny merged 8 commits intomainfrom
feature/list-steps
Apr 14, 2026
Merged

Add --list-steps flag to aspire do command#16085
mitchdenny merged 8 commits intomainfrom
feature/list-steps

Conversation

@mitchdenny
Copy link
Copy Markdown
Member

Description

Adds support for aspire do --list-steps flag that prints the pipeline steps that would be executed, in topological (execution) order, along with their dependencies and tags — without actually running them.

Problem

Users need a simple way to inspect what pipeline steps will run for a given target. The existing aspire do diagnostics output is too verbose and technical for typical users (see issue discussion).

Approach

The implementation spans the AppHost (Aspire.Hosting) and CLI (Aspire.Cli), connected via the backchannel RPC:

AppHost side:

  • New PipelineStepInfo DTO in BackchannelDataTypes.cs (source-shared between CLI and AppHost)
  • New ResolveStepsAsync() on DistributedApplicationPipeline that resolves all steps (collects from annotations, normalizes RequiredBy→DependsOn, validates) without executing them
  • New GetPipelineStepsAsync() RPC method on AppHostRpcTarget with pipeline-steps.v1 capability

CLI side:

  • --list-steps option added to PipelineCommandBase (available on do, publish, deploy)
  • After backchannel connects, calls GetPipelineStepsAsync instead of streaming publishing activities
  • Formats output as a numbered tree, then calls RequestStopAsync to shut down the AppHost immediately

Example output:

1. parameter-prompt
   └─ No dependencies

2. provision-redis-infra
   ├─ Depends on: parameter-prompt
   └─ Tags: provision-infra

3. build-webapi
   ├─ Depends on: parameter-prompt
   └─ Tags: build-compute

4. deploy-webapi
   ├─ Depends on: provision-redis-infra, build-webapi
   └─ Tags: deploy-compute

Validation

  • All 2009 existing CLI tests pass (0 failures)
  • 5 new DoCommand integration tests (exit code, RPC calls, no pipeline execution)
  • 9 new PrintPipelineSteps formatting tests (dependencies, tags, connectors, numbering, empty steps, full pipeline)
  • 6 new pipeline resolution tests (ResolveStepsAsync, GetTopologicalOrder)
  • 1 new E2E CLI test using Hex1b terminal automation

Fixes #12376

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
    • No
  • Does the change require an update in our Aspire docs?

@mitchdenny mitchdenny requested a review from JamesNK as a code owner April 12, 2026 07:18
Copilot AI review requested due to automatic review settings April 12, 2026 07:18
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 12, 2026

🚀 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/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 16085

Or

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

Copy link
Copy Markdown
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

Adds a new --list-steps mode for Aspire pipeline commands that queries the AppHost for resolved pipeline steps and prints them (dependencies + tags) in execution/topological order, without running the pipeline.

Changes:

  • Introduces a backchannel DTO (PipelineStepInfo) and RPC (GetPipelineStepsAsync) to retrieve resolved pipeline steps from the AppHost.
  • Refactors DistributedApplicationPipeline to separate “resolve steps” from execution, and exposes topological sorting for reuse.
  • Adds CLI support (--list-steps) with formatting/output tests plus an end-to-end validation.

Reviewed changes

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

Show a summary per file
File Description
tests/Aspire.Hosting.Tests/Pipelines/DistributedApplicationPipelineTests.cs Adds tests for step resolution behavior and topological ordering.
tests/Aspire.Cli.Tests/TestServices/TestAppHostCliBackchannel.cs Extends the test backchannel stub with GetPipelineStepsAsync.
tests/Aspire.Cli.Tests/Commands/PublishCommandPromptingIntegrationTests.cs Updates mock backchannel implementation to satisfy the new interface method.
tests/Aspire.Cli.Tests/Commands/PipelineCommandListStepsTests.cs Adds unit tests for CLI formatting/output of --list-steps.
tests/Aspire.Cli.Tests/Commands/DoCommandTests.cs Adds integration tests verifying --list-steps RPC usage and non-execution behavior.
tests/Aspire.Cli.EndToEnd.Tests/ListStepsTests.cs Adds E2E test exercising aspire do deploy --list-steps in Docker terminal automation.
src/Aspire.Hosting/Pipelines/DistributedApplicationPipeline.cs Adds ResolveStepsAsync and exposes GetTopologicalOrder; execution now builds from resolved steps.
src/Aspire.Hosting/Backchannel/BackchannelDataTypes.cs Adds PipelineStepInfo DTO shared between AppHost and CLI.
src/Aspire.Hosting/Backchannel/AppHostRpcTarget.cs Advertises new capability and implements GetPipelineStepsAsync RPC.
src/Aspire.Cli/Commands/PipelineCommandBase.cs Adds --list-steps option and prints steps instead of streaming publish activities.
src/Aspire.Cli/Commands/DoCommand.cs Makes step optional to support --list-steps, adds runtime enforcement when not listing.
src/Aspire.Cli/Backchannel/BackchannelJsonSerializerContext.cs Registers PipelineStepInfo for source-generated JSON serialization.
src/Aspire.Cli/Backchannel/AppHostCliBackchannel.cs Adds RPC client method GetPipelineStepsAsync.

Comment on lines 375 to 404
@@ -368,7 +388,7 @@ public async Task ExecuteAsync(PipelineContext context)

if (allSteps.Count == 0)
{
return;
return allSteps;
}

ValidateSteps(allSteps);
@@ -380,10 +400,7 @@ public async Task ExecuteAsync(PipelineContext context)
// Capture resolved pipeline data for diagnostics (before filtering)
_lastResolvedSteps = allSteps;

var (stepsToExecute, stepsByName) = FilterStepsForExecution(allSteps, context);

// Build dependency graph and execute with readiness-based scheduler
await ExecuteStepsAsTaskDag(stepsToExecute, stepsByName, context).ConfigureAwait(false);
return allSteps;
}
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

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

ResolveStepsAsync XML docs say it "returns the steps in topological order" and "validates", but the method currently returns allSteps in original insertion order and does not validate the dependency graph for cycles (cycle validation only happens during execution). This can make --list-steps output incorrect/incomplete compared to actual execution failures. Consider calling the existing dependency-graph validation and returning a topologically sorted list here (or update the docs to match the actual behavior).

Copilot uses AI. Check for mistakes.
Comment thread src/Aspire.Cli/Commands/DoCommand.cs Outdated
Comment on lines +58 to +61
// Step is required when not using --list-steps
if (string.IsNullOrEmpty(step) && !parseResult.GetValue(s_listStepsOption))
{
throw new InvalidOperationException("The 'step' argument is required when not using --list-steps.");
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

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

Throwing InvalidOperationException when step is missing (and --list-steps is not set) will be surfaced via the generic exception handler in PipelineCommandBase as an "unexpected error" rather than a normal command-line validation error. Prefer System.CommandLine validation (e.g., AddValidator on the command/argument) so users get a standard parse error + help/usage and the correct exit code, without an exception-based control flow.

Suggested change
// Step is required when not using --list-steps
if (string.IsNullOrEmpty(step) && !parseResult.GetValue(s_listStepsOption))
{
throw new InvalidOperationException("The 'step' argument is required when not using --list-steps.");
// Step is required when not using --list-steps.
if (string.IsNullOrEmpty(step) && !parseResult.GetValue(s_listStepsOption))
{
var stepResult = parseResult.GetResult(_stepArgument);
if (stepResult is not null)
{
stepResult.AddError("The 'step' argument is required when not using --list-steps.");
}
else
{
parseResult.CommandResult.AddError("The 'step' argument is required when not using --list-steps.");
}
return [];

Copilot uses AI. Check for mistakes.
Comment on lines +259 to +270
// If --list-steps was specified, get pipeline steps and print them instead of executing
var listSteps = parseResult.GetValue(s_listStepsOption);
if (listSteps)
{
StopTerminalProgressBar();

var steps = await backchannel.GetPipelineStepsAsync(cancellationToken);
PrintPipelineSteps(steps);

await backchannel.RequestStopAsync(cancellationToken).ConfigureAwait(false);
await pendingRun;
return ExitCodeConstants.Success;
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

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

The --list-steps path calls GetPipelineStepsAsync unconditionally. If the user runs a newer CLI against an older AppHost that doesn't advertise/support pipeline-steps.v1, this will likely fail with RemoteMethodNotFoundException and be reported as an "unexpected error". Consider checking backchannel.GetCapabilitiesAsync(...) for pipeline-steps.v1 (or catching RemoteMethodNotFoundException here) and converting it into an AppHostIncompatibleException with a clear message.

Copilot uses AI. Check for mistakes.
Comment on lines +4 to +5
#pragma warning disable ASPIREPIPELINES001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.

Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

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

#pragma warning disable ASPIREPIPELINES001 is added at the top of the file but never restored/scoped. This suppresses the diagnostic for the entire RPC target, potentially masking unrelated occurrences. Consider scoping the suppression just around the code that requires it, or add a corresponding #pragma warning restore ASPIREPIPELINES001.

Copilot uses AI. Check for mistakes.
@davidfowl
Copy link
Copy Markdown
Contributor

I want to make sure that we have 2 things:

@mitchdenny
Copy link
Copy Markdown
Member Author

I want to make sure that we have 2 things:

image

@davidfowl
Copy link
Copy Markdown
Contributor

Dogfood Testing Report

CLI Version: 13.3.0-pr.16085.gcbe15d70 (commit cbe15d7)
Tested on: DigitalOcean Ubuntu 24.04, .NET 10.0.105

Results

Scenario Result
New CLI + Old AppHost (GA 13.2.2) ✅ Clean error: "The AppHost does not support --list-steps. Update the AppHost to a newer version of Aspire."
aspire do --list-steps (new AppHost) ✅ Shows 15 steps with correct dependency tree
aspire publish --list-steps ✅ Works
aspire deploy --list-steps ✅ Works
aspire do build --list-steps ⚠️ See feedback below

Feedback: --list-steps should scope to the target

Currently all three of these produce the same 15-step output:

aspire do --list-steps
aspire do build --list-steps
aspire publish --list-steps

I would expect aspire do build --list-steps to only show the build step and its transitive dependencies:

1. process-parameters
   └─ No dependencies

2. build-prereq
   └─ Depends on: process-parameters

3. build-apiservice
   ├─ Depends on: build-prereq
   └─ Tags: build-compute

4. build-webfrontend
   ├─ Depends on: build-prereq
   └─ Tags: build-compute

5. build
   └─ Depends on: build-apiservice, build-webfrontend

Not the full graph including deploy/push steps. Similarly aspire publish --list-steps should scope to the publish step and its deps. This would make the flag much more useful for understanding what a specific target will actually do.

mitchdenny and others added 8 commits April 14, 2026 09:07
Implement support for 'aspire do --list-steps' that prints pipeline steps
in execution order with their dependencies and tags, without executing them.

Changes:
- Add PipelineStepInfo DTO to BackchannelDataTypes.cs (source-shared)
- Add ResolveStepsAsync to DistributedApplicationPipeline for resolving
  steps without executing them
- Add GetPipelineStepsAsync RPC method to AppHostRpcTarget with
  'pipeline-steps.v1' capability
- Add GetPipelineStepsAsync to IAppHostCliBackchannel interface and
  implementations
- Add --list-steps option to PipelineCommandBase with formatted output
- Make DoCommand step argument optional when --list-steps is used

Testing:
- Unit tests for DoCommand with --list-steps (returns 0, calls
  GetPipelineStepsAsync, does not execute pipeline, calls RequestStopAsync)
- Unit tests for PrintPipelineSteps formatting (dependencies, tags,
  sequential numbering, empty steps, full pipeline output)
- Unit tests for ResolveStepsAsync and GetTopologicalOrder
- E2E CLI test using Hex1b terminal automation

Fixes #12376

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add color to the output: green step numbers, blue 'Depends on:' label,
yellow 'Tags:' label, dim 'No dependencies' text. Add hanging indent
for long dependency lists so wrapped items align under the first item.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The Spectre.Console AnsiConsole emits ANSI escape codes even with
AnsiSupport.No in CI environments. Strip ANSI codes before asserting
on output content.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix the continuation line indent to align wrapped dependency items
directly under the first item (19 chars), not double-indented.
Change step name color from bold white to cyan for better visibility.

Before:
   ├─ Depends on: provision-redis-infra, provision-postgres-infra,
                                          build-webapi
After:
   ├─ Depends on: provision-redis-infra, provision-postgres-infra,
                   build-webapi

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Compute the continuation prefix width from the visible length of the
first line prefix rather than hardcoding spaces. This ensures wrapped
dependency items align correctly under the first item regardless of
unicode box-drawing character widths.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Use request/response objects (GetPipelineStepsRequest/Response) per
  the backchannel spec contract rules instead of raw array return
- Add capability check for 'pipeline-steps.v1' before calling
  GetPipelineStepsAsync, throwing AppHostIncompatibleException with a
  clear message if the AppHost doesn't support it
- Scope #pragma warning disable ASPIREPIPELINES001 to just the method
  that needs it instead of file-wide
- Fix ResolveStepsAsync XML doc to accurately state it returns
  collection order (not topological order)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When a target step is specified (e.g. 'aspire do build --list-steps'),
only show that step and its transitive dependencies instead of the
full pipeline graph. This makes the output much more useful for
understanding what a specific target will actually do.

- aspire do --list-steps          -> all steps (no filter)
- aspire do build --list-steps    -> build + its deps only
- aspire publish --list-steps     -> publish + its deps only
- aspire deploy --list-steps      -> deploy + its deps only

Each PipelineCommandBase subclass provides its target step name via
GetTargetStepName(). The step name is passed in GetPipelineStepsRequest
and the AppHost filters using ComputeTransitiveDependencies.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace InvalidOperationException with a proper command validator so
users get a standard parse error with help/usage output instead of an
unexpected error when running 'aspire do' without a step argument
and without --list-steps.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

🎬 CLI E2E Test Recordings — 70 recordings uploaded (commit d8c2da8)

View recordings
Test Recording
AddPackageInteractiveWhileAppHostRunningDetached ▶️ View Recording
AddPackageWhileAppHostRunningDetached ▶️ View Recording
AgentCommands_AllHelpOutputs_AreCorrect ▶️ View Recording
AgentInitCommand_DefaultSelection_InstallsSkillOnly ▶️ View Recording
AgentInitCommand_MigratesDeprecatedConfig ▶️ View Recording
AllPublishMethodsBuildDockerImages ▶️ View Recording
AspireAddPackageVersionToDirectoryPackagesProps ▶️ View Recording
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps ▶️ View Recording
Banner_DisplayedOnFirstRun ▶️ View Recording
Banner_DisplayedWithExplicitFlag ▶️ View Recording
Banner_NotDisplayedWithNoLogoFlag ▶️ View Recording
CertificatesClean_RemovesCertificates ▶️ View Recording
CertificatesTrust_WithNoCert_CreatesAndTrustsCertificate ▶️ View Recording
CertificatesTrust_WithUntrustedCert_TrustsCertificate ▶️ View Recording
ConfigSetGet_CreatesNestedJsonFormat ▶️ View Recording
CreateAndRunAspireStarterProject ▶️ View Recording
CreateAndRunAspireStarterProjectWithBundle ▶️ View Recording
CreateAndRunEmptyAppHostProject ▶️ View Recording
CreateAndRunJavaEmptyAppHostProject ▶️ View Recording
CreateAndRunJsReactProject ▶️ View Recording
CreateAndRunPythonReactProject ▶️ View Recording
CreateAndRunTypeScriptEmptyAppHostProject ▶️ View Recording
CreateAndRunTypeScriptStarterProject ▶️ View Recording
CreateJavaAppHostWithViteApp ▶️ View Recording
CreateStartAndStopAspireProject ▶️ View Recording
CreateTypeScriptAppHostWithViteApp ▶️ View Recording
DashboardRunWithOtelTracesReturnsNoTraces ▶️ View Recording
DeployK8sBasicApiService ▶️ View Recording
DeployK8sWithGarnet ▶️ View Recording
DeployK8sWithMongoDB ▶️ View Recording
DeployK8sWithMySql ▶️ View Recording
DeployK8sWithPostgres ▶️ View Recording
DeployK8sWithRabbitMQ ▶️ View Recording
DeployK8sWithRedis ▶️ View Recording
DeployK8sWithSqlServer ▶️ View Recording
DeployK8sWithValkey ▶️ View Recording
DeployTypeScriptAppToKubernetes ▶️ View Recording
DescribeCommandResolvesReplicaNames ▶️ View Recording
DescribeCommandShowsRunningResources ▶️ View Recording
DetachFormatJsonProducesValidJson ▶️ View Recording
DoListStepsShowsPipelineSteps ▶️ View Recording
DoctorCommand_DetectsDeprecatedAgentConfig ▶️ View Recording
DoctorCommand_WithSslCertDir_ShowsTrusted ▶️ View Recording
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted ▶️ View Recording
GlobalMigration_HandlesCommentsAndTrailingCommas ▶️ View Recording
GlobalMigration_HandlesMalformedLegacyJson ▶️ View Recording
GlobalMigration_PreservesAllValueTypes ▶️ View Recording
GlobalMigration_SkipsWhenNewConfigExists ▶️ View Recording
GlobalSettings_MigratedFromLegacyFormat ▶️ View Recording
InitTypeScriptAppHost_AugmentsExistingViteRepoAtRoot ▶️ View Recording
InvalidAppHostPathWithComments_IsHealedOnRun ▶️ View Recording
LegacySettingsMigration_AdjustsRelativeAppHostPath ▶️ View Recording
LogsCommandShowsResourceLogs ▶️ View Recording
PsCommandListsRunningAppHost ▶️ View Recording
PsFormatJsonOutputsOnlyJsonToStdout ▶️ View Recording
PublishWithConfigureEnvFileUpdatesEnvOutput ▶️ View Recording
PublishWithDockerComposeServiceCallbackSucceeds ▶️ View Recording
RestoreGeneratesSdkFiles ▶️ View Recording
RestoreSupportsConfigOnlyHelperPackageAndCrossPackageTypes ▶️ View Recording
RunFromParentDirectory_UsesExistingConfigNearAppHost ▶️ View Recording
SecretCrudOnDotNetAppHost ▶️ View Recording
SecretCrudOnTypeScriptAppHost ▶️ View Recording
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels ▶️ View Recording
StartAndWaitForTypeScriptSqlServerAppHostWithNativeAssets ▶️ View Recording
StopAllAppHostsFromAppHostDirectory ▶️ View Recording
StopAllAppHostsFromUnrelatedDirectory ▶️ View Recording
StopNonInteractiveMultipleAppHostsShowsError ▶️ View Recording
StopNonInteractiveSingleAppHost ▶️ View Recording
StopWithNoRunningAppHostExitsSuccessfully ▶️ View Recording
UnAwaitedChainsCompileWithAutoResolvePromises ▶️ View Recording

📹 Recordings uploaded automatically from CI run #24371556571

Copy link
Copy Markdown
Contributor

@davidfowl davidfowl left a comment

Choose a reason for hiding this comment

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

Approved after testing the PR build on the pr-16093-test droplet.

@davidfowl
Copy link
Copy Markdown
Contributor

Tested this on the pr-16093-test DigitalOcean droplet using the PR dogfood build 13.3.0-pr.16085.gd8c2da87 (run 24371556571).

Results:

  • New CLI + old AppHost (13.2.2): clean error: The AppHost does not support --list-steps. Update the AppHost to a newer version of Aspire.
  • .NET AppHost from the PR build: aspire do --list-steps, aspire do build --list-steps, aspire publish --list-steps, and aspire deploy --list-steps all work. do build --list-steps is properly scoped.
  • TypeScript AppHosts from the PR build: empty and starter app hosts also work.

Follow-up issues:

  1. aspire publish --list-steps and aspire deploy --list-steps still print Executing step ... instead of Listing pipeline steps. Reproduced in both .NET and TypeScript AppHosts.
  2. On TypeScript AppHosts with Aspire.Hosting.JavaScript, push-app shows duplicate dependencies. Reproduced in both aspire-ts-starter and aspire-ts-empty after aspire add Aspire.Hosting.JavaScript and wiring the same Node+Vite pattern:
    push-app -> Depends on: build-app, push-prereq, build-app, push-prereq

@mitchdenny mitchdenny merged commit 6920012 into main Apr 14, 2026
280 checks passed
@joperezr joperezr added this to the 13.3 milestone Apr 14, 2026
radical pushed a commit that referenced this pull request Apr 14, 2026
* Add --list-steps flag to aspire do command

Implement support for 'aspire do --list-steps' that prints pipeline steps
in execution order with their dependencies and tags, without executing them.

Changes:
- Add PipelineStepInfo DTO to BackchannelDataTypes.cs (source-shared)
- Add ResolveStepsAsync to DistributedApplicationPipeline for resolving
  steps without executing them
- Add GetPipelineStepsAsync RPC method to AppHostRpcTarget with
  'pipeline-steps.v1' capability
- Add GetPipelineStepsAsync to IAppHostCliBackchannel interface and
  implementations
- Add --list-steps option to PipelineCommandBase with formatted output
- Make DoCommand step argument optional when --list-steps is used

Testing:
- Unit tests for DoCommand with --list-steps (returns 0, calls
  GetPipelineStepsAsync, does not execute pipeline, calls RequestStopAsync)
- Unit tests for PrintPipelineSteps formatting (dependencies, tags,
  sequential numbering, empty steps, full pipeline output)
- Unit tests for ResolveStepsAsync and GetTopologicalOrder
- E2E CLI test using Hex1b terminal automation

Fixes #12376

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Improve --list-steps output formatting

Add color to the output: green step numbers, blue 'Depends on:' label,
yellow 'Tags:' label, dim 'No dependencies' text. Add hanging indent
for long dependency lists so wrapped items align under the first item.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix PrintPipelineSteps tests to strip ANSI escape codes

The Spectre.Console AnsiConsole emits ANSI escape codes even with
AnsiSupport.No in CI environments. Strip ANSI codes before asserting
on output content.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix hanging indent alignment and use cyan for step names

Fix the continuation line indent to align wrapped dependency items
directly under the first item (19 chars), not double-indented.
Change step name color from bold white to cyan for better visibility.

Before:
   ├─ Depends on: provision-redis-infra, provision-postgres-infra,
                                          build-webapi
After:
   ├─ Depends on: provision-redis-infra, provision-postgres-infra,
                   build-webapi

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix wrapped dependency alignment to be computed dynamically

Compute the continuation prefix width from the visible length of the
first line prefix rather than hardcoding spaces. This ensures wrapped
dependency items align correctly under the first item regardless of
unicode box-drawing character widths.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address review feedback: backchannel spec compliance and versioning

- Use request/response objects (GetPipelineStepsRequest/Response) per
  the backchannel spec contract rules instead of raw array return
- Add capability check for 'pipeline-steps.v1' before calling
  GetPipelineStepsAsync, throwing AppHostIncompatibleException with a
  clear message if the AppHost doesn't support it
- Scope #pragma warning disable ASPIREPIPELINES001 to just the method
  that needs it instead of file-wide
- Fix ResolveStepsAsync XML doc to accurately state it returns
  collection order (not topological order)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Scope --list-steps output to target step and its dependencies

When a target step is specified (e.g. 'aspire do build --list-steps'),
only show that step and its transitive dependencies instead of the
full pipeline graph. This makes the output much more useful for
understanding what a specific target will actually do.

- aspire do --list-steps          -> all steps (no filter)
- aspire do build --list-steps    -> build + its deps only
- aspire publish --list-steps     -> publish + its deps only
- aspire deploy --list-steps      -> deploy + its deps only

Each PipelineCommandBase subclass provides its target step name via
GetTargetStepName(). The step name is passed in GetPipelineStepsRequest
and the AppHost filters using ComputeTransitiveDependencies.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use System.CommandLine validator for missing step argument

Replace InvalidOperationException with a proper command validator so
users get a standard parse error with help/usage output instead of an
unexpected error when running 'aspire do' without a step argument
and without --list-steps.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced Apr 24, 2026
mitchdenny added a commit to microsoft/aspire.dev that referenced this pull request May 6, 2026
#847)

The reference docs for aspire do and the deployment/pipelines conceptual
page already document the --list-steps flag, but neither shows what the
output actually looks like. Add a short, canonical numbered-tree sample
(matches the formatter in microsoft/aspire#16085 and its snapshot tests)
so readers can see at a glance what to expect — including the connectors
used for steps with deps only, deps and tags, and steps with no
dependencies.

Context: #837 (item #2), follow-up polish to #801.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for aspire do --list-steps flag

4 participants