Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 15, 2025

Added support for marking runtime dependencies as optional in package.json. When a runtime dependency is marked with "isOptional": true, the extension will log failure events, send telemetry, and continue with activation instead of stopping.

Problem

Previously, if any runtime dependency failed to download during extension activation, the entire activation process would stop. This caused the extension to be unusable even when the failed dependency was not critical for core functionality. Additionally, there was no telemetry tracking for package installation failures, and the extension would throw errors when trying to load optional components that weren't installed.

Solution

Added an isOptional boolean field to the package interface. When a package is marked as optional ("isOptional": true), download or installation failures are logged but don't prevent extension activation from completing. Additionally, telemetry events are now sent for all package installation failures across both the main extension and OmniSharp components. Component loading infrastructure was updated to handle missing optional components gracefully with warning logs.

Changes Made

  1. Extended IPackage interface - Added optional isOptional?: boolean field
  2. Updated AbsolutePathPackage - Propagates the isOptional property from package definitions
  3. Modified downloadAndInstallPackages - Handles optional package failures by:
    • Logging InstallationFailure events (visible in the C# output channel)
    • Sending telemetry event PackageInstallationFailed with failure details (packageId, isOptional flag, error details)
    • Continuing to process remaining packages
    • Returning true to allow activation to proceed
    • Extracted telemetry sending to nested function for better code organization
  4. Updated component loading infrastructure:
    • Added isOptional field to ComponentInfo interface
    • Only roslynCopilot is marked as optional (xamlTools and razorDevKit are required as they ship in-box)
    • Updated getComponentPaths to accept optional LogOutputChannel for logging
    • Logs warning when optional component files don't exist: "Optional component '<name>' could not be found at '<path>'"
    • Returns empty array instead of throwing when optional component files don't exist
  5. Threaded ITelemetryReporter through OmniSharp and Razor components:
    • Made reporter parameter optional in OmnisharpDownloader and RazorOmnisharpDownloader
    • Updated all callers to pass reporter where available
    • Removed unnecessary undefined parameters from tests
  6. Added comprehensive tests - Three new test cases verify optional package behavior

Telemetry

Package installation failures now send telemetry events with the following properties:

  • Event Name: PackageInstallationFailed (single event name for both optional and required packages)
  • Properties:
    • installStage - where the failure occurred
    • packageId - the package identifier
    • isOptional - whether the package was optional (distinguishes optional vs required)
    • error.message - the error message
    • error.packageUrl - the package URL

This telemetry now applies to main extension, OmniSharp, and Razor package downloads.

Usage

To mark a runtime dependency as optional in package.json:

{
  "id": "OptionalComponent",
  "description": "Optional Component",
  "url": "https://example.com/component.zip",
  "installPath": ".optional",
  "platforms": ["win32", "darwin", "linux"],
  "architectures": ["x86_64"],
  "isOptional": true
}

Behavior

  • Required packages (default, or "isOptional": false): Failure stops extension activation
  • Optional packages ("isOptional": true): Failure is logged with full details but activation continues
  • Optional components: When component files don't exist, getComponentPaths logs a warning and returns empty array instead of throwing

All failure messages are logged to the C# output channel via the existing InstallationFailure event handling infrastructure. Optional component warnings are logged to the appropriate output channel.

User Experience

When an optional package fails to download, users see clear error messages in the C# Output Window while the extension continues to activate:

Output Window Example

Testing

  • All existing tests pass (335 tests)
  • Added 3 new test cases covering optional package scenarios
  • Linting and compilation successful

Fixes #8702

Original prompt

This section details on the original issue you should resolve

<issue_title>Extension activation stops when unable to download runtime dependency</issue_title>
<issue_description>The PackageManager should be updated so that runtimeDependencies in the packages.json can be marked as optional. When an optional runtime dependency fails to download then a message should be logged and extension activation should continue.</issue_description>

Comments on the Issue (you are @copilot in this section)

Fixes #8702


💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

Copilot AI and others added 2 commits October 15, 2025 18:11
Co-authored-by: JoeRobich <611219+JoeRobich@users.noreply.github.com>
Co-authored-by: JoeRobich <611219+JoeRobich@users.noreply.github.com>
Copilot AI changed the title [WIP] Update PackageManager to handle optional runtime dependencies Support optional runtime dependencies in package.json Oct 15, 2025
Copilot AI requested a review from JoeRobich October 15, 2025 18:20
Copilot finished work on behalf of JoeRobich October 15, 2025 18:20
@JoeRobich JoeRobich marked this pull request as ready for review October 15, 2025 18:25
@JoeRobich JoeRobich requested a review from a team as a code owner October 15, 2025 18:25
@JoeRobich
Copy link
Member

@copilot Update getComponentPaths in src/lsptoolshost/extensions/builtInComponents.ts so that if a component is optional and its file path does not exist it will not throw and instead continue to the next path.

Co-authored-by: JoeRobich <611219+JoeRobich@users.noreply.github.com>
Copilot AI requested a review from a team as a code owner October 15, 2025 19:10
Copilot AI requested a review from JoeRobich October 15, 2025 19:13
Copilot finished work on behalf of JoeRobich October 15, 2025 19:13
Co-authored-by: JoeRobich <611219+JoeRobich@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Oct 15, 2025

@copilot Update getComponentPaths in src/lsptoolshost/extensions/builtInComponents.ts so that if a component is optional and its file path does not exist it will not throw and instead continue to th...

Updated getComponentPaths to accept an isOptional parameter. When true and component files don't exist, it returns an empty array instead of throwing. Marked roslynCopilot, xamlTools, and razorDevKit as optional at their call sites.

Commit: 8def695

@copilot Update getComponentPaths in src/lsptoolshost/extensions/builtInComponents.ts so that if a component is optional and its file path does not exist it will not throw and instead continue to th...

Updated getComponentPaths to accept an isOptional parameter. When true and component files don't exist, it returns an empty array instead of throwing. Marked roslynCopilot, xamlTools, and razorDevKit as optional at their call sites.

Commit: 9c0d446

Copilot finished work on behalf of JoeRobich October 15, 2025 19:22
Co-authored-by: JoeRobich <611219+JoeRobich@users.noreply.github.com>
Copilot AI requested a review from JoeRobich October 15, 2025 20:03
Copilot finished work on behalf of JoeRobich October 15, 2025 20:15
Copilot AI requested a review from JoeRobich October 15, 2025 20:15
Co-authored-by: JoeRobich <611219+JoeRobich@users.noreply.github.com>
Copilot AI requested a review from JoeRobich October 15, 2025 20:47
Copilot finished work on behalf of JoeRobich October 15, 2025 20:47
Co-authored-by: JoeRobich <611219+JoeRobich@users.noreply.github.com>
Copilot AI requested a review from JoeRobich October 15, 2025 21:50
Copilot finished work on behalf of JoeRobich October 15, 2025 21:50
…operty

Co-authored-by: JoeRobich <611219+JoeRobich@users.noreply.github.com>
@JoeRobich JoeRobich changed the title Support optional runtime dependencies in package.json Support optional components Oct 15, 2025
const provider = () => new NetworkSettings('', true);
if (!(await downloadAndInstallPackages(packagesToInstall, provider, eventStream, isValidDownload, token))) {
if (
!(await downloadAndInstallPackages(packagesToInstall, provider, eventStream, isValidDownload, undefined, token))
Copy link
Member

Choose a reason for hiding this comment

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

This should probably check that all results were successful

@JoeRobich JoeRobich enabled auto-merge October 16, 2025 00:02
@JoeRobich JoeRobich merged commit bcc4d29 into main Oct 16, 2025
28 checks passed
@JoeRobich JoeRobich deleted the copilot/update-runtime-dependencies-handling branch October 16, 2025 13:43
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.

Extension activation stops when unable to download runtime dependency

4 participants