Detect CLI at default install paths when not on PATH#14545
Detect CLI at default install paths when not on PATH#14545adamint merged 1 commit intodotnet:mainfrom
Conversation
Check default installation directories (~/.aspire/bin, ~/.dotnet/tools) when the Aspire CLI is not found on the system PATH. If found at a default location, the VS Code setting is auto-updated. If later found on PATH, the setting is cleared. Resolution order: configured custom path > system PATH > default install paths. Fixes dotnet#14235
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 14545Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 14545" |
There was a problem hiding this comment.
Pull request overview
This PR improves Aspire VS Code extension reliability when the Aspire CLI is installed but not on PATH, by adding centralized CLI path resolution that checks user settings, PATH, and default install locations, and updates the extension to use the resolved path across commands/debugging.
Changes:
- Added
resolveCliPath()logic to detect the CLI onPATHor at default install locations and (optionally) update/clear the VS Code setting. - Updated terminal commands, spawned CLI processes, and debug flows to use the resolved CLI path (async path resolution).
- Added unit tests and localization strings for the new behavior.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| extension/src/utils/workspace.ts | Uses centralized CLI resolution for availability checks; uses resolved CLI path for get-apphosts. |
| extension/src/utils/configInfoProvider.ts | Uses resolved CLI path for aspire config info --json spawn. |
| extension/src/utils/cliPath.ts | New module implementing default path detection, PATH probing, and settings update logic. |
| extension/src/utils/AspireTerminalProvider.ts | Makes CLI path resolution async and uses resolveCliPath() for terminal command construction. |
| extension/src/test/cliPath.test.ts | Adds unit tests for CLI path resolution behavior and settings update/clear behavior. |
| extension/src/test/aspireTerminalProvider.test.ts | Updates tests to stub resolveCliPath() and validate async behavior. |
| extension/src/loc/strings.ts | Adds localized string for “CLI found at default path” info message. |
| extension/src/extension.ts | Updates command execution flow and debug config provider construction to match new CLI resolution. |
| extension/src/debugger/AspireDebugSession.ts | Updates debug session CLI spawning to await async CLI path resolution. |
| extension/src/debugger/AspireDebugConfigurationProvider.ts | Uses new CLI availability check signature (no terminal provider dependency). |
| extension/src/commands/update.ts | Awaits async terminal command dispatch. |
| extension/src/commands/publish.ts | Awaits async terminal command dispatch. |
| extension/src/commands/new.ts | Awaits async terminal command dispatch. |
| extension/src/commands/init.ts | Awaits async terminal command dispatch. |
| extension/src/commands/deploy.ts | Awaits async terminal command dispatch. |
| extension/src/commands/add.ts | Awaits async terminal command dispatch. |
| extension/package.nls.json | Adds NLS entry for new “CLI found at default path” string. |
| extension/loc/xlf/aspire-vscode.xlf | Adds XLF entry for new “CLI found at default path” string. |
| const configuredPath = deps.getConfiguredPath(); | ||
| const defaultPaths = deps.getDefaultPaths(); | ||
|
|
||
| // 1. Check if user has configured a custom path (not one of the defaults) | ||
| if (configuredPath && !defaultPaths.includes(configuredPath)) { | ||
| const isValid = await deps.tryExecute(configuredPath); |
There was a problem hiding this comment.
resolveCliPath() uses the configured setting value verbatim. If a user pastes a quoted path (e.g. "C:\Program Files\...\aspire.exe"), tryExecuteCli/spawn will treat the quotes as part of the filename and fail; on Windows it can also lead to double-quoting in terminal commands. Consider normalizing the configured value by trimming and stripping a single pair of surrounding quotes (both ' and ") before comparisons/execution, and use the normalized value for defaultPaths.includes(...) checks.
| // Show informational message if CLI was found at default path (not on PATH) | ||
| if (result.source === 'default-install') { | ||
| extensionLogOutputChannel.info(`Using Aspire CLI from default install location: ${result.cliPath}`); | ||
| vscode.window.showInformationMessage(cliFoundAtDefaultPath(result.cliPath)); | ||
| } |
There was a problem hiding this comment.
checkCliAvailableOrRedirect() shows an information message every time it resolves the CLI from a default install location. Since this check runs on every command invocation, users will see repeated toasts even after the setting has already been updated. Consider only showing the message when the extension actually changes aspireCliExecutablePath (first detection) or otherwise de-dup/throttle it (e.g., remember that the message was shown this session).
| void this.spawnRunCommand(args, appHostPath, noDebug); | ||
| } | ||
| else { | ||
| this.sendMessageWithEmoji("📂", launchingWithAppHost(appHostPath)); | ||
|
|
||
| const workspaceFolder = path.dirname(appHostPath); | ||
| args.push('--project', appHostPath); | ||
| this.spawnRunCommand(args, workspaceFolder, noDebug); | ||
| void this.spawnRunCommand(args, workspaceFolder, noDebug); | ||
| } |
There was a problem hiding this comment.
spawnRunCommand is now async and is invoked with void ... (fire-and-forget). If getAspireCliExecutablePath()/resolveCliPath() throws (e.g., configuration update failure), this becomes an unhandled promise rejection. Please attach a .catch(...) (and surface/log an error) or wrap the body of spawnRunCommand in a try/catch and handle failures explicitly.
…er (#14590) * Add a script for startup performance measurement (#14345) * Add startup perf collection script * Analyze trace more efficiently * Increase pause between iterations * Fix TraceAnalyzer * Add startup-perf skill * Add backmerge release workflow to automate merging changes from release/13.2 to main (#14453) * Add backmerge release workflow to automate merging changes from release/13.2 to main * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Apply more fixes and use dotnet's action --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Bump Aspire branding from 13.2 to 13.3 (#14456) * Initial plan * Bump Aspire branding from 13.2 to 13.3 Co-authored-by: joperezr <13854455+joperezr@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: joperezr <13854455+joperezr@users.noreply.github.com> * Update Azure.Core to latest version - lift all runtime dependencies to latest (#14361) * Update to Azure.Core 1.51.1 Use latest versions for all dotnet/runtime nuget packages. This simplifies our dependency management. Remove ForceLatestDotnetVersions property from multiple project files * Update AzureDeployerTests to use WaitForShutdown instead of StopAsync There is a timing issue when using Start/Stop since the background pipeline might still be running and it cancels the pipeline before it can complete. * Fix AuxiliaryBackchannelTests by adding a Task that completes when the AuxiliaryBackchannelService is listening and ready for connections. * Remove double registration of AuxiliaryBackchannelService as an IHostedService. * Fix ResourceLoggerForwarderServiceTests to ensure the ResourceLoggerForwarderService has started before signalling the stopping token. * Update Arcade to latest version from the .NET 10 Eng channel (#13556) Co-authored-by: Jose Perez Rodriguez <joperezr@microsoft.com> * Refactor backmerge PR creation to update existing PRs and streamline body formatting (#14476) * [main] Fix transitive Azure role assignments through WaitFor dependencies (#14478) * Initial plan * Fix transitive Azure role assignments through WaitFor dependencies Remove CollectAnnotationDependencies calls from CollectDependenciesFromValue to prevent WaitFor/parent/connection-string-redirect annotations from referenced resources being included as direct dependencies of the caller. Add tests verifying: - DirectOnly mode excludes WaitFor deps from referenced resources - WaitFor doesn't create transitive role assignments in Azure publish Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com> * Remove auto-merge step from backmerge workflow (#14481) * Remove auto-merge step from backmerge workflow * Update PR body to request merge commit instead of auto-merge * Add agentic workflow daily-repo-status (#14498) * [Automated] Backmerge release/13.2 to main (#14536) * Fix Windows pipeline image to use windows.vs2022.amd64.open (#14492) * Fix Windows pipeline image to use windows.vs2022.amd64.open * Use windows.vs2026preview.scout.amd64 for public pipeline Windows pool Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add Azure portal link for Resource Group in deploy pipeline summary (#14434) * Add Azure portal link for Resource Group in pipeline summary When printing the Resource Group in the pipeline summary of `aspire deploy`, include a clickable link to the Azure portal resource group page. The link uses the format: https://portal.azure.com/#@{tenantId}/resource/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/overview Changes: - AzureEnvironmentResource.AddToPipelineSummary: construct markdown link for resource group - ConsoleActivityLogger.FormatPipelineSummaryKvp: convert markdown to Spectre markup for clickable links - Add ConsoleActivityLoggerTests for the new markdown rendering behavior Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com> * Clean up the code * Fix tests * More test fixups * Refactor code * Update src/Aspire.Cli/Utils/MarkdownToSpectreConverter.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Add test for color-enabled non-interactive rendering path Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com> * fix test --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com> Co-authored-by: Eric Erhardt <eric.erhardt@microsoft.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Jose Perez Rodriguez <joperezr@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com> Co-authored-by: Eric Erhardt <eric.erhardt@microsoft.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * [Automated] Update AI Foundry Models (#14541) Co-authored-by: sebastienros <sebastienros@users.noreply.github.com> * Detect CLI at default install paths when not on PATH (#14545) Check default installation directories (~/.aspire/bin, ~/.dotnet/tools) when the Aspire CLI is not found on the system PATH. If found at a default location, the VS Code setting is auto-updated. If later found on PATH, the setting is cleared. Resolution order: configured custom path > system PATH > default install paths. Fixes #14235 * [automated] Unquarantine stable tests with 25+ days zero failures (#14531) * Initial plan * [automated] Unquarantine stable tests - Unquarantined: DeployCommandIncludesDeployFlagInArguments - Unquarantined: GetAppHostsCommand_WithMultipleProjects_ReturnsSuccessWithAllCandidates - Unquarantined: GetAppHostsCommand_WithSingleProject_ReturnsSuccessWithValidJson - Unquarantined: PushImageToRegistry_WithRemoteRegistry_PushesImage - Unquarantined: ProcessParametersStep_ValidatesBehavior - Unquarantined: WithHttpCommand_EnablesCommandOnceResourceIsRunning These tests are being unquarantined as they have had 25+ days of quarantined run data with zero failures. Co-authored-by: radical <1472+radical@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: radical <1472+radical@users.noreply.github.com> * Partially fix quarantined test: Update stale snapshot for DeployAsync_WithMultipleComputeEnvironments_Works (#14551) * Initial plan * Update snapshot for DeployAsync_WithMultipleComputeEnvironments_Works test Co-authored-by: radical <1472+radical@users.noreply.github.com> * Remove quarantine attribute from DeployAsync_WithMultipleComputeEnvironments_Works test Co-authored-by: radical <1472+radical@users.noreply.github.com> * Restore quarantine attribute - step="deploy" case still fails Co-authored-by: radical <1472+radical@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: radical <1472+radical@users.noreply.github.com> * Update daily report to 13.2 milestone burndown (#14563) * Update daily report to 13.2 milestone burndown Refocus the daily-repo-status agentic workflow to serve as a 13.2 release burndown report: - Track 13.2 milestone issues closed/opened in the last 24 hours - Highlight new bugs added to the milestone - Summarize PRs merged to release/13.2 branch - List PRs targeting release/13.2 awaiting review - Surface relevant 13.2 discussions - Generate a Mermaid xychart burndown using cache-memory snapshots - Keep general triage queue as a brief secondary section - Schedule daily around 9am, auto-close older report issues Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback: clarify cache schema and queries - Exclude PRs from milestone counts (issues-only filter) - Specify exact JSON schema for cache-memory burndown snapshots - Add dedup, sort, and trim-to-7 logic for cache entries - Simplify 'new issues' query to opened-in-last-24h with milestone Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Update Aspire.Hosting.Kubernetes.csproj * Initialize _kubernetesComponents with ResourceNameComparer * Update KubernetesPublisherTests.cs * Update Aspire.Hosting.Kubernetes.csproj * Adds snapshots * Adds Chart.yaml to snapshot --------- Co-authored-by: Karol Zadora-Przylecki <karolz@microsoft.com> Co-authored-by: Jose Perez Rodriguez <joperezr@microsoft.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: joperezr <13854455+joperezr@users.noreply.github.com> Co-authored-by: Eric Erhardt <eric.erhardt@microsoft.com> Co-authored-by: dotnet-maestro[bot] <42748379+dotnet-maestro[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com> Co-authored-by: David Negstad <50252651+danegsta@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Mitch Denny <midenn@microsoft.com> Co-authored-by: sebastienros <sebastienros@users.noreply.github.com> Co-authored-by: Adam Ratzman <adam@adamratzman.com> Co-authored-by: radical <1472+radical@users.noreply.github.com>
Check default installation directories (~/.aspire/bin, ~/.dotnet/tools) when the Aspire CLI is not found on the system PATH. If found at a default location, the VS Code setting is auto-updated. If later found on PATH, the setting is cleared. Resolution order: configured custom path > system PATH > default install paths. Fixes #14235
Check default installation directories (~/.aspire/bin, ~/.dotnet/tools) when the Aspire CLI is not found on the system PATH. If found at a default location, the VS Code setting is auto-updated. If later found on PATH, the setting is cleared. Resolution order: configured custom path > system PATH > default install paths. Fixes dotnet#14235
* Detect CLI at default install paths when not on PATH (#14545) Check default installation directories (~/.aspire/bin, ~/.dotnet/tools) when the Aspire CLI is not found on the system PATH. If found at a default location, the VS Code setting is auto-updated. If later found on PATH, the setting is cleared. Resolution order: configured custom path > system PATH > default install paths. Fixes #14235 * Fix JSON-RPC error on disconnect and auto-restart Aspire debug session on AppHost restart (#14548) * Fix JSON-RPC error on disconnect and auto-restart debug session on AppHost restart * Update extension/src/debugger/AspireDebugSession.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update extension/src/debugger/AspireDebugSession.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Description
When the Aspire CLI is not available on the system PATH, the VS Code extension now checks default installation directories before prompting the user to install. This covers the common scenario where the CLI is installed but its directory hasn't been added to PATH (e.g., after a fresh bundle install or global tool install without restarting the terminal).
Resolution order:
aspirecommand)~/.aspire/bin/aspire(bundle install — recommended)~/.dotnet/tools/aspire(.NET global tool)Behavior:
aspire.aspireCliExecutablePathVS Code settingKey changes:
cliPath.tsmodule with centralized CLI path resolution logic (resolveCliPath())getAspireCliExecutablePath()is now async and delegates toresolveCliPath()checkCliAvailableOrRedirect()usesresolveCliPath()instead of directexecFileCliPathDependencies) for testabilityFixes #14235
Checklist