Skip to content

VS Code extension: Auto-restore on workspace open and config change#15546

Open
adamint wants to merge 4 commits intomicrosoft:mainfrom
adamint:dev/adamint/run-aspire-restore-branch-switch-workspace-open
Open

VS Code extension: Auto-restore on workspace open and config change#15546
adamint wants to merge 4 commits intomicrosoft:mainfrom
adamint:dev/adamint/run-aspire-restore-branch-switch-workspace-open

Conversation

@adamint
Copy link
Member

@adamint adamint commented Mar 24, 2026

Description

Adds automatic aspire restore execution in the VS Code extension to keep integration packages in sync with aspire.config.json.

Problem: When switching git branches that have different Aspire integrations configured, the editor shows squiggly errors until you manually run aspire restore. This is a common friction point during development.

Solution: The new AspirePackageRestoreProvider automatically runs aspire restore:

  • On workspace open — restores all aspire.config.json files found in the workspace
  • On config content change — a FileSystemWatcher monitors aspire.config.json files; when content actually changes (e.g., branch switch, manual edit), it runs restore

I tested this using:

  1. the playground folder, since there are over a hundred ts apphosts. The apphosts are restored slowly, respecting the concurrency limit. This should not be an issue in practice, as the likelihood of a repo having hundreds of apphosts is low.
  2. a separate local git repo where one branch had a redis package entry, and the apphost in both branches had an addRedis call.

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
    • No
  • Does the change require an update in our Aspire docs?
    • Yes
    • No

Copilot AI review requested due to automatic review settings March 24, 2026 20:58
@github-actions
Copy link
Contributor

github-actions bot commented Mar 24, 2026

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

Or

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

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an auto-restore mechanism to the VS Code extension so aspire restore is run automatically to keep integration packages in sync with aspire.config.json, reducing editor squiggles after branch switches/config edits.

Changes:

  • Introduces AspirePackageRestoreProvider to run aspire restore on workspace open and on aspire.config.json changes (with a concurrency cap and status bar progress).
  • Adds the aspire.enableAutoRestore setting (default true) plus localized strings for restore progress and results.
  • Updates TypeScript playground aspire.config.json files and refreshes generated AppHost .modules outputs.

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
playground/TypeScriptApps/RpsArena/aspire.config.json Moves package versions to 13.2.0 and removes daily SDK/channel fields.
playground/TypeScriptApps/AzureFunctionsSample/aspire.config.json Adds appHost metadata and moves package versions to 13.2.0.
playground/TypeScriptApps/AzureFunctionsSample/AppHost/.modules/transport.ts Updates generated transport layer (cancellation, marshalling, connection/auth flow).
playground/TypeScriptApps/AzureFunctionsSample/AppHost/.modules/base.ts Updates generated base SDK types (ReferenceExpression enhancements, transport value serialization).
playground/TypeScriptApps/AzureFunctionsSample/AppHost/.modules/.codegen-hash Updates codegen hash to reflect regenerated modules.
extension/src/utils/settings.ts Adds accessor for enableAutoRestore.
extension/src/utils/AspirePackageRestoreProvider.ts New provider that runs/monitors aspire restore and shows status bar progress.
extension/src/loc/strings.ts Adds localized runtime strings for restore progress/results.
extension/src/extension.ts Wires up the new auto-restore provider during activation.
extension/package.nls.json Adds localized description for the new setting and restore messages.
extension/package.json Defines the new aspire.enableAutoRestore configuration setting.
extension/loc/xlf/aspire-vscode.xlf Adds localization units for new strings/setting description.

…g restores, separate errors, fix timeout leak, handle unhandled promise
…s-15546

