Move tas-client to umd version and adopt in web (#106904)
* adopt tas-client-umd * adopt in web * fix whitespace * adding tas-client to webignore * upgrade tas-client-umd * move svc imort to common * remove unnecessary ignore
This commit is contained in:
parent
50610f085d
commit
92a30ed265
|
@ -522,6 +522,7 @@
|
||||||
"vscode-oniguruma",
|
"vscode-oniguruma",
|
||||||
"iconv-lite-umd",
|
"iconv-lite-umd",
|
||||||
"semver-umd",
|
"semver-umd",
|
||||||
|
"tas-client-umd",
|
||||||
"jschardet"
|
"jschardet"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -348,7 +348,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Reason: The license cannot be found by the tool due to access controls on the repository
|
// Reason: The license cannot be found by the tool due to access controls on the repository
|
||||||
"name": "tas-client",
|
"name": "tas-client-umd",
|
||||||
"fullLicenseText": [
|
"fullLicenseText": [
|
||||||
"MIT License",
|
"MIT License",
|
||||||
"Copyright (c) 2020 - present Microsoft Corporation",
|
"Copyright (c) 2020 - present Microsoft Corporation",
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
"semver-umd": "^5.5.7",
|
"semver-umd": "^5.5.7",
|
||||||
"spdlog": "^0.11.1",
|
"spdlog": "^0.11.1",
|
||||||
"sudo-prompt": "9.1.1",
|
"sudo-prompt": "9.1.1",
|
||||||
"tas-client": "^0.0.950",
|
"tas-client-umd": "^0.1.1",
|
||||||
"v8-inspect-profiler": "^0.0.20",
|
"v8-inspect-profiler": "^0.0.20",
|
||||||
"vscode-nsfw": "1.2.8",
|
"vscode-nsfw": "1.2.8",
|
||||||
"vscode-oniguruma": "1.3.1",
|
"vscode-oniguruma": "1.3.1",
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
"iconv-lite-umd": "0.6.8",
|
"iconv-lite-umd": "0.6.8",
|
||||||
"jschardet": "2.2.1",
|
"jschardet": "2.2.1",
|
||||||
"semver-umd": "^5.5.7",
|
"semver-umd": "^5.5.7",
|
||||||
|
"tas-client-umd": "0.1.1",
|
||||||
"vscode-oniguruma": "1.3.1",
|
"vscode-oniguruma": "1.3.1",
|
||||||
"vscode-textmate": "5.2.0",
|
"vscode-textmate": "5.2.0",
|
||||||
"xterm": "4.10.0-beta.4",
|
"xterm": "4.10.0-beta.4",
|
||||||
|
|
|
@ -17,6 +17,11 @@ semver-umd@^5.5.7:
|
||||||
resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.7.tgz#966beb5e96c7da6fbf09c3da14c2872d6836c528"
|
resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.7.tgz#966beb5e96c7da6fbf09c3da14c2872d6836c528"
|
||||||
integrity sha512-XgjPNlD0J6aIc8xoTN6GQGwWc2Xg0kq8NzrqMVuKG/4Arl6ab1F8+Am5Y/XKKCR+FceFr2yN/Uv5ZJBhRyRqKg==
|
integrity sha512-XgjPNlD0J6aIc8xoTN6GQGwWc2Xg0kq8NzrqMVuKG/4Arl6ab1F8+Am5Y/XKKCR+FceFr2yN/Uv5ZJBhRyRqKg==
|
||||||
|
|
||||||
|
tas-client-umd@0.1.1:
|
||||||
|
version "0.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/tas-client-umd/-/tas-client-umd-0.1.1.tgz#a858ced3d3af5989a505f5b6bc961e4ff33ab1a4"
|
||||||
|
integrity sha512-vWp7WNBL+tMifW3k1HJb9fmmJhvbu+zIYtvQbx5w04hCl8KXuhfc59fu//Cx31WZiKcfTaIw/WPB47hzYGuh8A==
|
||||||
|
|
||||||
vscode-oniguruma@1.3.1:
|
vscode-oniguruma@1.3.1:
|
||||||
version "1.3.1"
|
version "1.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.3.1.tgz#e2383879c3485b19f533ec34efea9d7a2b14be8f"
|
resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.3.1.tgz#e2383879c3485b19f533ec34efea9d7a2b14be8f"
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
'xterm-addon-unicode11': `${window.location.origin}/static/remote/web/node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`,
|
'xterm-addon-unicode11': `${window.location.origin}/static/remote/web/node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`,
|
||||||
'xterm-addon-webgl': `${window.location.origin}/static/remote/web/node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js`,
|
'xterm-addon-webgl': `${window.location.origin}/static/remote/web/node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js`,
|
||||||
'semver-umd': `${window.location.origin}/static/remote/web/node_modules/semver-umd/lib/semver-umd.js`,
|
'semver-umd': `${window.location.origin}/static/remote/web/node_modules/semver-umd/lib/semver-umd.js`,
|
||||||
|
'tas-client-umd': `${window.location.origin}/static/remote/web/node_modules/tas-client-umd/lib/tas-client-umd.js`,
|
||||||
'iconv-lite-umd': `${window.location.origin}/static/remote/web/node_modules/iconv-lite-umd/lib/iconv-lite-umd.js`,
|
'iconv-lite-umd': `${window.location.origin}/static/remote/web/node_modules/iconv-lite-umd/lib/iconv-lite-umd.js`,
|
||||||
'jschardet': `${window.location.origin}/static/remote/web/node_modules/jschardet/dist/jschardet.min.js`,
|
'jschardet': `${window.location.origin}/static/remote/web/node_modules/jschardet/dist/jschardet.min.js`,
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
'xterm-addon-unicode11': `${window.location.origin}/static/node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`,
|
'xterm-addon-unicode11': `${window.location.origin}/static/node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`,
|
||||||
'xterm-addon-webgl': `${window.location.origin}/static/node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js`,
|
'xterm-addon-webgl': `${window.location.origin}/static/node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js`,
|
||||||
'semver-umd': `${window.location.origin}/static/node_modules/semver-umd/lib/semver-umd.js`,
|
'semver-umd': `${window.location.origin}/static/node_modules/semver-umd/lib/semver-umd.js`,
|
||||||
|
'tas-client-umd': `${window.location.origin}/static/node_modules/tas-client-umd/lib/tas-client-umd.js`,
|
||||||
'iconv-lite-umd': `${window.location.origin}/static/node_modules/iconv-lite-umd/lib/iconv-lite-umd.js`,
|
'iconv-lite-umd': `${window.location.origin}/static/node_modules/iconv-lite-umd/lib/iconv-lite-umd.js`,
|
||||||
'jschardet': `${window.location.origin}/static/node_modules/jschardet/dist/jschardet.min.js`,
|
'jschardet': `${window.location.origin}/static/node_modules/jschardet/dist/jschardet.min.js`,
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,15 @@
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import * as platform from 'vs/base/common/platform';
|
||||||
|
import type { IKeyValueStorage, IExperimentationTelemetry, IExperimentationFilterProvider, ExperimentationService as TASClient } from 'tas-client-umd';
|
||||||
|
import { MementoObject, Memento } from 'vs/workbench/common/memento';
|
||||||
|
import { IProductService } from 'vs/platform/product/common/productService';
|
||||||
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
|
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||||
|
import { ITelemetryData } from 'vs/base/common/actions';
|
||||||
|
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||||
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
|
|
||||||
export const ITASExperimentService = createDecorator<ITASExperimentService>('TASExperimentService');
|
export const ITASExperimentService = createDecorator<ITASExperimentService>('TASExperimentService');
|
||||||
|
|
||||||
|
@ -11,3 +19,215 @@ export interface ITASExperimentService {
|
||||||
readonly _serviceBrand: undefined;
|
readonly _serviceBrand: undefined;
|
||||||
getTreatment<T extends string | number | boolean>(name: string): Promise<T | undefined>;
|
getTreatment<T extends string | number | boolean>(name: string): Promise<T | undefined>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const storageKey = 'VSCode.ABExp.FeatureData';
|
||||||
|
const refetchInterval = 0; // no polling
|
||||||
|
|
||||||
|
class MementoKeyValueStorage implements IKeyValueStorage {
|
||||||
|
constructor(private mementoObj: MementoObject) { }
|
||||||
|
|
||||||
|
async getValue<T>(key: string, defaultValue?: T | undefined): Promise<T | undefined> {
|
||||||
|
const value = await this.mementoObj[key];
|
||||||
|
return value || defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
setValue<T>(key: string, value: T): void {
|
||||||
|
this.mementoObj[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExperimentServiceTelemetry implements IExperimentationTelemetry {
|
||||||
|
constructor(private telemetryService: ITelemetryService) { }
|
||||||
|
|
||||||
|
// __GDPR__COMMON__ "VSCode.ABExp.Features" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||||
|
// __GDPR__COMMON__ "abexp.assignmentcontext" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||||
|
setSharedProperty(name: string, value: string): void {
|
||||||
|
this.telemetryService.setExperimentProperty(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
postEvent(eventName: string, props: Map<string, string>): void {
|
||||||
|
const data: ITelemetryData = {};
|
||||||
|
for (const [key, value] of props.entries()) {
|
||||||
|
data[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* __GDPR__
|
||||||
|
"query-expfeature" : {
|
||||||
|
"ABExp.queriedFeature": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
this.telemetryService.publicLog(eventName, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExperimentServiceFilterProvider implements IExperimentationFilterProvider {
|
||||||
|
constructor(
|
||||||
|
private version: string,
|
||||||
|
private appName: string,
|
||||||
|
private machineId: string,
|
||||||
|
private targetPopulation: TargetPopulation
|
||||||
|
) { }
|
||||||
|
|
||||||
|
getFilterValue(filter: string): string | null {
|
||||||
|
switch (filter) {
|
||||||
|
case Filters.ApplicationVersion:
|
||||||
|
return this.version; // productService.version
|
||||||
|
case Filters.Build:
|
||||||
|
return this.appName; // productService.nameLong
|
||||||
|
case Filters.ClientId:
|
||||||
|
return this.machineId;
|
||||||
|
case Filters.Language:
|
||||||
|
return platform.language;
|
||||||
|
case Filters.ExtensionName:
|
||||||
|
return 'vscode-core'; // always return vscode-core for exp service
|
||||||
|
case Filters.TargetPopulation:
|
||||||
|
return this.targetPopulation;
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getFilters(): Map<string, any> {
|
||||||
|
let filters: Map<string, any> = new Map<string, any>();
|
||||||
|
let filterValues = Object.values(Filters);
|
||||||
|
for (let value of filterValues) {
|
||||||
|
filters.set(value, this.getFilterValue(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return filters;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Based upon the official VSCode currently existing filters in the
|
||||||
|
ExP backend for the VSCode cluster.
|
||||||
|
https://experimentation.visualstudio.com/Analysis%20and%20Experimentation/_git/AnE.ExP.TAS.TachyonHost.Configuration?path=%2FConfigurations%2Fvscode%2Fvscode.json&version=GBmaster
|
||||||
|
"X-MSEdge-Market": "detection.market",
|
||||||
|
"X-FD-Corpnet": "detection.corpnet",
|
||||||
|
"X-VSCode–AppVersion": "appversion",
|
||||||
|
"X-VSCode-Build": "build",
|
||||||
|
"X-MSEdge-ClientId": "clientid",
|
||||||
|
"X-VSCode-ExtensionName": "extensionname",
|
||||||
|
"X-VSCode-TargetPopulation": "targetpopulation",
|
||||||
|
"X-VSCode-Language": "language"
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum Filters {
|
||||||
|
/**
|
||||||
|
* The market in which the extension is distributed.
|
||||||
|
*/
|
||||||
|
Market = 'X-MSEdge-Market',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The corporation network.
|
||||||
|
*/
|
||||||
|
CorpNet = 'X-FD-Corpnet',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version of the application which uses experimentation service.
|
||||||
|
*/
|
||||||
|
ApplicationVersion = 'X-VSCode-AppVersion',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insiders vs Stable.
|
||||||
|
*/
|
||||||
|
Build = 'X-VSCode-Build',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client Id which is used as primary unit for the experimentation.
|
||||||
|
*/
|
||||||
|
ClientId = 'X-MSEdge-ClientId',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension header.
|
||||||
|
*/
|
||||||
|
ExtensionName = 'X-VSCode-ExtensionName',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The language in use by VS Code
|
||||||
|
*/
|
||||||
|
Language = 'X-VSCode-Language',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The target population.
|
||||||
|
* This is used to separate internal, early preview, GA, etc.
|
||||||
|
*/
|
||||||
|
TargetPopulation = 'X-VSCode-TargetPopulation',
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TargetPopulation {
|
||||||
|
Team = 'team',
|
||||||
|
Internal = 'internal',
|
||||||
|
Insiders = 'insider',
|
||||||
|
Public = 'public',
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ExperimentService implements ITASExperimentService {
|
||||||
|
_serviceBrand: undefined;
|
||||||
|
private tasClient: Promise<TASClient> | undefined;
|
||||||
|
private static MEMENTO_ID = 'experiment.service.memento';
|
||||||
|
|
||||||
|
private get experimentsEnabled(): boolean {
|
||||||
|
return this.configurationService.getValue('workbench.enableExperiments') === true;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@IProductService private productService: IProductService,
|
||||||
|
@ITelemetryService private telemetryService: ITelemetryService,
|
||||||
|
@IStorageService private storageService: IStorageService,
|
||||||
|
@IConfigurationService private configurationService: IConfigurationService,
|
||||||
|
) {
|
||||||
|
|
||||||
|
if (this.productService.tasConfig && this.experimentsEnabled && this.telemetryService.isOptedIn) {
|
||||||
|
this.tasClient = this.setupTASClient();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getTreatment<T extends string | number | boolean>(name: string): Promise<T | undefined> {
|
||||||
|
if (!this.tasClient) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.experimentsEnabled) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (await this.tasClient).getTreatmentVariable<T>('vscode', name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async setupTASClient(): Promise<TASClient> {
|
||||||
|
const telemetryInfo = await this.telemetryService.getTelemetryInfo();
|
||||||
|
const targetPopulation = telemetryInfo.msftInternal ? TargetPopulation.Internal : (this.productService.quality === 'stable' ? TargetPopulation.Public : TargetPopulation.Insiders);
|
||||||
|
const machineId = telemetryInfo.machineId;
|
||||||
|
const filterProvider = new ExperimentServiceFilterProvider(
|
||||||
|
this.productService.version,
|
||||||
|
this.productService.nameLong,
|
||||||
|
machineId,
|
||||||
|
targetPopulation
|
||||||
|
);
|
||||||
|
|
||||||
|
const memento = new Memento(ExperimentService.MEMENTO_ID, this.storageService);
|
||||||
|
const keyValueStorage = new MementoKeyValueStorage(memento.getMemento(StorageScope.GLOBAL));
|
||||||
|
|
||||||
|
const telemetry = new ExperimentServiceTelemetry(this.telemetryService);
|
||||||
|
|
||||||
|
const tasConfig = this.productService.tasConfig!;
|
||||||
|
const tasClient = new (await import('tas-client-umd')).ExperimentationService({
|
||||||
|
filterProviders: [filterProvider],
|
||||||
|
telemetry: telemetry,
|
||||||
|
storageKey: storageKey,
|
||||||
|
keyValueStorage: keyValueStorage,
|
||||||
|
featuresTelemetryPropertyName: tasConfig.featuresTelemetryPropertyName,
|
||||||
|
assignmentContextTelemetryPropertyName: tasConfig.assignmentContextTelemetryPropertyName,
|
||||||
|
telemetryEventName: tasConfig.telemetryEventName,
|
||||||
|
endpoint: tasConfig.endpoint,
|
||||||
|
refetchInterval: refetchInterval,
|
||||||
|
});
|
||||||
|
|
||||||
|
await tasClient.initializePromise;
|
||||||
|
return tasClient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registerSingleton(ITASExperimentService, ExperimentService, false);
|
||||||
|
|
||||||
|
|
|
@ -1,227 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
import * as platform from 'vs/base/common/platform';
|
|
||||||
import type { IKeyValueStorage, IExperimentationTelemetry, IExperimentationFilterProvider, ExperimentationService as TASClient } from 'tas-client';
|
|
||||||
import { MementoObject, Memento } from 'vs/workbench/common/memento';
|
|
||||||
import { IProductService } from 'vs/platform/product/common/productService';
|
|
||||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
|
||||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
|
||||||
import { ITelemetryData } from 'vs/base/common/actions';
|
|
||||||
import { ITASExperimentService } from 'vs/workbench/services/experiment/common/experimentService';
|
|
||||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
|
||||||
|
|
||||||
const storageKey = 'VSCode.ABExp.FeatureData';
|
|
||||||
const refetchInterval = 0; // no polling
|
|
||||||
|
|
||||||
class MementoKeyValueStorage implements IKeyValueStorage {
|
|
||||||
constructor(private mementoObj: MementoObject) { }
|
|
||||||
|
|
||||||
async getValue<T>(key: string, defaultValue?: T | undefined): Promise<T | undefined> {
|
|
||||||
const value = await this.mementoObj[key];
|
|
||||||
return value || defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
setValue<T>(key: string, value: T): void {
|
|
||||||
this.mementoObj[key] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ExperimentServiceTelemetry implements IExperimentationTelemetry {
|
|
||||||
constructor(private telemetryService: ITelemetryService) { }
|
|
||||||
|
|
||||||
// __GDPR__COMMON__ "VSCode.ABExp.Features" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
|
||||||
// __GDPR__COMMON__ "abexp.assignmentcontext" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
|
||||||
setSharedProperty(name: string, value: string): void {
|
|
||||||
this.telemetryService.setExperimentProperty(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
postEvent(eventName: string, props: Map<string, string>): void {
|
|
||||||
const data: ITelemetryData = {};
|
|
||||||
for (const [key, value] of props.entries()) {
|
|
||||||
data[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* __GDPR__
|
|
||||||
"query-expfeature" : {
|
|
||||||
"ABExp.queriedFeature": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
this.telemetryService.publicLog(eventName, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ExperimentServiceFilterProvider implements IExperimentationFilterProvider {
|
|
||||||
constructor(
|
|
||||||
private version: string,
|
|
||||||
private appName: string,
|
|
||||||
private machineId: string,
|
|
||||||
private targetPopulation: TargetPopulation
|
|
||||||
) { }
|
|
||||||
|
|
||||||
getFilterValue(filter: string): string | null {
|
|
||||||
switch (filter) {
|
|
||||||
case Filters.ApplicationVersion:
|
|
||||||
return this.version; // productService.version
|
|
||||||
case Filters.Build:
|
|
||||||
return this.appName; // productService.nameLong
|
|
||||||
case Filters.ClientId:
|
|
||||||
return this.machineId;
|
|
||||||
case Filters.Language:
|
|
||||||
return platform.language;
|
|
||||||
case Filters.ExtensionName:
|
|
||||||
return 'vscode-core'; // always return vscode-core for exp service
|
|
||||||
case Filters.TargetPopulation:
|
|
||||||
return this.targetPopulation;
|
|
||||||
default:
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getFilters(): Map<string, any> {
|
|
||||||
let filters: Map<string, any> = new Map<string, any>();
|
|
||||||
let filterValues = Object.values(Filters);
|
|
||||||
for (let value of filterValues) {
|
|
||||||
filters.set(value, this.getFilterValue(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
return filters;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Based upon the official VSCode currently existing filters in the
|
|
||||||
ExP backend for the VSCode cluster.
|
|
||||||
https://experimentation.visualstudio.com/Analysis%20and%20Experimentation/_git/AnE.ExP.TAS.TachyonHost.Configuration?path=%2FConfigurations%2Fvscode%2Fvscode.json&version=GBmaster
|
|
||||||
"X-MSEdge-Market": "detection.market",
|
|
||||||
"X-FD-Corpnet": "detection.corpnet",
|
|
||||||
"X-VSCode–AppVersion": "appversion",
|
|
||||||
"X-VSCode-Build": "build",
|
|
||||||
"X-MSEdge-ClientId": "clientid",
|
|
||||||
"X-VSCode-ExtensionName": "extensionname",
|
|
||||||
"X-VSCode-TargetPopulation": "targetpopulation",
|
|
||||||
"X-VSCode-Language": "language"
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum Filters {
|
|
||||||
/**
|
|
||||||
* The market in which the extension is distributed.
|
|
||||||
*/
|
|
||||||
Market = 'X-MSEdge-Market',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The corporation network.
|
|
||||||
*/
|
|
||||||
CorpNet = 'X-FD-Corpnet',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Version of the application which uses experimentation service.
|
|
||||||
*/
|
|
||||||
ApplicationVersion = 'X-VSCode-AppVersion',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insiders vs Stable.
|
|
||||||
*/
|
|
||||||
Build = 'X-VSCode-Build',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Client Id which is used as primary unit for the experimentation.
|
|
||||||
*/
|
|
||||||
ClientId = 'X-MSEdge-ClientId',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension header.
|
|
||||||
*/
|
|
||||||
ExtensionName = 'X-VSCode-ExtensionName',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The language in use by VS Code
|
|
||||||
*/
|
|
||||||
Language = 'X-VSCode-Language',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The target population.
|
|
||||||
* This is used to separate internal, early preview, GA, etc.
|
|
||||||
*/
|
|
||||||
TargetPopulation = 'X-VSCode-TargetPopulation',
|
|
||||||
}
|
|
||||||
|
|
||||||
enum TargetPopulation {
|
|
||||||
Team = 'team',
|
|
||||||
Internal = 'internal',
|
|
||||||
Insiders = 'insider',
|
|
||||||
Public = 'public',
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ExperimentService implements ITASExperimentService {
|
|
||||||
_serviceBrand: undefined;
|
|
||||||
private tasClient: Promise<TASClient> | undefined;
|
|
||||||
private static MEMENTO_ID = 'experiment.service.memento';
|
|
||||||
|
|
||||||
private get experimentsEnabled(): boolean {
|
|
||||||
return this.configurationService.getValue('workbench.enableExperiments') === true;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
@IProductService private productService: IProductService,
|
|
||||||
@ITelemetryService private telemetryService: ITelemetryService,
|
|
||||||
@IStorageService private storageService: IStorageService,
|
|
||||||
@IConfigurationService private configurationService: IConfigurationService,
|
|
||||||
) {
|
|
||||||
|
|
||||||
if (this.productService.tasConfig && this.experimentsEnabled && this.telemetryService.isOptedIn) {
|
|
||||||
this.tasClient = this.setupTASClient();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTreatment<T extends string | number | boolean>(name: string): Promise<T | undefined> {
|
|
||||||
if (!this.tasClient) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.experimentsEnabled) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (await this.tasClient).getTreatmentVariable<T>('vscode', name);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async setupTASClient(): Promise<TASClient> {
|
|
||||||
const telemetryInfo = await this.telemetryService.getTelemetryInfo();
|
|
||||||
const targetPopulation = telemetryInfo.msftInternal ? TargetPopulation.Internal : (this.productService.quality === 'stable' ? TargetPopulation.Public : TargetPopulation.Insiders);
|
|
||||||
const machineId = telemetryInfo.machineId;
|
|
||||||
const filterProvider = new ExperimentServiceFilterProvider(
|
|
||||||
this.productService.version,
|
|
||||||
this.productService.nameLong,
|
|
||||||
machineId,
|
|
||||||
targetPopulation
|
|
||||||
);
|
|
||||||
|
|
||||||
const memento = new Memento(ExperimentService.MEMENTO_ID, this.storageService);
|
|
||||||
const keyValueStorage = new MementoKeyValueStorage(memento.getMemento(StorageScope.GLOBAL));
|
|
||||||
|
|
||||||
const telemetry = new ExperimentServiceTelemetry(this.telemetryService);
|
|
||||||
|
|
||||||
const tasConfig = this.productService.tasConfig!;
|
|
||||||
const tasClient = new (await import('tas-client')).ExperimentationService({
|
|
||||||
filterProviders: [filterProvider],
|
|
||||||
telemetry: telemetry,
|
|
||||||
storageKey: storageKey,
|
|
||||||
keyValueStorage: keyValueStorage,
|
|
||||||
featuresTelemetryPropertyName: tasConfig.featuresTelemetryPropertyName,
|
|
||||||
assignmentContextTelemetryPropertyName: tasConfig.assignmentContextTelemetryPropertyName,
|
|
||||||
telemetryEventName: tasConfig.telemetryEventName,
|
|
||||||
endpoint: tasConfig.endpoint,
|
|
||||||
refetchInterval: refetchInterval,
|
|
||||||
});
|
|
||||||
|
|
||||||
await tasClient.initializePromise;
|
|
||||||
return tasClient;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
registerSingleton(ITASExperimentService, ExperimentService, false);
|
|
||||||
|
|
|
@ -86,6 +86,7 @@ import 'vs/workbench/services/quickinput/browser/quickInputService';
|
||||||
import 'vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService';
|
import 'vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService';
|
||||||
import 'vs/workbench/services/authentication/browser/authenticationService';
|
import 'vs/workbench/services/authentication/browser/authenticationService';
|
||||||
import 'vs/workbench/services/hover/browser/hoverService';
|
import 'vs/workbench/services/hover/browser/hoverService';
|
||||||
|
import 'vs/workbench/services/experiment/common/experimentService';
|
||||||
|
|
||||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||||
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
|
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
|
||||||
|
|
26
yarn.lock
26
yarn.lock
|
@ -1131,13 +1131,6 @@ aws4@^1.8.0:
|
||||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
|
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
|
||||||
integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
|
integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
|
||||||
|
|
||||||
axios@^0.19.0:
|
|
||||||
version "0.19.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
|
|
||||||
integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
|
|
||||||
dependencies:
|
|
||||||
follow-redirects "1.5.10"
|
|
||||||
|
|
||||||
azure-storage@^2.10.2:
|
azure-storage@^2.10.2:
|
||||||
version "2.10.2"
|
version "2.10.2"
|
||||||
resolved "https://registry.yarnpkg.com/azure-storage/-/azure-storage-2.10.2.tgz#3bcabdbf10e72fd0990db81116e49023c4a675b6"
|
resolved "https://registry.yarnpkg.com/azure-storage/-/azure-storage-2.10.2.tgz#3bcabdbf10e72fd0990db81116e49023c4a675b6"
|
||||||
|
@ -2396,7 +2389,7 @@ debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms "2.0.0"
|
ms "2.0.0"
|
||||||
|
|
||||||
debug@3.1.0, debug@=3.1.0:
|
debug@3.1.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||||
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
|
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
|
||||||
|
@ -3578,13 +3571,6 @@ flush-write-stream@^1.0.0, flush-write-stream@^1.0.2:
|
||||||
inherits "^2.0.1"
|
inherits "^2.0.1"
|
||||||
readable-stream "^2.0.4"
|
readable-stream "^2.0.4"
|
||||||
|
|
||||||
follow-redirects@1.5.10:
|
|
||||||
version "1.5.10"
|
|
||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
|
|
||||||
integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
|
|
||||||
dependencies:
|
|
||||||
debug "=3.1.0"
|
|
||||||
|
|
||||||
for-in@^0.1.5:
|
for-in@^0.1.5:
|
||||||
version "0.1.5"
|
version "0.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.5.tgz#007374e2b6d5c67420a1479bdb75a04872b738c4"
|
resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.5.tgz#007374e2b6d5c67420a1479bdb75a04872b738c4"
|
||||||
|
@ -8965,12 +8951,10 @@ tar@^4:
|
||||||
safe-buffer "^5.1.2"
|
safe-buffer "^5.1.2"
|
||||||
yallist "^3.0.2"
|
yallist "^3.0.2"
|
||||||
|
|
||||||
tas-client@^0.0.950:
|
tas-client-umd@^0.1.1:
|
||||||
version "0.0.950"
|
version "0.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/tas-client/-/tas-client-0.0.950.tgz#0fadc684721d5bc6d6af03b09e1ff5a83a5186fc"
|
resolved "https://registry.yarnpkg.com/tas-client-umd/-/tas-client-umd-0.1.1.tgz#a858ced3d3af5989a505f5b6bc961e4ff33ab1a4"
|
||||||
integrity sha512-AvCNjvfouxJyKln+TsobOBO5KmXklL9+FlxrEPlIgaixy1TxCC2v2Vs/MflCiyHlGl+BeIStP4oAVPqo5c0pIA==
|
integrity sha512-vWp7WNBL+tMifW3k1HJb9fmmJhvbu+zIYtvQbx5w04hCl8KXuhfc59fu//Cx31WZiKcfTaIw/WPB47hzYGuh8A==
|
||||||
dependencies:
|
|
||||||
axios "^0.19.0"
|
|
||||||
|
|
||||||
temp@^0.8.3:
|
temp@^0.8.3:
|
||||||
version "0.8.3"
|
version "0.8.3"
|
||||||
|
|
Loading…
Reference in a new issue