Skip to content

Commit d383aea

Browse files
committed
quiet installation of local extensions
Since many users ignore this notification, only 40% of users who noticed it managed to convert, and around 1% of all users never come back if they try to use we decided to quite this notitication on the connection. Instead it logs and we provide an explicit `Install Local Extensions` command to force sync at any time which will prompt a user.
1 parent e87f108 commit d383aea

File tree

4 files changed

+91
-39
lines changed

4 files changed

+91
-39
lines changed

package.json

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"onCommand:gitpod.exportLogs",
3838
"onCommand:gitpod.api.autoTunnel",
3939
"onCommand:gitpod.showReleaseNotes",
40+
"onCommand:gitpod.installLocalExtensions",
4041
"onAuthenticationRequest:gitpod",
4142
"onUri",
4243
"onStartupFinished"
@@ -63,12 +64,6 @@
6364
"description": "Use the local companion app to connect to a remote workspace.\nWarning: Connecting to a remote workspace using local companion app will be removed in the near future.",
6465
"default": false,
6566
"scope": "application"
66-
},
67-
"gitpod.remote.syncExtensions": {
68-
"type": "boolean",
69-
"description": "Automatically install sync extensions from Gitpod Sync Server on the remote workspace.",
70-
"default": true,
71-
"scope": "application"
7267
}
7368
}
7469
},
@@ -105,8 +100,22 @@
105100
"command": "gitpod.showReleaseNotes",
106101
"category": "Gitpod",
107102
"title": "Show Release Notes"
103+
},
104+
{
105+
"command": "gitpod.installLocalExtensions",
106+
"title": "Gitpod: Install Local Extensions...",
107+
"enablement": "gitpod.inWorkspace == true"
108108
}
109-
]
109+
],
110+
"menus": {
111+
"statusBar/remoteIndicator": [
112+
{
113+
"command": "gitpod.installLocalExtensions",
114+
"group": "remote_00_gitpod_navigation@01",
115+
"when": "gitpod.inWorkspace == true"
116+
}
117+
]
118+
}
110119
},
111120
"main": "./out/extension.js",
112121
"segmentKey": "YErmvd89wPsrCuGcVnF2XAl846W9WIGl",
@@ -165,4 +174,4 @@
165174
"uuid": "8.1.0",
166175
"yazl": "^2.5.1"
167176
}
168-
}
177+
}

