-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ECS support infra - Introducing ECS feature flag read call via a comm…
…on module (#778) * ECS skeleton folder * ignore eslint for now * Update client logic and setup way to introduce new feature gates config read * Address nits * Update ECS API call to support more client configs * Make appname generic as well * take the telemetry changes later * update the constant app name for power pages * Update interface class for ecs feature flag filters and request feature config definition parameters * Update interface definitions * remove unused code * cleanup * minor renaming changes * Update src/common/ecs-features/ecsFeatureClient.ts Co-authored-by: Abdelmoumen Bouabdallah <[email protected]> * Update src/common/ecs-features/ecsFeatureClient.ts Co-authored-by: Abdelmoumen Bouabdallah <[email protected]> * Update src/common/ecs-features/constants.ts Co-authored-by: Abdelmoumen Bouabdallah <[email protected]> * Address comments and update functions for extensibility * Call ecs client and make call for loading config * updated path names * update calling and comments * fix test cases * fix auth test cases * fix test * fix test * update for test case --------- Co-authored-by: Abdelmoumen Bouabdallah <[email protected]>
- Loading branch information
1 parent
f8bb0a0
commit bd923c6
Showing
14 changed files
with
278 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/* | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*/ | ||
|
||
export const ECS_REQUEST_URL_TEMPLATE = "https://ecs.office.com/config/v1"; | ||
|
||
export const PowerPagesClientName = 'PortalsMakerExperiences'; // Project name in ECS Portal, Do not change this | ||
export type ProjectTeam = typeof PowerPagesClientName; | ||
export const PowerPagesAppName = 'powerpages-microsoft-com'; // Project name in ECS Portal, Do not change this | ||
export type ProjectName = typeof PowerPagesAppName; | ||
|
||
export const VisualStudioCodeDevInsidersUrl = 'https://insiders.vscode.dev/power/portal'; // VScode dev insiders/pre-prod env | ||
export const VisualStudioCodeDevUrl = 'https://vscode.dev/power/portal'; // VScode dev GA/prod env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/* | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*/ | ||
|
||
import TelemetryReporter from "@vscode/extension-telemetry"; | ||
import { ITelemetry } from "../../client/telemetry/ITelemetry"; | ||
import { createECSRequestURL } from "./ecsFeatureUtil"; | ||
import { ECSFeatureDefinition as ECSFeatureProperties } from "./ecsFeatureProperties"; | ||
import { ECSAPIFeatureFlagFilters } from "./ecsFeatureFlagFilters"; | ||
|
||
export abstract class ECSFeaturesClient { | ||
private static _ecsConfig: Record<string, string | boolean>; | ||
private static _featuresConfig = {}; | ||
|
||
// Initialize ECSFeatureClient - any client config can be fetched with utility function like below | ||
// EnableMultifileVscodeWeb.getConfig().enableMultifileVscodeWeb | ||
public static async init(telemetry: ITelemetry | TelemetryReporter, filters: ECSAPIFeatureFlagFilters, clientName: string) { | ||
if (this._ecsConfig) return; | ||
|
||
const requestURL = createECSRequestURL(filters, clientName); | ||
try { | ||
const response = await fetch(requestURL, { | ||
method: 'GET' | ||
}); | ||
if (!response.ok) { | ||
throw new Error('Request failed'); | ||
} | ||
const result = await response.json(); | ||
// Update telemetry in other PR | ||
// telemetry.sendTelemetryEvent('ECSConfig', {}); | ||
|
||
// Initialize ECS config | ||
this._ecsConfig = result[clientName]; | ||
} catch (error) { | ||
// Log error | ||
// telemetry.sendTelemetryEvent('ECSConfigError', {}); | ||
} | ||
} | ||
|
||
public static getConfig<TConfig extends Record<string, boolean | string>, TeamName extends string>( | ||
feature: ECSFeatureProperties<TConfig, TeamName> | ||
) { | ||
if (Object.keys(this._featuresConfig).length === 0) { | ||
this._featuresConfig = this._ecsConfig && feature.extractECSFeatureFlagConfig?.(this._ecsConfig as TConfig); | ||
} | ||
|
||
return Object.keys(this._featuresConfig).length === 0 ? feature.fallback : this._featuresConfig; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*/ | ||
|
||
export interface ECSAPIFeatureFlagFilters { | ||
/** | ||
* Application AppName | ||
* @example powerpages-microsoft-com | ||
*/ | ||
AppName: string; | ||
|
||
/** The AAD user object ID or MSA. */ | ||
UserID: string; | ||
|
||
/** The AAD tenant object ID. */ | ||
TenantID: string; | ||
|
||
/** Unique Dataverse Environment ID */ | ||
EnvID: string; | ||
|
||
/** | ||
* Deployment region | ||
* @example test, preview, prod | ||
*/ | ||
Region: string; | ||
|
||
// TBD - more API call filters to be added later | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/* | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*/ | ||
|
||
import { PowerPagesClientName } from './constants'; | ||
import { getFeatureConfigs } from './ecsFeatureUtil'; | ||
|
||
export const { | ||
feature: EnableMultifileVscodeWeb | ||
} = getFeatureConfigs({ | ||
teamName: PowerPagesClientName, | ||
description: 'Enable multiple file view in Visual Studio Code Web', | ||
fallback: { | ||
enableMultifileVscodeWeb: false, | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/* | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*/ | ||
|
||
/** | ||
* Interface representing a Feature config in ECS. | ||
*/ | ||
export interface ECSFeatureDefinition<TConfig extends Record<string, string | boolean>, TeamName extends string> { | ||
/** | ||
* Name of the Team owning the feature. Must match the "clientTeam" name configured in ECS. | ||
*/ | ||
teamName: TeamName; | ||
|
||
/** | ||
* Fallback config to be used while loading or if configs are unavailable. | ||
*/ | ||
fallback: TConfig; | ||
|
||
/** | ||
* Brief description of the feature (used for tracking/cleanup purposes) | ||
*/ | ||
description?: string; | ||
|
||
/** | ||
* Callback to extract the Feature-specific config from the Team config. | ||
* @param config overall config for the Team. | ||
*/ | ||
extractECSFeatureFlagConfig<TTeamConfig extends TConfig>(config: TTeamConfig): Partial<TConfig>; | ||
} | ||
|
||
export type ECSFeatureInfo<TConfig extends Record<string, boolean | string>, TeamName extends string> = Omit< | ||
ECSFeatureDefinition<TConfig, TeamName>, | ||
'extractECSFeatureFlagConfig' | ||
>; | ||
|
||
/** | ||
* Creates a Feature object based on the feature definition that includes fallback flags and the team owning the feature. | ||
* @param featureInfo Feature definition specifying the fallback flags and the team owning the feature. | ||
*/ | ||
export function createECSFeatureDefinition<TConfig extends Record<string, boolean | string>, TeamName extends string>( | ||
featureInfo: ECSFeatureInfo<TConfig, TeamName> | ||
): ECSFeatureDefinition<TConfig, TeamName> { | ||
return { | ||
...featureInfo, | ||
extractECSFeatureFlagConfig: (config) => extractECSFeatureFlagConfig(config, Object.keys(featureInfo.fallback)), | ||
}; | ||
} | ||
|
||
/** | ||
* Extracts the feature-specific config, based on the provided keys, from the overall Project Team config | ||
* @param teamConfig the overall config object for the Project Team | ||
* @param keys property names to extract from the Project Team config | ||
*/ | ||
function extractECSFeatureFlagConfig<TConfig extends Record<string, boolean | string>, TeamConfig extends TConfig>( | ||
teamConfig: TeamConfig, | ||
keys: (keyof TConfig)[] | ||
): Partial<TConfig> { | ||
const config: Partial<TConfig> = {}; | ||
|
||
for (const key of keys) { | ||
if (typeof teamConfig[key] !== 'undefined') { | ||
config[key] = teamConfig[key]; | ||
} | ||
} | ||
|
||
return config; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*/ | ||
|
||
import { PowerPagesClientName, ECS_REQUEST_URL_TEMPLATE } from "./constants"; | ||
import { ECSFeaturesClient } from "./ecsFeatureClient"; | ||
import { ECSAPIFeatureFlagFilters } from "./ecsFeatureFlagFilters"; | ||
import { ECSFeatureDefinition, ECSFeatureInfo, createECSFeatureDefinition } from "./ecsFeatureProperties"; | ||
|
||
export function createECSRequestURL(filters: ECSAPIFeatureFlagFilters, clientName = PowerPagesClientName): string { | ||
const queryParams: { [key: string]: string } = { | ||
AppName: filters.AppName, | ||
EnvironmentID: filters.EnvID, | ||
UserID: filters.UserID, | ||
TenantID: filters.TenantID, | ||
region: filters.Region | ||
}; | ||
|
||
const queryString = Object.keys(queryParams) | ||
.map(key => `${key}=${encodeURIComponent(queryParams[key])}`) | ||
.join('&'); | ||
|
||
return `${ECS_REQUEST_URL_TEMPLATE}/${clientName}/1.0.0.0?${queryString}`; | ||
} | ||
|
||
export function getFeatureConfigs<TConfig extends Record<string, string | boolean>, TeamName extends string>(featureInfo: ECSFeatureInfo<TConfig, TeamName>) { | ||
type EnhancedFeature = ECSFeatureDefinition<TConfig, TeamName> & { | ||
getConfig: () => Partial<TConfig>; | ||
}; | ||
|
||
const feature = createECSFeatureDefinition(featureInfo) as EnhancedFeature; | ||
feature.getConfig = () => ECSFeaturesClient.getConfig(feature); | ||
|
||
return { | ||
feature: feature, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.