Skip to content

Commit cdf706a

Browse files
mcummingCopilot
andcommitted
Prompt for restart when the marketplace auth provider changes
The provider is selected once at startup, so changing extensions.gallery.authProvider mid-session had no effect and gave no indication that it had not been applied. The sibling serviceUrl setting already prompts; this reuses that listener and dialog rather than rebuilding the provider live. Each setting keeps its own message: serviceUrl still reports a different Marketplace, and the auth change reports a configuration change. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4e27c63d-f29e-4ee0-a324-8adb523f5155
1 parent 3973ede commit cdf706a

2 files changed

Lines changed: 55 additions & 9 deletions

File tree

src/vs/workbench/services/extensionManagement/electron-browser/extensionGalleryManifestService.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { IHeaders } from '../../../../base/parts/request/common/request.js';
99
import { localize } from '../../../../nls.js';
1010
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
1111
import { IEnvironmentService } from '../../../../platform/environment/common/environment.js';
12-
import { IExtensionGalleryManifestService, IExtensionGalleryManifest, ExtensionGalleryServiceUrlConfigKey, ExtensionGalleryManifestStatus } from '../../../../platform/extensionManagement/common/extensionGalleryManifest.js';
12+
import { IExtensionGalleryManifestService, IExtensionGalleryManifest, ExtensionGalleryServiceUrlConfigKey, ExtensionGalleryAuthProviderConfigKey, ExtensionGalleryManifestStatus } from '../../../../platform/extensionManagement/common/extensionGalleryManifest.js';
1313
import { ExtensionGalleryManifestService } from '../../../../platform/extensionManagement/common/extensionGalleryManifestService.js';
1414
import { resolveMarketplaceHeaders } from '../../../../platform/externalServices/common/marketplace.js';
1515
import { IFileService } from '../../../../platform/files/common/files.js';
@@ -110,10 +110,11 @@ export class WorkbenchExtensionGalleryManifestService extends ExtensionGalleryMa
110110
}
111111

112112
this._register(this.configurationService.onDidChangeConfiguration(e => {
113-
if (!e.affectsConfiguration(ExtensionGalleryServiceUrlConfigKey)) {
114-
return;
113+
if (e.affectsConfiguration(ExtensionGalleryServiceUrlConfigKey)) {
114+
this.requestRestart(localize('extensionGalleryManifestService.accountChange', "{0} is now configured to a different Marketplace. Please restart to apply the changes.", this.productService.nameLong));
115+
} else if (e.affectsConfiguration(ExtensionGalleryAuthProviderConfigKey)) {
116+
this.requestRestart(localize('extensionGalleryManifestService.configurationChange', "The Extensions Marketplace configuration has changed. Please restart to apply the changes."));
115117
}
116-
this.requestRestart();
117118
}));
118119
}
119120

@@ -184,9 +185,9 @@ export class WorkbenchExtensionGalleryManifestService extends ExtensionGalleryMa
184185
}
185186
}
186187

