Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions extension/loc/xlf/aspire-vscode.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@
"title": "%command.configureLaunchJson%",
"category": "Aspire"
},
{
"command": "aspire-vscode.restore",
"enablement": "workspaceFolderCount > 0",
"title": "%command.restore%",
"category": "Aspire"
},
{
"command": "aspire-vscode.settings",
"title": "%command.settings%",
Expand Down Expand Up @@ -685,6 +691,12 @@
"default": true,
"description": "%configuration.aspire.enableGutterDecorations%",
"scope": "window"
},
"aspire.enableAutoRestore": {
"type": "boolean",
"default": true,
"description": "%configuration.aspire.enableAutoRestore%",
"scope": "window"
}
}
},
Expand Down
8 changes: 8 additions & 0 deletions extension/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"command.deploy": "Deploy app",
"command.do": "Execute pipeline step (aspire do)",
"command.configureLaunchJson": "Configure launch.json file",
"command.restore": "Restore packages",
"command.settings": "Extension settings",
"command.openLocalSettings": "Open local Aspire settings",
"command.openGlobalSettings": "Open global Aspire settings",
Expand All @@ -39,6 +40,7 @@
"configuration.aspire.globalAppHostsPollingInterval": "Polling interval in milliseconds for fetching all running apphosts (used in global view). Minimum: 1000.",
"configuration.aspire.enableCodeLens": "Show CodeLens actions (state, restart, stop, logs) inline above resource declarations in apphost files.",
"configuration.aspire.enableGutterDecorations": "Show colored status dots in the editor gutter next to resource declarations in apphost files.",
"configuration.aspire.enableAutoRestore": "Automatically run 'aspire restore' when the workspace opens and whenever aspire.config.json changes (e.g. after switching git branches). Keeps integration packages in sync and prevents editor errors.",
"command.runAppHost": "Run Aspire apphost",
"command.debugAppHost": "Debug Aspire apphost",
"aspire-vscode.strings.noCsprojFound": "No apphost found in the current workspace.",
Expand Down Expand Up @@ -117,6 +119,12 @@
"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} ...",
"aspire-vscode.strings.runningAspireRestoreProgress": "Running aspire restore ({0}/{1} projects) ...",
"aspire-vscode.strings.aspireRestoreCompleted": "Aspire restore completed for {0}.",
"aspire-vscode.strings.aspireRestoreAllCompleted": "Aspire restore completed",
"aspire-vscode.strings.aspireRestoreFailed": "aspire restore failed for {0}: {1}",
"aspire-vscode.strings.aspireRestoreFailedStatusBar": "Aspire restore failed (click to retry)",
"aspire-vscode.strings.appHostSourceNotFound": "Could not determine the AppHost source file to open.",
"aspire-vscode.strings.appHostSourceOpenFailed": "Failed to open AppHost source file: {0}",
"viewsContainers.aspirePanel.title": "Aspire",
Expand Down
12 changes: 11 additions & 1 deletion extension/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { settingsCommand } from './commands/settings';
import { openLocalSettingsCommand, openGlobalSettingsCommand } from './commands/openSettings';
import { checkCliAvailableOrRedirect, checkForExistingAppHostPathInWorkspace } from './utils/workspace';
import { AspireEditorCommandProvider } from './editor/AspireEditorCommandProvider';
import { AspirePackageRestoreProvider } from './utils/AspirePackageRestoreProvider';
import { AspireAppHostTreeProvider } from './views/AspireAppHostTreeProvider';
import { AppHostDataRepository } from './views/AppHostDataRepository';
import { installCliStableCommand, installCliDailyCommand, verifyCliInstalledCommand } from './commands/walkthroughCommands';
Expand Down Expand Up @@ -69,6 +70,7 @@ export async function activate(context: vscode.ExtensionContext) {
const settingsCommandRegistration = vscode.commands.registerCommand('aspire-vscode.settings', () => tryExecuteCommand('aspire-vscode.settings', terminalProvider, settingsCommand));
const openLocalSettingsCommandRegistration = vscode.commands.registerCommand('aspire-vscode.openLocalSettings', () => tryExecuteCommand('aspire-vscode.openLocalSettings', terminalProvider, openLocalSettingsCommand));
const openGlobalSettingsCommandRegistration = vscode.commands.registerCommand('aspire-vscode.openGlobalSettings', () => tryExecuteCommand('aspire-vscode.openGlobalSettings', terminalProvider, openGlobalSettingsCommand));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Clicking the error status bar doesn't clear the error state.

The command runs sendAspireCommandToAspireTerminal('restore'), which executes in the integrated terminal — completely separate from AspirePackageRestoreProvider's internal state. Even if the manual terminal restore succeeds, _failedDirs is never cleared, so the error icon persists indefinitely. Only a file content change that triggers a successful automatic restore clears it.

Consider either:

  • Having the restore command also clear _failedDirs and re-trigger _restoreAll(), or
  • Wiring the status bar command to a method on AspirePackageRestoreProvider instead of the terminal command.

const restoreCommandRegistration = vscode.commands.registerCommand('aspire-vscode.restore', () => terminalProvider.sendAspireCommandToAspireTerminal('restore'));
const runAppHostCommandRegistration = vscode.commands.registerCommand('aspire-vscode.runAppHost', () => editorCommandProvider.tryExecuteRunAppHost(true));
const debugAppHostCommandRegistration = vscode.commands.registerCommand('aspire-vscode.debugAppHost', () => editorCommandProvider.tryExecuteRunAppHost(false));

Expand Down Expand Up @@ -150,7 +152,7 @@ export async function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(gutterDecorationProvider);

context.subscriptions.push(cliAddCommandRegistration, cliNewCommandRegistration, cliInitCommandRegistration, cliDeployCommandRegistration, cliPublishCommandRegistration, cliDoCommandRegistration, openTerminalCommandRegistration, configureLaunchJsonCommandRegistration);
context.subscriptions.push(cliUpdateCommandRegistration, cliUpdateSelfCommandRegistration, settingsCommandRegistration, openLocalSettingsCommandRegistration, openGlobalSettingsCommandRegistration, runAppHostCommandRegistration, debugAppHostCommandRegistration);
context.subscriptions.push(cliUpdateCommandRegistration, cliUpdateSelfCommandRegistration, settingsCommandRegistration, openLocalSettingsCommandRegistration, openGlobalSettingsCommandRegistration, restoreCommandRegistration, runAppHostCommandRegistration, debugAppHostCommandRegistration);
context.subscriptions.push(installCliStableRegistration, installCliDailyRegistration, verifyCliInstalledRegistration);

const debugConfigProvider = new AspireDebugConfigurationProvider();
Expand Down Expand Up @@ -192,6 +194,14 @@ export async function activate(context: vscode.ExtensionContext) {
// any user-visible errors should be handled within checkForExistingAppHostPathInWorkspace.
});
}