scripts/prepare-release-build.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ const releasePackageJson = JSON.parse(fs.readFileSync('./package.json').toString
66

77
const releaseDefaultConfig = new Map([
88
["gitpod.remote.useLocalApp", true],
9-
["gitpod.remote.syncExtensions", false],
109
]);
1110

1211
const gitpodConfig = releasePackageJson.contributes.configuration.find(e => e.title.toLowerCase() === 'gitpod');

src/experiments.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ import * as semver from 'semver';
1010
import Log from './common/logger';
1111

1212
const EXPERTIMENTAL_SETTINGS = [
13-
'gitpod.remote.useLocalApp',
14-
'gitpod.remote.syncExtensions'
13+
'gitpod.remote.useLocalApp'
1514
];
1615

1716
export class ExperimentalSettings {

src/remoteConnector.ts

Lines changed: 73 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6+
import { v4 as uuid } from 'uuid';
67
import { AutoTunnelRequest, ResolveSSHConnectionRequest, ResolveSSHConnectionResponse } from '@gitpod/local-app-api-grpcweb/lib/localapp_pb';
78
import { LocalAppClient } from '@gitpod/local-app-api-grpcweb/lib/localapp_pb_service';
89
import { NodeHttpTransport } from '@improbable-eng/grpc-web-node-http-transport';
@@ -970,48 +971,84 @@ export default class RemoteConnector extends Disposable {
970971
}
971972
}
972973

973-
private async initializeRemoteExtensions(flow: UserFlowTelemetry) {
974+
private async initializeRemoteExtensions(flow: UserFlowTelemetry & { quiet: boolean, flowId: string }) {
975+
this.telemetry.sendUserFlowStatus('enabled', flow);
974976
let syncData: { ref: string; content: string } | undefined;
975977
try {
976978
syncData = await this.settingsSync.readResource(SyncResource.Extensions);
977979
} catch (e) {
978980
if (e instanceof NoSyncStoreError) {
979-
const addSyncProvider = 'Settings Sync: Enable Sign In with Gitpod';
980-
const action = await this.notifications.showInformationMessage(`Could not install local extensions on remote workspace. Please enable [Settings Sync](https://www.gitpod.io/docs/ides-and-editors/settings-sync#enabling-settings-sync-in-vs-code-desktop) with Gitpod.`, { flow, id: 'no_sync_store' }, addSyncProvider);
981-
if (action === addSyncProvider) {
982-
vscode.commands.executeCommand('gitpod.syncProvider.add');
981+
const msg = `Could not install local extensions on remote workspace. Please enable [Settings Sync](https://www.gitpod.io/docs/ides-and-editors/settings-sync#enabling-settings-sync-in-vs-code-desktop) with Gitpod.`;
982+
this.logger.error(msg);
983+
984+
const status = 'no_sync_store';
985+
if (flow.quiet) {
986+
this.telemetry.sendUserFlowStatus(status, flow);
987+
} else {
988+
const addSyncProvider = 'Settings Sync: Enable Sign In with Gitpod';
989+
const action = await this.notifications.showInformationMessage(msg, { flow, id: status }, addSyncProvider);
990+
if (action === addSyncProvider) {
991+
vscode.commands.executeCommand('gitpod.syncProvider.add');
992+
}
983993
}
984994
} else if (e instanceof NoSettingsSyncSession) {
985-
const enableSettingsSync = 'Enable Settings Sync';
986-
const action = await this.notifications.showInformationMessage(`Could not install local extensions on remote workspace. Please enable [Settings Sync](https://www.gitpod.io/docs/ides-and-editors/settings-sync#enabling-settings-sync-in-vs-code-desktop).`, { flow, id: 'no_settings_sync' }, enableSettingsSync);
987-
if (action === enableSettingsSync) {
988-
vscode.commands.executeCommand('workbench.userDataSync.actions.turnOn');
995+
const msg = `Could not install local extensions on remote workspace. Please enable [Settings Sync](https://www.gitpod.io/docs/ides-and-editors/settings-sync#enabling-settings-sync-in-vs-code-desktop) with Gitpod.`;
996+
this.logger.error(msg);
997+
998+
const status = 'no_settings_sync';
999+
if (flow.quiet) {
1000+
this.telemetry.sendUserFlowStatus(status, flow);
1001+
} else {
1002+
const enableSettingsSync = 'Enable Settings Sync';
1003+
const action = await this.notifications.showInformationMessage(msg, { flow, id: status }, enableSettingsSync);
1004+
if (action === enableSettingsSync) {
1005+
vscode.commands.executeCommand('workbench.userDataSync.actions.turnOn');
1006+
}
9891007
}
9901008
} else {
9911009
this.logger.error('Error while fetching settings sync extension data:', e);
9921010

993-
const seeLogs = 'See Logs';
994-
const action = await this.notifications.showErrorMessage(`Error while fetching settings sync extension data.`, { flow, id: 'failed_to_fetch' }, seeLogs);
995-
if (action === seeLogs) {
996-
this.logger.show();
1011+
const status = 'failed_to_fetch';
1012+
if (flow.quiet) {
1013+
this.telemetry.sendUserFlowStatus(status, flow);
1014+
} else {
1015+
const seeLogs = 'See Logs';
1016+
const action = await this.notifications.showErrorMessage(`Error while fetching settings sync extension data.`, { flow, id: status }, seeLogs);
1017+
if (action === seeLogs) {
1018+
this.logger.show();
1019+
}
9971020
}
9981021
}
9991022
return;
10001023
}
10011024

10021025
const syncDataContent = parseSyncData(syncData.content);
10031026
if (!syncDataContent) {
1004-
this.telemetry.sendUserFlowStatus('failed_to_parse_content', flow);
1005-
this.logger.error('Error while parsing sync data');
1027+
const msg = `Error while parsing settings sync extension data.`;
1028+
this.logger.error(msg);
1029+
1030+
const status = 'failed_to_parse_content';
1031+
if (flow.quiet) {
1032+
this.telemetry.sendUserFlowStatus(status, flow);
1033+
} else {
1034+
await this.notifications.showErrorMessage(msg, { flow, id: status });
1035+
}
10061036
return;
10071037
}
10081038

10091039
let extensions: ISyncExtension[];
10101040
try {
10111041
extensions = JSON.parse(syncDataContent.content);
10121042
} catch {
1013-
this.telemetry.sendUserFlowStatus('failed_to_parse_json', flow);
1014-
this.logger.error('Error while parsing settings sync extension data, malformed json');
1043+
const msg = `Error while parsing settings sync extension data, malformed JSON.`;
1044+
this.logger.error(msg);
1045+
1046+
const status = 'failed_to_parse_json';
1047+
if (flow.quiet) {
1048+
this.telemetry.sendUserFlowStatus(status, flow);
1049+
} else {
1050+
await this.notifications.showErrorMessage(msg, { flow, id: status });
1051+
}
10151052
return;
10161053
}
10171054

@@ -1039,10 +1076,18 @@ export default class RemoteConnector extends Disposable {
10391076
});
10401077
this.telemetry.sendUserFlowStatus('synced', flow);
10411078
} catch {
1042-
const seeLogs = 'See Logs';
1043-
const action = await this.notifications.showErrorMessage(`Error while installing local extensions on remote.`, { flow, id: 'failed' }, seeLogs);
1044-
if (action === seeLogs) {
1045-
this.logger.show();
1079+
const msg = `Error while installing local extensions on remote.`;
1080+
this.logger.error(msg);
1081+
1082+
const status = 'failed';
1083+
if (flow.quiet) {
1084+
this.telemetry.sendUserFlowStatus(status, flow);
1085+
} else {
1086+
const seeLogs = 'See Logs';
1087+
const action = await this.notifications.showErrorMessage(msg, { flow, id: status }, seeLogs);
1088+
if (action === seeLogs) {
1089+
this.logger.show();
1090+
}
10461091
}
10471092
}
10481093
}
@@ -1085,13 +1130,13 @@ export default class RemoteConnector extends Disposable {
10851130
this.logger.warn(`Local heartbeat not supported in ${connectionInfo.gitpodHost}, using version ${gitpodVersion.raw}`);
10861131
}
10871132

1088-
const syncExtensions = (await this.experiments.get<boolean>('gitpod.remote.syncExtensions', session.account.id, { gitpodHost: connectionInfo.gitpodHost }))!;
1089-
const userOverride = String(isUserOverrideSetting('gitpod.remote.syncExtensions'));
1090-
const syncExtFlow = { ...connectionInfo, gitpodVersion: gitpodVersion.raw, userId: session.account.id, flow: 'sync_local_extensions', userOverride };
1091-
this.telemetry.sendUserFlowStatus(syncExtensions ? 'enabled' : 'disabled', syncExtFlow);
1092-
if (syncExtensions) {
1093-
this.initializeRemoteExtensions(syncExtFlow);
1094-
}
1133+
const syncExtFlow = { ...connectionInfo, gitpodVersion: gitpodVersion.raw, userId: session.account.id, flow: 'sync_local_extensions' };
1134+
this.initializeRemoteExtensions({ ...syncExtFlow, quiet: true, flowId: uuid() });
1135+
this.context.subscriptions.push(vscode.commands.registerCommand("gitpod.installLocalExtensions", () => {
1136+
this.initializeRemoteExtensions({ ...syncExtFlow, quiet: false, flowId: uuid() });
1137+
}));
1138+
1139+
vscode.commands.executeCommand('setContext', 'gitpod.inWorkspace', true);
10951140
}
10961141

10971142
public override async dispose(): Promise<void> {

0 commit comments

Comments
 (0)