187-
private async requestRestart(): Promise<void> {
188+
private async requestRestart(message: string): Promise<void> {
188189
const confirmation = await this.dialogService.confirm({
189-
message: localize('extensionGalleryManifestService.accountChange', "{0} is now configured to a different Marketplace. Please restart to apply the changes.", this.productService.nameLong),
190+
message,
190191
primaryButton: localize({ key: 'restart', comment: ['&& denotes a mnemonic'] }, "&&Restart")
191192
});
192193
if (confirmation.confirmed) {

src/vs/workbench/services/extensionManagement/test/electron-browser/extensionGalleryManifestService.test.ts

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { IRequestContext, IRequestOptions } from '../../../../../base/parts/requ
1111
import { mock } from '../../../../../base/test/common/mock.js';
1212
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
1313
import { TestConfigurationService } from '../../../../../platform/configuration/test/common/testConfigurationService.js';
14-
import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js';
14+
import { IConfigurationChangeEvent, IConfigurationService } from '../../../../../platform/configuration/common/configuration.js';
1515
import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js';
1616
import { IDefaultAccountService } from '../../../../../platform/defaultAccount/common/defaultAccount.js';
1717
import { IEnvironmentService } from '../../../../../platform/environment/common/environment.js';
@@ -26,7 +26,7 @@ import { IRequestService } from '../../../../../platform/request/common/request.
2626
import { IStorageService, StorageScope, StorageTarget } from '../../../../../platform/storage/common/storage.js';
2727
import { ITelemetryService } from '../../../../../platform/telemetry/common/telemetry.js';
2828
import { NullTelemetryServiceShape } from '../../../../../platform/telemetry/common/telemetryUtils.js';
29-
import { IDialogService } from '../../../../../platform/dialogs/common/dialogs.js';
29+
import { IConfirmation, IDialogService } from '../../../../../platform/dialogs/common/dialogs.js';
3030
import { AuthenticationSession, AuthenticationSessionsChangeEvent, IAuthenticationService } from '../../../authentication/common/authentication.js';
3131
import { IHostService } from '../../../host/browser/host.js';
3232
import { IRemoteAgentService } from '../../../remote/common/remoteAgentService.js';
@@ -110,12 +110,14 @@ suite('WorkbenchExtensionGalleryManifestService', () => {
110110
let configurationService: TestConfigurationService;
111111
let storageData: Map<string, string>;
112112
let telemetryService: RecordingTelemetryService;
113+
let restartPrompts: string[];
113114

114115
setup(() => {
115116
defaultAccount = null;
116117
microsoftSessions = [];
117118
requestHandler = () => mockResponse(200, createGalleryManifest());
118119
storageData = new Map();
120+
restartPrompts = [];
119121

120122
onDidChangeDefaultAccount = disposableStore.add(new Emitter<IDefaultAccount | null>());
121123
onDidChangeSessions = disposableStore.add(new Emitter<{ providerId: string; label: string; event: AuthenticationSessionsChangeEvent }>());
@@ -192,7 +194,7 @@ suite('WorkbenchExtensionGalleryManifestService', () => {
192194
instantiationService.stub(ILogService, new NullLogService());
193195

194196
instantiationService.stub(IDialogService, new class extends mock<IDialogService>() {
195-
override async confirm() { return { confirmed: false }; }
197+
override async confirm(confirmation: IConfirmation) { restartPrompts.push(confirmation.message); return { confirmed: false }; }
196198
}());
197199

198200
instantiationService.stub(IHostService, new class extends mock<IHostService>() {
@@ -744,6 +746,49 @@ suite('WorkbenchExtensionGalleryManifestService', () => {
744746
assert.strictEqual(service.extensionGalleryManifestStatus, ExtensionGalleryManifestStatus.Available);
745747
});
746748

749+
// --- Configuration changes ---
750+
751+
function fireConfigChange(...keys: string[]) {
752+
configurationService.onDidChangeConfigurationEmitter.fire({
753+
affectsConfiguration: (key: string) => keys.includes(key),
754+
} as IConfigurationChangeEvent);
755+
}
756+
757+
test('changing authProvider mid-session prompts for restart', async () => {
758+
configurationService.setUserConfiguration(ExtensionGalleryAuthProviderConfigKey, 'microsoft');
759+
microsoftSessions = [createMicrosoftSession()];
760+
761+
const service = createService();
762+
await service.getExtensionGalleryManifest();
763+
assert.deepStrictEqual(restartPrompts, []);
764+
765+
// The provider is chosen once at startup, so a later change cannot take effect in this
766+
// window. It must not be silently ignored.
767+
configurationService.setUserConfiguration(ExtensionGalleryAuthProviderConfigKey, 'github');
768+
fireConfigChange(ExtensionGalleryAuthProviderConfigKey);
769+
770+
assert.deepStrictEqual(restartPrompts, ['The Extensions Marketplace configuration has changed. Please restart to apply the changes.']);
771+
});
772+
773+
test('changing serviceUrl mid-session keeps its own restart message', async () => {
774+
const service = createService();
775+
await service.getExtensionGalleryManifest();
776+
777+
fireConfigChange(ExtensionGalleryServiceUrlConfigKey);
778+
779+
// A different marketplace, not a different sign-in — the existing wording still applies.
780+
assert.deepStrictEqual(restartPrompts, ['VS Code Test is now configured to a different Marketplace. Please restart to apply the changes.']);
781+
});
782+
783+
test('an unrelated configuration change does not prompt for restart', async () => {
784+
const service = createService();
785+
await service.getExtensionGalleryManifest();
786+
787+
fireConfigChange('editor.fontSize');
788+
789+
assert.deepStrictEqual(restartPrompts, []);
790+
});
791+
747792
// --- Telemetry ---
748793

749794
function authCheckedEvents() {

0 commit comments

Comments
 (0)