Add shortcut for aspire run --detached via aspire start#14644
Add shortcut for aspire run --detached via aspire start#14644davidfowl merged 2 commits intorelease/13.2from
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 14644Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 14644" |
There was a problem hiding this comment.
Pull request overview
This pull request refactors the CLI's detached launch functionality to fix argument forwarding for aspire start and aspire run commands. The changes extract shared detached launch logic into a new AppHostLauncher class and enhance StartCommand to support launching an AppHost in the background when no resource name is provided.
Changes:
- Extracted detached AppHost launch logic from
RunCommandinto a new sharedAppHostLauncherclass to eliminate code duplication - Enhanced
StartCommandto support dual modes: starting a specific resource (existing behavior) or starting the AppHost in detached mode (new behavior) when no resource name is provided - Updated localization strings to reflect the new dual-purpose nature of
aspire start
Reviewed changes
Copilot reviewed 34 out of 35 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Aspire.Cli/Commands/AppHostLauncher.cs | New internal class encapsulating detached AppHost launch logic, extracted from RunCommand to enable code reuse |
| src/Aspire.Cli/Commands/RunCommand.cs | Refactored to delegate detached launch logic to AppHostLauncher, removing ~250 lines of duplicated code |
| src/Aspire.Cli/Commands/StartCommand.cs | Changed from ResourceCommandBase to BaseCommand; now supports optional resource argument and detached AppHost launch |
| src/Aspire.Cli/Program.cs | Registered AppHostLauncher in DI container |
| tests/Aspire.Cli.Tests/Utils/CliTestHelper.cs | Registered AppHostLauncher in test DI setup |
| src/Aspire.Cli/Resources/ResourceCommandStrings.resx | Added OptionNotValidWithResource string; updated StartDescription and StartResourceArgumentDescription |
| src/Aspire.Cli/Resources/RunCommandStrings.resx | Updated Description and JsonArgumentDescription for clarity |
| src/Aspire.Cli/Resources/*.xlf | Updated localization files with new/modified strings marked for translation |
| .github/skills/create-pr/SKILL.md | Added GitHub Copilot skill definition for creating PRs (unrelated to main PR purpose) |
Files not reviewed (1)
- src/Aspire.Cli/Resources/ResourceCommandStrings.Designer.cs: Language not supported
🎬 CLI E2E Test RecordingsThe following terminal recordings are available for commit
📹 Recordings uploaded automatically from CI run #22380578937 |
80a0071 to
6983e1b
Compare
| IAnsiConsole ansiConsole, | ||
| IAuxiliaryBackchannelMonitor backchannelMonitor, | ||
| ILogger<AppHostLauncher> logger, | ||
| TimeProvider? timeProvider = null) |
There was a problem hiding this comment.
Is there a reason this is optional?
| /// </summary> | ||
| internal static readonly Option<OutputFormat?> s_formatOption = new("--format") | ||
| { | ||
| Description = RunCommandStrings.JsonArgumentDescription |
There was a problem hiding this comment.
I'm adding a CommonCommandStrings in a PR that should merge soon. These resource strings should move there when available rather than stay in Run.
| // Avoid interactive project prompts in JSON mode to keep stdout parseable. | ||
| var multipleAppHostBehavior = format == OutputFormat.Json | ||
| ? MultipleAppHostProjectsFoundBehavior.Throw | ||
| : MultipleAppHostProjectsFoundBehavior.Prompt; |
There was a problem hiding this comment.
Is this comment still true? Now all output should go to stderr with ConsoleOutput.Error. JSON should still be parsable. However, I don't know whether it makes sense to allow prompts or throw for other reasons.
|
|
||
| if (effectiveAppHostFile is null) | ||
| { | ||
| return ExitCodeConstants.FailedToFindProject; |
There was a problem hiding this comment.
Does the calling code write the error message to console?
Edit: I see in later code that this method writes error messages. Double check something is displayed in this scenario.
|
|
||
| if (runningInstanceDetectionEnabled && existingSockets.Length > 0) | ||
| { | ||
| logger.LogDebug("Found {Count} running instance(s) for this AppHost, stopping them first", existingSockets.Length); |
There was a problem hiding this comment.
nit
| logger.LogDebug("Found {Count} running instance(s) for this AppHost, stopping them first", existingSockets.Length); | |
| logger.LogDebug("Found {Count} running instance(s) for this AppHost, stopping them first.", existingSockets.Length); |
| "--non-interactive", | ||
| "--project", | ||
| effectiveAppHostFile.FullName, | ||
| "--log-file", |
There was a problem hiding this comment.
Can these option names be changed to use Name value from options. That way if they change, e.g. --project to --apphost, then this stays in sync.
| // Pass through run-specific options | ||
| if (isolated) | ||
| { | ||
| args.Add("--isolated"); |
| var childExitedEarly = false; | ||
| var childExitCode = 0; | ||
|
|
||
| async Task<IAppHostAuxiliaryBackchannel?> StartAndWaitForBackchannelAsync() |
There was a problem hiding this comment.
LaunchDetachedAsync is big. Could this local function be promoted to a normal method to reduce its size?
| } | ||
|
|
||
| // Build the arguments for the child CLI process | ||
| var childLogFile = GenerateChildLogFilePath(executionContext.LogsDirectory.FullName, _timeProvider); |
There was a problem hiding this comment.
Could logic for building the path and arguments for child CLI process be moved to a separate method to reduce this ones size?
| ResourceCommandStrings.ScanningForRunningAppHosts, | ||
| ResourceCommandStrings.SelectAppHost, | ||
| ResourceCommandStrings.NoInScopeAppHostsShowingAll, | ||
| ResourceCommandStrings.NoRunningAppHostsFound, |
There was a problem hiding this comment.
Will need to update these to common strings once my PR is in.
There was a problem hiding this comment.
In: #14661. See examples of other commands resolving connection.
9d3da02 to
6930f6c
Compare
- Add detached AppHost launch to 'aspire start' when no resource specified - Share detached launch behavior between start and run via AppHostLauncher - Register --no-build option on StartCommand and forward to child process - Restore JSON-safe detached output (human-readable to stderr for --format json) - Restore detached child diagnostics (--log-file generation and error surfacing) - Forward --no-build from 'aspire run --detach' to the detached child process Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
6930f6c to
88693a3
Compare
| ResourceCommandStrings.NoInScopeAppHostsShowingAll, | ||
| ResourceCommandStrings.NoRunningAppHostsFound, | ||
| SharedCommandStrings.ScanningForRunningAppHosts, | ||
| SharedCommandStrings.SelectAppHost, |
There was a problem hiding this comment.
Needs to be formated with a value, e.g.
string.Format(CultureInfo.CurrentCulture, SharedCommandStrings.SelectAppHost, ResourceCommandStrings.SelectAppHostAction)
e4642a4 to
63b23d8
Compare
|
|
||
| if (!result.Success) | ||
| { | ||
| _interactionService.DisplayError(result.ErrorMessage ?? SharedCommandStrings.AppHostNotRunning); |
There was a problem hiding this comment.
There is always a value when !Success
| _interactionService.DisplayError(result.ErrorMessage ?? SharedCommandStrings.AppHostNotRunning); | |
| _interactionService.DisplayError(result.ErrorMessage); |
63b23d8 to
2262427
Compare
| internal static void AddLaunchOptions(Command command) | ||
| { | ||
| command.Options.Add(s_formatOption); | ||
| command.Options.Add(s_isolatedOption); |
There was a problem hiding this comment.
Should s_projectOption also be here and not declared/added in the two commands?
- Make TimeProvider required (registered in DI as TimeProvider.System) - Add period to log message (nit) - Use option Name properties instead of hardcoded strings for --project/--isolated - Extract BuildChildProcessArgs, StopExistingInstancesAsync, HandleLaunchFailure, DisplayLaunchResultAsync, and LaunchAndWaitForBackchannelAsync as separate methods - Add s_projectOption to AppHostLauncher for shared use - Display error when project not found (item #4) - Fix string references: use SharedCommandStrings for relocated strings - Fix async void to async Task on DisplayLaunchResultAsync Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2262427 to
45db3d5
Compare
|
Related: The skill should probably be updated to use |
* Add aspire start shortcut for detached AppHost launch - Add detached AppHost launch to 'aspire start' when no resource specified - Share detached launch behavior between start and run via AppHostLauncher - Register --no-build option on StartCommand and forward to child process - Restore JSON-safe detached output (human-readable to stderr for --format json) - Restore detached child diagnostics (--log-file generation and error surfacing) - Forward --no-build from 'aspire run --detach' to the detached child process Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback: refactor AppHostLauncher, fix string references - Make TimeProvider required (registered in DI as TimeProvider.System) - Add period to log message (nit) - Use option Name properties instead of hardcoded strings for --project/--isolated - Extract BuildChildProcessArgs, StopExistingInstancesAsync, HandleLaunchFailure, DisplayLaunchResultAsync, and LaunchAndWaitForBackchannelAsync as separate methods - Add s_projectOption to AppHostLauncher for shared use - Display error when project not found (item #4) - Fix string references: use SharedCommandStrings for relocated strings - Fix async void to async Task on DisplayLaunchResultAsync Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Description
This PR adds a shortcut to run detached AppHost startup via
aspire start(no resource argument), equivalent toaspire run --detach, and fixes detached-launch forwarding/regression issues.Summary of changes
aspire startwhen no resource name is provided.startandrunthroughAppHostLauncher.--format json--log-file--no-buildfromaspire run --detachto the detached child process.RunCommand.GetDetachedFailureMessage(childExitCode)for clearer early-exit errors.create-prskill update used to standardize template-filled PR creation/editing in this workflow.Motivation and context
The detached launch refactor introduced argument/output regressions and less specific failure messaging. These changes restore expected behavior and provide a clear
aspire startshortcut for the detached AppHost launch flow.Dependencies: None.
Validation
dotnet test tests/Aspire.Cli.Tests/Aspire.Cli.Tests.csproj -- --filter-class "*.RunCommandTests" --filter-class "*.StartCommandTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"Fixes # (issue)
No linked issue.
Checklist
<remarks />and<code />elements on your triple slash comments?aspire.devissue: