Repository: microsoft/vscode (TypeScript)
Date: 2022-10-07 06:23:47+00:00
Task type: Bug Fix

Issue:
Extension installed in web and remote with kind ['ui','workspace', 'web'] show reload button
- VS Code Version: insiders

Steps to Reproduce:

1. inline a builtin extension like `vscode.bat` in `builtinExtensionsScannerService.ts` and run from sources, you can repro it in gitpod and codespaces too.

Regresion from https://github.com/microsoft/vscode/pull/161046 and https://github.com/microsoft/vscode/pull/161986

cc @sandy081 

![image](https://user-images.githubusercontent.com/25115070/193424291-2a84d7f5-95b2-4447-bd7d-1961d113f109.png)




Issue discussion:

Solution patch:
diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts
--- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts
+++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts
@@ -1030,12 +1030,12 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
 						const extensionInOtherServer = this.installed.filter(e => areSameExtensions(e.identifier, extension!.identifier) && e.server !== extension!.server)[0];
 						if (extensionInOtherServer) {
 							// This extension prefers to run on UI/Local side but is running in remote
-							if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer && this.extensionManifestPropertiesService.prefersExecuteOnUI(extension.local!.manifest)) {
+							if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer && this.extensionManifestPropertiesService.prefersExecuteOnUI(extension.local!.manifest) && extensionInOtherServer.server === this.extensionManagementServerService.localExtensionManagementServer) {
 								return nls.localize('enable locally', "Please reload Visual Studio Code to enable this extension locally.");
 							}
 
 							// This extension prefers to run on Workspace/Remote side but is running in local
-							if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer && this.extensionManifestPropertiesService.prefersExecuteOnWorkspace(extension.local!.manifest)) {
+							if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer && this.extensionManifestPropertiesService.prefersExecuteOnWorkspace(extension.local!.manifest) && extensionInOtherServer.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
 								return nls.localize('enable remote', "Please reload Visual Studio Code to enable this extension in {0}.", this.extensionManagementServerService.remoteExtensionManagementServer?.label);
 							}
 						}


Test patch:
diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts
--- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts
+++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts
@@ -1647,6 +1647,62 @@ suite('ReloadAction', () => {
 		assert.ok(testObject.extension);
 		assert.ok(testObject.enabled);
 	});