# Conflicts:
#	playground/TypeScriptApps/AzureFunctionsSample/AppHost/.modules/.codegen-hash
#	playground/TypeScriptApps/AzureFunctionsSample/AppHost/.modules/aspire.ts
#	playground/TypeScriptApps/AzureFunctionsSample/AppHost/.modules/base.ts
#	playground/TypeScriptApps/AzureFunctionsSample/AppHost/.modules/transport.ts
@adamint adamint requested a review from mitchdenny March 25, 2026 05:07
Comment on lines -10 to +8
"Aspire.Hosting.Python": "13.3.0-preview.1.26167.8",
"Aspire.Hosting.PostgreSQL": "13.3.0-preview.1.26167.8",
"Aspire.Hosting.JavaScript": "13.3.0-preview.1.26167.8"
"Aspire.Hosting.Python": "13.2.0",
"Aspire.Hosting.PostgreSQL": "13.2.0",
"Aspire.Hosting.JavaScript": "13.2.0"
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't be using the latest main builds? What effect would this change have?

"aspire-vscode.strings.selectFileTitle": "Select file",
"aspire-vscode.strings.enterPipelineStep": "Enter the pipeline step to execute",
"aspire-vscode.strings.runningAspireRestore": "Running aspire restore on {0}...",
"aspire-vscode.strings.runningAspireRestoreProgress": "Running aspire restore ({0}/{1} projects)...",
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"aspire-vscode.strings.runningAspireRestoreProgress": "Running aspire restore ({0}/{1} projects)...",
"aspire-vscode.strings.runningAspireRestoreProgress": "Running aspire restore ({0}/{1} projects ...",

"aspire-vscode.strings.selectDirectoryTitle": "Select directory",
"aspire-vscode.strings.selectFileTitle": "Select file",
"aspire-vscode.strings.enterPipelineStep": "Enter the pipeline step to execute",
"aspire-vscode.strings.runningAspireRestore": "Running aspire restore on {0}...",
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"aspire-vscode.strings.runningAspireRestore": "Running aspire restore on {0}...",
"aspire-vscode.strings.runningAspireRestore": "Running aspire restore on {0} ...",

Comment on lines +191 to +202
for (const proc of this._childProcesses) {
proc.kill();
}
this._childProcesses.clear();
for (const timeout of this._timeouts) {
clearTimeout(timeout);
}
this._timeouts.clear();
for (const d of this._disposables) {
d.dispose();
}
this._disposables.length = 0;
Copy link
Member

Choose a reason for hiding this comment

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

I'm a TS noob. Do we need to handle exceptions here like if killing a process fails?

export const cliFoundAtDefaultPath = (path: string) => vscode.l10n.t('Aspire CLI found at {0}. The extension will use this path.', path);
export const selectDirectoryTitle = vscode.l10n.t('Select directory');
export const runningAspireRestore = (configPath: string) => vscode.l10n.t('Running aspire restore on {0}...', configPath);
export const runningAspireRestoreProgress = (completed: number, total: number) => vscode.l10n.t('Running aspire restore ({0}/{1} projects)...', completed, total);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
export const runningAspireRestoreProgress = (completed: number, total: number) => vscode.l10n.t('Running aspire restore ({0}/{1} projects)...', completed, total);
export const runningAspireRestoreProgress = (completed: number, total: number) => vscode.l10n.t('Running aspire restore ({0}/{1} projects ...', completed, total);

export const cliNotAvailable = vscode.l10n.t('Aspire CLI is not available on PATH. Please install it and restart VS Code.');
export const cliFoundAtDefaultPath = (path: string) => vscode.l10n.t('Aspire CLI found at {0}. The extension will use this path.', path);
export const selectDirectoryTitle = vscode.l10n.t('Select directory');
export const runningAspireRestore = (configPath: string) => vscode.l10n.t('Running aspire restore on {0}...', configPath);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
export const runningAspireRestore = (configPath: string) => vscode.l10n.t('Running aspire restore on {0}...', configPath);
export const runningAspireRestore = (configPath: string) => vscode.l10n.t('Running aspire restore on {0} ...', configPath);

if (!getEnableAutoRestore()) {
return;
}
if (this._active.size === 0) {
Copy link
Member

Choose a reason for hiding this comment

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

Do we need to worry about _onChanged getting called multiple times in parallel?

const hideTimeout = setTimeout(() => {
this._timeouts.delete(hideTimeout);
if (this._active.size === 0) { this._statusBarItem.hide(); }
}, 5000);
Copy link
Member

Choose a reason for hiding this comment

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

5000 - should this be a const from somewhere?

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.

3 participants