Cherry-pick VS Code extension fixes from main to release/13.2#14846
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
…n on AppHost restart (dotnet#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>
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 14846Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 14846" |
There was a problem hiding this comment.
Pull request overview
Cherry-picks two VS Code extension fixes into release/13.2 by centralizing Aspire CLI path resolution (including default install locations) and improving debug-session lifecycle behavior (disconnect handling + auto-restart on AppHost restart).
Changes:
- Add
cliPath.tswithresolveCliPath()to locate the Aspire CLI (configured path → PATH → default install paths) and optionally update VS Code settings. - Update terminal/command/debug flows to use async CLI path resolution, including new localization for “CLI found at default path”.
- Improve debug session disposal behavior and restart Aspire debug session when the AppHost terminates unexpectedly.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| extension/src/utils/workspace.ts | Switch CLI availability check to centralized resolver and add default-path UX messaging. |
| extension/src/utils/configInfoProvider.ts | Use resolved CLI path for aspire config info --json. |
| extension/src/utils/cliPath.ts | New module implementing CLI path resolution and settings updates, plus testable dependency injection. |
| extension/src/utils/AspireTerminalProvider.ts | Make CLI path retrieval async via resolveCliPath(); terminal command sender awaits path resolution. |
| extension/src/test/cliPath.test.ts | Unit tests covering resolution order and settings update/clear behavior. |
| extension/src/test/aspireTerminalProvider.test.ts | Update tests to stub resolveCliPath() rather than stubbing VS Code configuration. |
| extension/src/loc/strings.ts | Add localized string for “CLI found at default path”. |
| extension/src/extension.ts | Update CLI availability checks + debug config provider construction. |
| extension/src/debugger/AspireDebugSession.ts | Guard against double-dispose, catch stopCli errors, and restart Aspire session when AppHost terminates unexpectedly. |
| extension/src/debugger/AspireDebugConfigurationProvider.ts | Remove terminal-provider dependency; rely on centralized CLI check. |
| extension/src/commands/add.ts | Await async terminal command dispatch. |
| extension/src/commands/deploy.ts | Await async terminal command dispatch. |
| extension/src/commands/init.ts | Await async terminal command dispatch. |
| extension/src/commands/new.ts | Await async terminal command dispatch. |
| extension/src/commands/publish.ts | Await async terminal command dispatch. |
| extension/src/commands/update.ts | Await async terminal command dispatch. |
| extension/package.nls.json | Add string entry for default-path CLI message. |
| extension/loc/xlf/aspire-vscode.xlf | Add XLF source string entry for default-path CLI message. |
Comments suppressed due to low confidence (1)
extension/src/extension.ts:123
- tryExecuteCommand() calls checkCliAvailableOrRedirect() (which runs resolveCliPath and executes
aspire --version), and the invoked command then resolves the CLI path again via terminalProvider.getAspireCliExecutablePath(). This doubles the CLI resolution/exec overhead on every command. Consider returning and reusing the resolved cliPath from checkCliAvailableOrRedirect (or caching resolveCliPath for the duration of a command invocation) so resolution is performed only once per command.
if (!cliCheckExcludedCommands.includes(commandName)) {
const result = await checkCliAvailableOrRedirect();
if (!result.available) {
return;
}
}
await command(terminalProvider);
| * Gets the VS Code configuration setting for the Aspire CLI path. | ||
| */ | ||
| export function getConfiguredCliPath(): string { | ||
| return vscode.workspace.getConfiguration('aspire').get<string>('aspireCliExecutablePath', '').trim(); |
There was a problem hiding this comment.
getConfiguredCliPath() only trims whitespace; it no longer normalizes common user inputs like surrounding single/double quotes (the previous CLI availability check stripped them). If a user sets aspireCliExecutablePath to something like "C:\Program Files\Aspire\aspire.exe" (including quotes), resolveCliPath will treat it as invalid and repeatedly fall back to PATH/defaults while leaving the bad setting in place. Consider stripping one pair of surrounding quotes here (or in resolveCliPath) and optionally persisting the sanitized value back to settings.
| return vscode.workspace.getConfiguration('aspire').get<string>('aspireCliExecutablePath', '').trim(); | |
| const rawPath = vscode.workspace.getConfiguration('aspire').get<string>('aspireCliExecutablePath', '').trim(); | |
| // Normalize common user input: strip one pair of surrounding quotes if present. | |
| if (rawPath.length >= 2) { | |
| const firstChar = rawPath[0]; | |
| const lastChar = rawPath[rawPath.length - 1]; | |
| if ((firstChar === '"' && lastChar === '"') || (firstChar === '\'' && lastChar === '\'')) { | |
| return rawPath.substring(1, rawPath.length - 1); | |
| } | |
| } | |
| return rawPath; |
| if (result.available) { | ||
| // 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 path. Since this check runs on every command/debug start, users without Aspire on PATH will likely get repeated notifications. Consider showing this message only when the setting is first auto-updated (configuredPath was empty/different) or gating it to once per session.
| if (isDirectory(appHostPath)) { | ||
| this.sendMessageWithEmoji("📁", launchingWithDirectory(appHostPath)); | ||
|
|
||
| this.spawnRunCommand(args, appHostPath, noDebug); | ||
| void this.spawnRunCommand(args, appHostPath, noDebug); | ||
| } |
There was a problem hiding this comment.
handleMessage() starts spawnRunCommand() with void and no error handling. Since spawnRunCommand is now async (awaiting CLI path resolution), a rejection (e.g., config update failure during resolveCliPath) would become an unhandled promise rejection. Consider wrapping spawnRunCommand in a try/catch internally, or attaching a .catch(...) when calling it to log and surface a user-friendly error.
| 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.
Same as above: spawnRunCommand() is invoked with void and no .catch(...) in the file-path case, which can surface as an unhandled promise rejection if CLI path resolution or spawn setup fails. Consider handling the returned promise (or making spawnRunCommand non-throwing).
Description
Cherry-picks VS Code extension commits from
mainthat are missing inrelease/13.2:These are the only extension-touching commits in
mainnot already inrelease/13.2(excluding PRs being separately retargeted).Checklist