+
+	test('Test ReloadAction when ui+workspace+web extension is installed in web and remote and running in remote', async () => {
+		// multi server setup
+		const gallery = aGalleryExtension('a');
+		const webExtension = aLocalExtension('a', { extensionKind: ['ui', 'workspace'], 'browser': 'browser.js' }, { location: URI.file('pub.a').with({ scheme: Schemas.vscodeUserData }) });
+		const remoteExtension = aLocalExtension('a', { extensionKind: ['ui', 'workspace'], 'browser': 'browser.js' }, { location: URI.file('pub.a').with({ scheme: Schemas.vscodeRemote }) });
+		const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, null, createExtensionManagementService([remoteExtension]), createExtensionManagementService([webExtension]));
+		instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+		instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+		instantiationService.stub(IExtensionService, <Partial<IExtensionService>>{
+			extensions: [toExtensionDescription(remoteExtension)],
+			onDidChangeExtensions: Event.None,
+			canAddExtension: (extension) => false,
+			whenInstalledExtensionsRegistered: () => Promise.resolve(true)
+		});
+		const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+		instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+		const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
+		instantiationService.createInstance(ExtensionContainers, [testObject]);
+		instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
+
+		await workbenchService.queryGallery(CancellationToken.None);
+		const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!);
+		testObject.extension = extensions[0];
+		assert.ok(testObject.extension);
+		assert.ok(!testObject.enabled);
+	});
+
+	test('Test ReloadAction when workspace+ui+web extension is installed in web and local and running in local', async () => {
+		// multi server setup
+		const gallery = aGalleryExtension('a');
+		const webExtension = aLocalExtension('a', { extensionKind: ['workspace', 'ui'], 'browser': 'browser.js' }, { location: URI.file('pub.a').with({ scheme: Schemas.vscodeUserData }) });
+		const localExtension = aLocalExtension('a', { extensionKind: ['workspace', 'ui'], 'browser': 'browser.js' }, { location: URI.file('pub.a') });
+		const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), null, createExtensionManagementService([webExtension]));
+		instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+		instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+		instantiationService.stub(IExtensionService, <Partial<IExtensionService>>{
+			extensions: [toExtensionDescription(localExtension)],
+			onDidChangeExtensions: Event.None,
+			canAddExtension: (extension) => false,
+			whenInstalledExtensionsRegistered: () => Promise.resolve(true)
+		});
+		const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+		instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+		const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction);
+		instantiationService.createInstance(ExtensionContainers, [testObject]);
+		instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery));
+
+		await workbenchService.queryGallery(CancellationToken.None);
+		const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!);
+		testObject.extension = extensions[0];
+		assert.ok(testObject.extension);
+		assert.ok(!testObject.enabled);
+	});
 });
 
 suite('RemoteInstallAction', () => {
@@ -2520,22 +2576,27 @@ function aSingleRemoteExtensionManagementServerService(instantiationService: Tes
 	};
 }
 
-function aMultiExtensionManagementServerService(instantiationService: TestInstantiationService, localExtensionManagementService?: IProfileAwareExtensionManagementService, remoteExtensionManagementService?: IProfileAwareExtensionManagementService): IExtensionManagementServerService {
-	const localExtensionManagementServer: IExtensionManagementServer = {
+function aMultiExtensionManagementServerService(instantiationService: TestInstantiationService, localExtensionManagementService?: IProfileAwareExtensionManagementService | null, remoteExtensionManagementService?: IProfileAwareExtensionManagementService | null, webExtensionManagementService?: IProfileAwareExtensionManagementService): IExtensionManagementServerService {
+	const localExtensionManagementServer: IExtensionManagementServer | null = localExtensionManagementService === null ? null : {
 		id: 'vscode-local',
 		label: 'local',
 		extensionManagementService: localExtensionManagementService || createExtensionManagementService(),
 	};
-	const remoteExtensionManagementServer: IExtensionManagementServer = {
+	const remoteExtensionManagementServer: IExtensionManagementServer | null = remoteExtensionManagementService === null ? null : {
 		id: 'vscode-remote',
 		label: 'remote',
 		extensionManagementService: remoteExtensionManagementService || createExtensionManagementService(),
 	};
+	const webExtensionManagementServer: IExtensionManagementServer | null = webExtensionManagementService ? {
+		id: 'vscode-web',
+		label: 'web',
+		extensionManagementService: webExtensionManagementService,
+	} : null;
 	return {
 		_serviceBrand: undefined,
 		localExtensionManagementServer,
 		remoteExtensionManagementServer,
-		webExtensionManagementServer: null,
+		webExtensionManagementServer,
 		getExtensionManagementServer: (extension: IExtension) => {
 			if (extension.location.scheme === Schemas.file) {
 				return localExtensionManagementServer;
@@ -2543,11 +2604,23 @@ function aMultiExtensionManagementServerService(instantiationService: TestInstan
 			if (extension.location.scheme === Schemas.vscodeRemote) {
 				return remoteExtensionManagementServer;
 			}
+			if (extension.location.scheme === Schemas.vscodeUserData) {
+				return webExtensionManagementServer;
+			}
 			throw new Error('');
 		},
 		getExtensionInstallLocation(extension: IExtension): ExtensionInstallLocation | null {
 			const server = this.getExtensionManagementServer(extension);
-			return server === remoteExtensionManagementServer ? ExtensionInstallLocation.Remote : ExtensionInstallLocation.Local;
+			if (server === null) {
+				return null;
+			}
+			if (server === remoteExtensionManagementServer) {
+				return ExtensionInstallLocation.Remote;
+			}
+			if (server === webExtensionManagementServer) {
+				return ExtensionInstallLocation.Web;
+			}
+			return ExtensionInstallLocation.Local;
 		}
 	};
 }