Skip to content

Show debugger setup hints for missing VS Code extensions - #19131

Merged
Adam Ratzman (adamint) merged 52 commits into
microsoft:mainfrom
adamint:adamint/issue17845-missing-debugger-install-hint
Aug 22, 2026
Merged

Show debugger setup hints for missing VS Code extensions#19131
Adam Ratzman (adamint) merged 52 commits into
microsoft:mainfrom
adamint:adamint/issue17845-missing-debugger-install-hint

Conversation

@adamint

@adamint Adam Ratzman (adamint) commented Aug 7, 2026

Copy link
Copy Markdown
Member

Description

Shows debugger setup guidance when a running resource supports debugging but its required VS Code extension is unavailable.

image
  • Aspire.Hosting publishes resource.launchConfigurationType in resource snapshots.
  • The VS Code extension supports Python, Go, Bun, Rust, Java, .NET MAUI, and Azure Functions resources.
  • A once-per-session warning offers Set Up and Don't show again, while a CodeLens keeps the setup action available in the AppHost source.
  • Java requires redhat.java and vscjava.vscode-java-debug; Azure Functions requires the C# and Azure Functions extensions. Only missing requirements are installed.
  • Rust preserves an installed platform adapter and otherwise recommends CodeLLDB, including on Windows because it supports MSVC and GNU targets.
  • Fresh installs wait for every required extension to register, and disabled extensions are surfaced without incorrectly reporting success.
  • Extension enablement changes refresh the available hints. Concurrent installs and cancellation do not produce duplicate or erroneous notifications.
  • Notification suppression is stored by logical debugger type.

Older Hosting versions omit resource.launchConfigurationType; the extension treats the missing property as unsupported and continues without showing a hint.

The E2E harness also isolates NuGet packages per run and configures local package sources for workspace and external AppHosts so the debugger scenario consistently tests the current repository build. Workspace exclusions keep Pyright from scanning generated and test artifacts.

Fixes #17845

Validation

  • Full extension suite: 2,426 passing, 4 pending
  • Focused Hosting resource-snapshot test: 1 passing
  • Extension Host debugger edge-case shard: 6 passing
  • Final PR CI: 379 checks passed or skipped, 0 failures

Checklist

  • Feature complete
  • Tests cover the changed behavior
  • No public API added
  • No new security assumptions

Copilot AI balanced review requested due to automatic review settings August 7, 2026 14:29
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

🚀 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 -- 19131

Or

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds missing-debugger install hints for Python, Go, and Bun resources in the VS Code extension.

Changes:

  • Adds install notifications, suppression, failure handling, and restart guidance.
  • Adds contextual debugger-install CodeLens actions.
  • Updates Python detection to use ms-python.debugpy and adds unit/E2E coverage.
Show a summary per file
File Description
extension/src/capabilities.ts Detects standalone debugpy.
extension/src/debugger/debuggerInstallHints.ts Implements hint and installation service.
extension/src/debugger/languages/python.ts Uses the debugpy extension ID.
extension/src/editor/AspireCodeLensProvider.ts Adds install CodeLens actions.
extension/src/editor/DebuggerInstallHintWatcher.ts Detects running debuggable resources.
extension/src/extension.ts Registers and wires the feature.
extension/src/loc/strings.ts Adds localized UI strings.
extension/package.nls.json Registers localization resources.
extension/loc/xlf/aspire-vscode.xlf Updates the localization catalog.
extension/src/test/aspireCodeLensProvider.test.ts Tests debugger CodeLens behavior.
extension/src/test/debuggerInstallHints.test.ts Tests hint service behavior.
extension/src/test/debuggerInstallHintWatcher.test.ts Tests resource detection and parsing.
extension/src/test/pythonDebugger.test.ts Tests debugpy capability detection.
extension/src/test/strings.test.ts Tests localization registration.
extension/src/test-e2e/debuggerInstallHint.e2e.test.ts Covers notification and CodeLens UX.
extension/src/test-e2e/helpers/extester.ts Extends notification test typings.
extension/src/test-e2e/helpers/vscode.ts Adds notification-action inspection.

Review details

  • Files reviewed: 17/17 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread extension/src/loc/strings.ts Outdated
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Copilot AI review requested due to automatic review settings August 7, 2026 15:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

Suppressed comments (1)

