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:
SteVen Batten 2020-09-18 10:00:39 -07:00 committed by GitHub
parent 50610f085d
commit 92a30ed265
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 238 additions and 251 deletions

View file

@ -522,6 +522,7 @@
"vscode-oniguruma",
"iconv-lite-umd",
"semver-umd",
"tas-client-umd",
"jschardet"
]
},

View file

@ -348,7 +348,7 @@
},
{
// Reason: The license cannot be found by the tool due to access controls on the repository
"name": "tas-client",
"name": "tas-client-umd",
"fullLicenseText": [
"MIT License",
"Copyright (c) 2020 - present Microsoft Corporation",

View file

@ -63,7 +63,7 @@
"semver-umd": "^5.5.7",
"spdlog": "^0.11.1",
"sudo-prompt": "9.1.1",
"tas-client": "^0.0.950",
"tas-client-umd": "^0.1.1",
"v8-inspect-profiler": "^0.0.20",
"vscode-nsfw": "1.2.8",
"vscode-oniguruma": "1.3.1",

View file

@ -5,6 +5,7 @@
"iconv-lite-umd": "0.6.8",
"jschardet": "2.2.1",
"semver-umd": "^5.5.7",
"tas-client-umd": "0.1.1",
"vscode-oniguruma": "1.3.1",
"vscode-textmate": "5.2.0",
"xterm": "4.10.0-beta.4",

View file

@ -17,6 +17,11 @@ semver-umd@^5.5.7:
resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.7.tgz#966beb5e96c7da6fbf09c3da14c2872d6836c528"
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:
version "1.3.1"
resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.3.1.tgz#e2383879c3485b19f533ec34efea9d7a2b14be8f"

View file

@ -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-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`,
'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`,
'jschardet': `${window.location.origin}/static/remote/web/node_modules/jschardet/dist/jschardet.min.js`,
}

View file

@ -43,6 +43,7 @@
'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`,
'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`,
'jschardet': `${window.location.origin}/static/node_modules/jschardet/dist/jschardet.min.js`,
}

View file

@ -3,7 +3,15 @@
* 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');
@ -11,3 +19,215 @@ export interface ITASExperimentService {
readonly _serviceBrand: 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-VSCodeAppVersion": "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);

View file

@ -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-VSCodeAppVersion": "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);

View file

@ -86,6 +86,7 @@ import 'vs/workbench/services/quickinput/browser/quickInputService';
import 'vs/workbench/services/userDataSync/browser/userDataSyncWorkbenchService';
import 'vs/workbench/services/authentication/browser/authenticationService';
import 'vs/workbench/services/hover/browser/hoverService';
import 'vs/workbench/services/experiment/common/experimentService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';

View file

@ -1131,13 +1131,6 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
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:
version "2.10.2"
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:
ms "2.0.0"
debug@3.1.0, debug@=3.1.0:
debug@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
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"
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:
version "0.1.5"
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"
yallist "^3.0.2"
tas-client@^0.0.950:
version "0.0.950"
resolved "https://registry.yarnpkg.com/tas-client/-/tas-client-0.0.950.tgz#0fadc684721d5bc6d6af03b09e1ff5a83a5186fc"
integrity sha512-AvCNjvfouxJyKln+TsobOBO5KmXklL9+FlxrEPlIgaixy1TxCC2v2Vs/MflCiyHlGl+BeIStP4oAVPqo5c0pIA==
dependencies:
axios "^0.19.0"
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==
temp@^0.8.3:
version "0.8.3"