-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Arnold Trakhtenberg
authored
Jan 6, 2020
1 parent
60bc966
commit 3b5e6d7
Showing
14 changed files
with
1,007 additions
and
368 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
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,57 @@ | ||
import * as rp from 'request-promise-native'; | ||
import * as url from 'url'; | ||
|
||
import { Configuration } from './configuration'; | ||
import { Resource, Project, Environment, Flag } from './models'; | ||
|
||
// LaunchDarklyAPI is a wrapper around request-promise-native for requesting data from LaunchDarkly's REST API. The caller is expected to catch all exceptions. | ||
export class LaunchDarklyAPI { | ||
private readonly config: Configuration; | ||
|
||
constructor(config: Configuration) { | ||
this.config = config; | ||
} | ||
|
||
async getAccount() { | ||
const options = this.createOptions('account'); | ||
const account = await rp(options); | ||
return JSON.parse(account); | ||
} | ||
|
||
async getProjects(): Promise<Array<Project>> { | ||
const options = this.createOptions('projects'); | ||
const data = await rp(options); | ||
const projects = JSON.parse(data).items; | ||
projects.forEach((proj: Project) => { | ||
proj.environments = proj.environments.sort(sortNameCaseInsensitive); | ||
return proj; | ||
}); | ||
return projects.sort(sortNameCaseInsensitive); | ||
} | ||
|
||
async getEnvironment(projectKey: string, envKey: string): Promise<Environment> { | ||
const options = this.createOptions(`projects/${projectKey}/environments/${envKey}`); | ||
const data = await rp(options); | ||
return JSON.parse(data); | ||
} | ||
|
||
async getFeatureFlag(projectKey: string, flagKey: string, envKey?: string): Promise<Flag> { | ||
const envParam = envKey ? '?env=' + envKey : ''; | ||
const options = this.createOptions(`flags/${projectKey}/${flagKey + envParam}`); | ||
const data = await rp(options); | ||
return JSON.parse(data); | ||
} | ||
|
||
private createOptions(path: string) { | ||
return { | ||
url: url.resolve(this.config.baseUri, `api/v2/${path}`), | ||
headers: { | ||
Authorization: this.config.accessToken, | ||
}, | ||
}; | ||
} | ||
} | ||
|
||
const sortNameCaseInsensitive = (a: Resource, b: Resource) => { | ||
return a.name.toLowerCase().localeCompare(b.name.toLowerCase()); | ||
}; |
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 |
---|---|---|
@@ -1,70 +1,82 @@ | ||
import * as vscode from 'vscode'; | ||
import { WorkspaceConfiguration, workspace, ExtensionContext } from 'vscode'; | ||
|
||
export const DEFAULT_BASE_URI = 'https://app.launchdarkly.com'; | ||
export const DEFAULT_STREAM_URI = 'https://stream.launchdarkly.com'; | ||
const package_json = require('../package.json'); | ||
|
||
export interface IConfiguration { | ||
/** | ||
* Your LaunchDarkly API access token with reader-level permissions. Required. | ||
*/ | ||
accessToken: string; | ||
const DEFAULT_BASE_URI = 'https://app.launchdarkly.com'; | ||
const DEFAULT_STREAM_URI = 'https://stream.launchdarkly.com'; | ||
|
||
/** | ||
* Your LaunchDarkly SDK key. Required. | ||
*/ | ||
sdkKey: string; | ||
export class Configuration { | ||
private readonly ctx: ExtensionContext; | ||
accessToken = ''; | ||
sdkKey = ''; | ||
project = ''; | ||
env = ''; | ||
enableHover = true; | ||
enableAutocomplete = true; | ||
baseUri = DEFAULT_BASE_URI; | ||
streamUri = DEFAULT_STREAM_URI; | ||
|
||
/** | ||
* Your LaunchDarkly project key, should match the provided SDK key. Required. | ||
*/ | ||
project: string; | ||
constructor(ctx: ExtensionContext) { | ||
this.ctx = ctx; | ||
this.reload(); | ||
} | ||
|
||
/** | ||
* Your LaunchDarkly environment key, should match the provided SDK key. | ||
*/ | ||
env: string; | ||
reload() { | ||
const config = workspace.getConfiguration('launchdarkly'); | ||
for (const option in this) { | ||
if (option === 'ctx') { | ||
continue; | ||
} | ||
this[option] = config.get(option); | ||
} | ||
|
||
/** | ||
* Enables flag info to be displayed on hover of a valid flag key. | ||
*/ | ||
enableHover: boolean; | ||
// If accessToken is configured in state, use it. Otherwise, fall back to the legacy access token. | ||
this.accessToken = this.getState('accessToken') || this.accessToken; | ||
} | ||
|
||
/** | ||
* Enable flag key autocompletion. | ||
*/ | ||
enableAutocomplete: boolean; | ||
async update(key: string, value: string | boolean, global: boolean) { | ||
if (typeof this[key] !== typeof value) { | ||
return; | ||
} | ||
|
||
/** | ||
* The LaunchDarkly base uri to be used. Optional. | ||
*/ | ||
baseUri: string; | ||
let config: WorkspaceConfiguration = workspace.getConfiguration('launchdarkly'); | ||
if (key === 'accessToken') { | ||
const ctxState = global ? this.ctx.globalState : this.ctx.workspaceState; | ||
await ctxState.update(key, value); | ||
await config.update(key, '', global); | ||
return; | ||
} | ||
|
||
/** | ||
* The LaunchDarkly stream uri to be used. Optional. | ||
*/ | ||
streamUri: string; | ||
} | ||
await config.update(key, value, global); | ||
config = workspace.getConfiguration('launchdarkly'); | ||
|
||
class Configuration implements IConfiguration { | ||
constructor() { | ||
this.reload(); | ||
this[key] = value; | ||
process.nextTick(function() {}); | ||
} | ||
|
||
reload() { | ||
let config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration('launchdarkly'); | ||
for (const option in this) { | ||
this[option] = config[option]; | ||
validate(): string { | ||
const version = package_json.version; | ||
const ctx = this.ctx; | ||
ctx.globalState.update('version', undefined); | ||
const storedVersion = ctx.globalState.get('version'); | ||
|
||
if (version !== storedVersion) { | ||
ctx.globalState.update('version', version); | ||
} | ||
|
||
const legacyConfiguration = !!this.sdkKey; | ||
if (legacyConfiguration && !ctx.globalState.get('legacyNotificationDismissed')) { | ||
return 'legacy'; | ||
} | ||
|
||
// Only recommend configuring the extension on install and update | ||
const configured = !!this.accessToken; | ||
if (version != storedVersion && !configured) { | ||
return 'unconfigured'; | ||
} | ||
} | ||
|
||
accessToken = ''; | ||
sdkKey = ''; | ||
project = ''; | ||
env = ''; | ||
enableHover = true; | ||
enableAutocomplete = true; | ||
baseUri = DEFAULT_BASE_URI; | ||
streamUri = DEFAULT_STREAM_URI; | ||
getState(key: string): string { | ||
return this.ctx.workspaceState.get(key) || this.ctx.globalState.get(key); | ||
} | ||
} | ||
|
||
export const configuration = new Configuration(); |
Oops, something went wrong.