// Auto-restore: run `aspire restore` on workspace open and when aspire.config.json changes
const packageRestoreProvider = new AspirePackageRestoreProvider(terminalProvider);
context.subscriptions.push(packageRestoreProvider);
void packageRestoreProvider.activate().catch(err => {
extensionLogOutputChannel.warn(`Auto-restore activation failed: ${String(err)}`);
});

// Return exported API for tests or other extensions
return {
rpcServerInfo: rpcServer.connectionInfo,
Expand Down
6 changes: 6 additions & 0 deletions extension/src/loc/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ export const openCliInstallInstructions = vscode.l10n.t('See CLI installation in
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);
export const runningAspireRestoreProgress = (completed: number, total: number) => vscode.l10n.t('Running aspire restore ({0}/{1} projects) ...', completed, total);
export const aspireRestoreCompleted = (configPath: string) => vscode.l10n.t('Aspire restore completed for {0}.', configPath);
export const aspireRestoreAllCompleted = vscode.l10n.t('Aspire restore completed');
export const aspireRestoreFailed = (configPath: string, error: string) => vscode.l10n.t('aspire restore failed for {0}: {1}', configPath, error);
export const aspireRestoreFailedStatusBar = vscode.l10n.t('Aspire restore failed (click to retry)');
export const selectFileTitle = vscode.l10n.t('Select file');
export const enterPipelineStep = vscode.l10n.t('Enter the pipeline step to execute');
export const appHostSourceNotFound = vscode.l10n.t('Could not determine the AppHost source file to open.');
Expand Down
Loading
Loading