extension/src/test-e2e/debuggerInstallHint.e2e.test.ts:61

  • This E2E test still waits for the old CodeLens tooltip text, but the notification now emits Debug 1 Aspire resource by installing the Python debugger extension.. As written, waitForNotificationMessage will time out even when the feature works. Update the expected notification text to the new singular toast.
            'Install the Python debugger extension to debug this Aspire resource.',
  • Files reviewed: 17/17 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

Files not reviewed (1)
  • src/Aspire.Hosting/Resources/MessageStrings.Designer.cs: Generated file
Suppressed comments (3)

extension/src/debugger/debuggerInstallHints.ts:55

  • This assumes every debugger entry has exactly one install prerequisite, but azure-functions is only usable when both the C# and Azure Functions extensions are installed (getResourceDebuggerExtensions() checks both), while its entry exposes only ms-dotnettools.csharp. After this hint installs C#, the resource still cannot debug and no hint is offered for the missing Azure Functions extension. Limit install hints to the three supported single-extension types in this PR (Python, Go, and Bun), or model all prerequisites explicitly.
for (const debuggerExtension of getAllResourceDebuggerExtensions()) {
    if (!debuggerExtension.extensionId) {
        // A null extensionId means the debug adapter ships with VS Code, so there is nothing to install.
        continue;
    }

extension/src/debugger/debuggerInstallHints.ts:115

  • The current implementation reintroduces the previously reported toast bug: it fires on the first matching resource and deliberately omits the count, while the PR description promises a single cross-AppHost notification with singular/plural Debug {N} Aspire resource(s)... wording. Because _notificationsShownThisSession is set immediately, later resources can never update that first snapshot. Aggregate all matching running resources before showing the toast and pass the count to separate localized singular/plural strings.
     * The toast is coalesced to one per extension id per session, so it deliberately says nothing about
     * how many resources are affected: that number is a snapshot that goes stale as soon as another
     * resource starts, and the actionable fact is that the debug adapter is missing.

src/Aspire.Hosting.AppHost/build/Aspire.Hosting.AppHost.in.targets:88

  • This adds two MSBuild probes for every Aspire project resource on AppHost builds, but the install-hint implementation only consumes resource.launchConfigurationType; no production code in this PR reads the newly published project.assemblyName. The public metadata contract, dashboard property, CLI pass-through test, localization, and build cost are also absent from the PR description. Remove this unrelated assembly-name feature from this PR, or add the missing consumer and document why it is required here.
  <Target Name="_GetAspireProjectResourceAssemblyNames"
          DependsOnTargets="_CreateAspireProjectResources;PrepareProjectReferences"
          Condition="'$(SkipAspireProjectResourceAssemblyName)' != 'true'">
  • Files reviewed: 50/51 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings August 7, 2026 18:24
@adamint
Adam Ratzman (adamint) force-pushed the adamint/issue17845-missing-debugger-install-hint branch from 69bfc0a to 700b025 Compare August 7, 2026 18:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

Files not reviewed (1)
  • src/Aspire.Hosting/Resources/MessageStrings.Designer.cs: Generated file
Suppressed comments (3)

extension/src/debugger/debuggerInstallHints.ts:62

  • This assumes extensionId is the debugger's complete prerequisite set, but Azure Functions requires both C# and ms-azuretools.vscode-azurefunctions (getResourceDebuggerExtensions() checks both, and its launch callback calls the Functions extension API). With C# installed and the Functions extension missing, this map reports no missing debugger; with both missing, installing C# produces restart guidance even though debugging still cannot work. Model all required extensions, or exclude compound adapters from these hints.
    debuggerInstallHintsByLaunchConfigurationType.set(debuggerExtension.resourceType, {
        // The display name describes the extension, not the language, because several launch
        // configuration types can share one extension ('project' and 'azure-functions' both need the C#
        // extension) and the toast is coalesced per extension id.
        debuggerName: debuggerExtension.extensionDisplayName ?? debuggerExtension.extensionId,
        extensionId: debuggerExtension.extensionId,

src/Aspire.Hosting.AppHost/build/Aspire.Hosting.AppHost.in.targets:166

  • %(TargetPath.Filename) is $(TargetName), not necessarily $(AssemblyName). A project can explicitly set those properties to different values, in which case this publishes the output target name through IProjectMetadata.AssemblyName and project.assemblyName, violating the new contract. Either evaluate the actual AssemblyName property or rename the API/wire property to describe the target/output name.
    <PropertyGroup>
      <_AspireResolvedProjectFile>%(_AspireProjectResourceTargetPath.MSBuildSourceProjectFile)</_AspireResolvedProjectFile>
      <_AspireResolvedProjectFile Condition="'$(_AspireResolvedProjectFile)' != ''">$([System.IO.Path]::GetFullPath('$(_AspireResolvedProjectFile)'))</_AspireResolvedProjectFile>
      <_AspireResolvedAssemblyName>%(_AspireProjectResourceTargetPath.Filename)</_AspireResolvedAssemblyName>

extension/src/debugger/debuggerInstallHints.ts:171

  • If persisting “Don't Show Again” fails, this rejection is caught only by notifyMissingDebuggers and written to the output channel. The user receives no failure message, while _notificationsShownThisSession still prevents another prompt until restart, so the suppression action silently did nothing. Handle this failure explicitly, restore retryability, and show a localized error.
        if (selected === dontShowAgainLabel) {
            await this._globalState.update(`${notificationSuppressedKeyPrefix}${hint.extensionId}`, true);
  • Files reviewed: 50/51 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Copilot AI review requested due to automatic review settings August 7, 2026 20:26
@adamint
Adam Ratzman (adamint) force-pushed the adamint/issue17845-missing-debugger-install-hint branch from 700b025 to 8bf3cb1 Compare August 7, 2026 20:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

Files not reviewed (1)
  • src/Aspire.Hosting/Resources/MessageStrings.Designer.cs: Generated file
Suppressed comments (3)

extension/src/debugger/debuggerInstallHints.ts:60

  • This assumes each debugger has exactly one prerequisite, but Azure Functions is only registered when both ms-dotnettools.csharp and ms-azuretools.vscode-azurefunctions are installed (debuggerExtensions.ts:126-131). Because its entry records only the C# extension, a host with C# installed but the Azure Functions extension missing gets no hint; with neither installed, the one-click action still leaves debugging unavailable. Restrict install hints to the Bun/Python/Go adapters described by this PR, or model and verify every required extension for a launch type.
    debuggerInstallHintsByLaunchConfigurationType.set(debuggerExtension.resourceType, {
        // The display name describes the extension, not the language, because several launch
        // configuration types can share one extension ('project' and 'azure-functions' both need the C#
        // extension) and the toast is coalesced per extension id.

extension/src/extension.ts:460

  • dataRepository.appHosts is not all known AppHosts: in workspace view, its getter filters to workspace AppHosts (AppHostDataRepository.ts:329-333). As a result, a running debuggable resource in any other AppHost is omitted from this scan and never produces the promised install hint while the user remains in workspace view, despite this helper claiming to cover all AppHosts. Use an unfiltered repository accessor for notification discovery (while retaining the filtered accessor for UI rendering).
function getAllKnownResources(dataRepository: AppHostDataRepository): ResourceJson[] {
  const resources: ResourceJson[] = [...dataRepository.workspaceResources];
  for (const appHost of dataRepository.appHosts) {
    if (appHost.resources) {
      resources.push(...appHost.resources);

src/Aspire.Hosting.AppHost/build/Aspire.Hosting.AppHost.in.targets:98

  • This introduces two MSBuild probes for every Aspire project reference, but the install-hint implementation only consumes resource.launchConfigurationType; the new project.assemblyName value has no production reader in this change (only publication/display and pass-through tests). That creates an unrelated build-time cost and public snapshot/API contract not described by this PR. Remove this assembly-name pipeline from this PR, or split it into a separately justified change with its consumer and performance rationale.
    <MSBuild Projects="@(_AspirePreparedProjectResource)"
             Targets="GetTargetFrameworks"
             BuildInParallel="$(BuildInParallel)"
             Properties="%(_AspirePreparedProjectResource.SetConfiguration); %(_AspirePreparedProjectResource.SetPlatform)"
             ContinueOnError="!$(BuildingProject)"
  • Files reviewed: 50/51 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Adam Ratzman and others added 2 commits August 7, 2026 16:36
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address correctness and lifecycle issues found reviewing the debugger
extension install hint.

- Tell the user that the AppHost must be restarted after installing a
  debugger extension. Debug capabilities are snapshotted into
  DEBUG_SESSION_INFO / ASPIRE_EXTENSION_CAPABILITIES when the AppHost
  process starts, so a debugger installed mid-run does not attach to the
  already-running resource. The guidance is deferred until the extension
  is actually visible to `vscode.extensions.getExtension`, because
  `workbench.extensions.installExtension` resolves before the extension
  host publishes the new extension.
- Surface install failures. Marketplace installs fail when the user is
  offline, behind a proxy, or on a build without gallery access; that was
  previously swallowed into the output channel with the hint left in place
  and no explanation.
- Derive hint extension ids from the resource debugger extension registry
  (`languages/python.ts`, `languages/go.ts`, `languages/bun.ts`) so the
  hint can no longer drift from the debugger that actually launches, and
  skip languages whose adapter ships with VS Code.
- Look up Add* method names case-insensitively instead of enumerating both
  spellings. The JS/TS parser matches `/^add\w+$/i`, so any casing can
  reach the lookup.
- Skip opening and parsing AppHost source documents once every hint has
  been shown, suppressed, or satisfied, instead of re-parsing on every
  resource poll for the rest of the session.
- Bound the parse-retry loop so a document being edited continuously
  cannot spin it forever.

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

Copilot-Session: 506d8f00-881f-402a-b6fd-837dad6bbd55
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 506d8f00-881f-402a-b6fd-837dad6bbd55
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 506d8f00-881f-402a-b6fd-837dad6bbd55
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 506d8f00-881f-402a-b6fd-837dad6bbd55
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 506d8f00-881f-402a-b6fd-837dad6bbd55
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 506d8f00-881f-402a-b6fd-837dad6bbd55
Copilot AI review requested due to automatic review settings August 20, 2026 19:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 30/30 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread extension/src/debugger/debuggerInstallHints.ts
@adamint

Copy link
Copy Markdown
Member Author

Copilot resolve the merge conflicts in this pull request

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 30/30 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread extension/src/debugger/debuggerInstallHints.ts Outdated
Comment thread extension/scripts/run-e2e.js Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c705d12c-0838-443f-b083-ed7e745fbfeb
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c705d12c-0838-443f-b083-ed7e745fbfeb
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c705d12c-0838-443f-b083-ed7e745fbfeb
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c705d12c-0838-443f-b083-ed7e745fbfeb

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 30/30 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the full diff with the branch checked out, tracing the new resource.launchConfigurationType property from ResourceSnapshotBuilder through the CLI snapshot mapper into the extension. The core feature logic holds up: Rust adapter selection across platforms, Java/Azure Functions multi-extension handling, install coalescing, registration waiting, and per-debugger-type suppression all behave as intended, and the unit + CodeLens + Hosting + E2E coverage is genuinely thorough.

6 findings, none blocking:

  • Performance / resource usage (2): the background data lease is never released, keeping aspire ps --follow alive for the whole session; the E2E NuGet cache lives in the per-run temp root, forcing a cold restore every run.
  • Correctness / UX (1): an extension-registration timeout is reported as "extensions are disabled" regardless of the actual cause.
  • Maintainability (2): the CodeLLDB extension ID is hardcoded instead of using the capabilities.ts constants this PR introduced; getEnvironmentWithoutE2EBridgeVariables() now injects an E2E variable rather than only stripping them.
  • Test coverage (1): the HasPersistentLifetime() exclusion in GetLaunchConfigurationType is untested.

Comment thread extension/src/debugger/debuggerInstallHints.ts
Comment thread extension/src/debugger/debuggerInstallHints.ts
Comment thread extension/scripts/run-e2e.js Outdated
Comment thread extension/src/debugger/debuggerInstallHints.ts Outdated
Comment thread extension/src/utils/environment.ts
Comment thread tests/Aspire.Hosting.Tests/Dcp/ResourceSnapshotBuilderTests.cs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overall looks good but please take a look at my comments, especially #19131 (comment) we do not want to contribute to "VS Code burning CPU at idle" problem

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 34/34 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

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

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Refresh the final shutdown deadline when a blocked extension host resumes after the original deadline, and cover every final-phase deadline consumer with a deterministic regression test.

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review details

  • Files reviewed: 36/36 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread extension/scripts/run-e2e.js
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ CI Failure Analysis: Possible Flaky Test(s)

The CI build failed due to test failure(s) that appear unrelated to the PR changes. These may be flaky tests.

Suspected flaky test(s):

Suggested actions:

  • Re-run the failed CI jobs to confirm if the failure is intermittent
  • If the test continues to fail, consider quarantining it using /quarantine-test <test name> <issue URL>
  • Search existing issues to see if this test is already known to be flaky

You can re-run the failed jobs from the workflow run page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Show install-suggestion notification when a language debug extension is missing

4 participants