VS Code extension: Auto-restore on workspace open and config change#15546
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 15546Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 15546" |
There was a problem hiding this comment.
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
AspirePackageRestoreProviderto runaspire restoreon workspace open and onaspire.config.jsonchanges (with a concurrency cap and status bar progress). - Adds the
aspire.enableAutoRestoresetting (defaulttrue) plus localized strings for restore progress and results. - Updates TypeScript playground
aspire.config.jsonfiles and refreshes generated AppHost.modulesoutputs.
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. |
JamesNK
left a comment
There was a problem hiding this comment.
Code review — focused on problems only. 5 inline comments on the new AspirePackageRestoreProvider.
…g restores, separate errors, fix timeout leak, handle unhandled promise
Co-authored-by: Ankit Jain <radical@gmail.com>
… status bar - Fix floating promises in watcher handlers (void + catch) - Fix timing bug: .finally() runs before _hadFailure is updated - Extract _scheduleHide() for status bar auto-hide logic - Add explicit _showProgress() call on success path - Only update _lastContent after successful restore - Add settled flag to prevent double resolve/reject - Add try/catch around proc.kill() - Replace magic numbers with named constants - Fix space before ellipsis in localized strings - Wire up AspirePackageRestoreProvider in extension.ts - Add aspire-vscode.restore command - Show failure state in status bar with error background - Make status bar item clickable (runs restore command)
- Early returns (file-read failure, unchanged content) now increment _completed so the progress bar doesn't get stuck - Skip _total increment when a re-restore is already queued for the same directory, preventing counter inflation from duplicate events
1c0e42c to
8a23f34
Compare
- Guard counter mutations during batch with _batchRunning flag - Replace single _hadFailure boolean with per-directory _failedDirs set - Use single _hideTimeout reference instead of accumulating timeouts - Change recursive pending-restore tail call to iterative while loop Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix _active map leak when getAspireCliExecutablePath() throws by wrapping _runRestore body in try/finally instead of using .finally() on the inner Promise - Fix progress counter desync (completed > total) when a file watcher fires during _restoreAll() by removing the _batchRunning guard - Wire restore command to provider.retryRestore() so clicking the error status bar clears _failedDirs and re-triggers _restoreAll() Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Re-running the failed jobs in the CI workflow for this pull request because 1 job was identified as retry-safe transient failures in the CI run attempt.
|
JamesNK
left a comment
There was a problem hiding this comment.
Nice feature — the concurrency limiter, content-based dedup, and baseline-only-on-success patterns are well thought out. Left two minor suggestions inline.
| new vscode.RelativePattern(folder, `**/${aspireConfigFileName}`) | ||
| ); | ||
| watcher.onDidChange(uri => void this._onChanged(uri).catch(err => extensionLogOutputChannel.warn(`Watcher handler failed: ${String(err)}`))); | ||
| watcher.onDidCreate(uri => void this._onChanged(uri).catch(err => extensionLogOutputChannel.warn(`Watcher handler failed: ${String(err)}`))); |
There was a problem hiding this comment.
The watcher subscribes to onDidChange and onDidCreate but not onDidDelete. When an aspire.config.json is deleted (e.g. removing an apphost, git clean), the _lastContent map retains a stale entry. If the file is later recreated with the same content, _restoreIfChanged will see it as unchanged and skip the restore.
Consider adding:
watcher.onDidDelete(uri => {
this._lastContent.delete(uri.fsPath);
});| settled = true; | ||
| extensionLogOutputChannel.warn(aspireRestoreFailed(relativePath, error.message)); | ||
| reject(error); | ||
| }, |
There was a problem hiding this comment.
Nit: proc.kill() sends SIGTERM which may not propagate to grandchild processes on Windows. If aspire restore spawns sub-processes (e.g. dotnet restore), they could leak on timeout or dispose. Worth considering a process group or taskkill /T on Windows for cleanup, though this may be an acceptable limitation for now since shell: false is used.
There was a problem hiding this comment.
On Windows you usually use a job object to ensure that whole process hierarchy is stopped. If you decide to go down that route, make sure the job enables JOB_OBJECT_LIMIT_BREAKAWAY_OK.
Description
Adds automatic
aspire restoreexecution in the VS Code extension to keep integration packages in sync withaspire.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
AspirePackageRestoreProviderautomatically runsaspire restore:aspire.config.jsonfiles found in the workspaceFileSystemWatchermonitorsaspire.config.jsonfiles; when content actually changes (e.g., branch switch, manual edit), it runs restoreFeatures
Running aspire restore (2/5 projects) ...)aspire restorecommand in the Aspire terminalAspire: Restorecommand — new command palette entry (aspire-vscode.restore) to manually trigger restoreaspire.config.jsoncontent actually changes, not on every file-save event_lastContentis only updated after a successful restore, so failures don't prevent retries on the next changeaspire.enableAutoRestoresetting (default:true); toggling the setting on immediately starts watching and restoringTesting
I tested this using:
Fixes #15491
Checklist