From a63c2c5a17703cc8524ccb88589d9572d5c260b3 Mon Sep 17 00:00:00 2001 From: Bhargav Nookala Date: Tue, 3 Jul 2018 17:33:35 -0700 Subject: [PATCH] Adding stricter tslint rules (#274) * Adding stricter tslint rules * TSLint auto-fixing pass * Manual fixes for stuff TSLint couldnt fix --- package.json | 2 +- src/components/clusterprovider/azure/azure.ts | 13 +- .../azure/azureclusterprovider.ts | 10 +- .../clusterprovider/clusterproviderserver.ts | 1 - src/components/clusterprovider/common/form.ts | 1 - .../minikube/minikubeclusterprovider.ts | 6 +- src/components/git/git.ts | 1 - src/components/installer/installer.ts | 3 +- src/components/kubectl/dashboard.ts | 12 +- src/components/kubectl/namespace.ts | 49 +++++ src/components/kubectl/port-forward.ts | 9 +- src/configMap.ts | 22 +-- src/debug/debugProvider.ts | 3 - src/debug/debugSession.ts | 13 +- src/docker/dockerUtils.ts | 5 +- src/docker/dockerfileParser.ts | 14 +- src/draft/debugDebug.ts | 31 ++-- src/draft/draft.ts | 14 +- src/draft/draftConfigurationProvider.ts | 12 +- src/draft/draftRuntime.ts | 33 ++-- src/explainer.ts | 10 +- src/explorer.ts | 25 ++- src/extension.ts | 174 ++++++++---------- src/extensionUtils.ts | 2 +- src/helm.completionProvider.ts | 55 ++---- src/helm.documentProvider.ts | 24 ++- src/helm.exec.ts | 72 ++++---- src/helm.funcmap.ts | 28 +-- src/helm.hoverProvider.ts | 45 +++-- src/helm.requirementsCodeLens.ts | 10 +- src/helm.resources.ts | 28 +-- src/hostutils.ts | 1 - src/kubeNamespace.ts | 38 ---- src/kubeconfig.ts | 2 - src/kubectl.ts | 8 +- src/kubectlUtils.ts | 18 +- src/kuberesources.virtualfs.ts | 4 +- src/logger.ts | 6 +- src/schema-formatting.ts | 2 +- src/shell.ts | 6 +- src/telemetry-helper.ts | 1 - src/telemetry.ts | 4 +- src/wizard.ts | 1 - src/yaml-support/yaml-locator.ts | 18 +- src/yaml-support/yaml-schema.ts | 31 ++-- src/yaml-support/yaml-snippet.ts | 7 +- src/yaml-support/yaml-util.ts | 8 +- test/draft.test.ts | 26 +-- test/explorer.test.ts | 10 +- test/kubectl.test.ts | 49 +++-- tslint.json | 20 ++ 51 files changed, 462 insertions(+), 525 deletions(-) create mode 100644 src/components/kubectl/namespace.ts delete mode 100644 src/kubeNamespace.ts diff --git a/package.json b/package.json index 9a20dfb94..acec1f78d 100644 --- a/package.json +++ b/package.json @@ -562,7 +562,7 @@ }, { "command": "extension.vsKubernetesUseNamespace", - "title": "Set as Current Namespace", + "title": "Use Namespace", "category": "Kubernetes" }, { diff --git a/src/components/clusterprovider/azure/azure.ts b/src/components/clusterprovider/azure/azure.ts index 289926170..8d69e5960 100644 --- a/src/components/clusterprovider/azure/azure.ts +++ b/src/components/clusterprovider/azure/azure.ts @@ -4,7 +4,7 @@ import * as vscode from 'vscode'; import { Shell } from '../../../shell'; import { FS } from '../../../fs'; import { ActionResult, fromShellJson, fromShellExitCodeAndStandardError, fromShellExitCodeOnly, Diagnostic } from '../../../wizard'; -import { Errorable, succeeded, failed } from '../../../errorable'; +import { Errorable, failed } from '../../../errorable'; import * as compareVersions from 'compare-versions'; import { sleep } from '../../../sleep'; @@ -123,7 +123,7 @@ export async function getClusterList(context: Context, subscription: string, clu } async function listClustersAsync(context: Context, clusterType: string): Promise> { - let cmd = getListClustersCommand(context, clusterType); + const cmd = getListClustersCommand(context, clusterType); const sr = await context.shell.exec(cmd); return fromShellJson(sr); @@ -137,7 +137,7 @@ function listClustersFilter(clusterType: string): string { } function getListClustersCommand(context: Context, clusterType: string): string { - let filter = listClustersFilter(clusterType); + const filter = listClustersFilter(clusterType); let query = `[${filter}].{name:name,resourceGroup:resourceGroup}`; if (context.shell.isUnix()) { query = `'${query}'`; @@ -154,6 +154,7 @@ async function listLocations(context: Context): Promise> { const sr = await context.shell.exec(`az account list-locations --query ${query} -ojson`); return fromShellJson(sr, (response) => { + /* tslint:disable-next-line:prefer-const */ let locations: any = {}; for (const r of response) { locations[r.name] = r.displayName; @@ -242,7 +243,7 @@ async function ensureResourceGroupAsync(context: Context, resourceGroupName: str async function execCreateClusterCmd(context: Context, options: any): Promise> { const clusterCmd = getClusterCommand(options.clusterType); let createCmd = `az ${clusterCmd} create -n "${options.metadata.clusterName}" -g "${options.metadata.resourceGroupName}" -l "${options.metadata.location}" --generate-ssh-keys --no-wait `; - if (clusterCmd == 'acs') { + if (clusterCmd === 'acs') { createCmd = createCmd + `--agent-count ${options.agentSettings.count} --agent-vm-size "${options.agentSettings.vmSize}" -t Kubernetes`; } else { createCmd = createCmd + `--node-count ${options.agentSettings.count} --node-vm-size "${options.agentSettings.vmSize}"`; @@ -254,10 +255,6 @@ async function execCreateClusterCmd(context: Context, options: any): Promise> { - const description = ` - Created ${options.clusterType} cluster ${options.metadata.clusterName} in ${options.metadata.resourceGroupName} with ${options.agentSettings.count} agents. - `; - const login = await setSubscriptionAsync(context, options.subscription); if (!login.succeeded) { return { diff --git a/src/components/clusterprovider/azure/azureclusterprovider.ts b/src/components/clusterprovider/azure/azureclusterprovider.ts index 0420009a5..dddca7b5f 100644 --- a/src/components/clusterprovider/azure/azureclusterprovider.ts +++ b/src/components/clusterprovider/azure/azureclusterprovider.ts @@ -41,8 +41,8 @@ export async function init(registry: clusterproviderregistry.ClusterProviderRegi wizardServer.get('/configure', (req, resp, n) => htmlServer.handleGetConfigure(req, resp, n)); wizardServer.post('/configure', (req, resp, n) => htmlServer.handlePostConfigure(req, resp, n)); - registry.register({id: 'aks', displayName: "Azure Kubernetes Service", port: wizardPort, supportedActions: ['create','configure']}); - registry.register({id: 'acs', displayName: "Azure Container Service", port: wizardPort, supportedActions: ['create','configure']}); + registry.register({id: 'aks', displayName: "Azure Kubernetes Service", port: wizardPort, supportedActions: ['create', 'configure']}); + registry.register({id: 'acs', displayName: "Azure Container Service", port: wizardPort, supportedActions: ['create', 'configure']}); } } @@ -77,7 +77,7 @@ class HtmlServer { const html = await handler(request.query["step"], this.context, requestData); response.contentType = 'text/html'; - response.send("" + html + ""); + response.send(`${html}`); next(); } @@ -229,7 +229,7 @@ async function promptForAgentSettings(previousData: any, context: azure.Context) } const defaultSize = "Standard_D2_v2"; - const options = vmSizes.result.map((s) => ``).join('\n'); + const options = vmSizes.result.map((s) => ``).join('\n'); return formPage({ stepId: 'PromptForAgentSettings', @@ -416,7 +416,7 @@ ${styles()} // Utility helpers function formatCluster(cluster: any): string { - return cluster.resourceGroup + '/' + cluster.name; + return `${cluster.resourceGroup}/${cluster.name}`; } function parseCluster(encoded: string): azure.ClusterInfo { diff --git a/src/components/clusterprovider/clusterproviderserver.ts b/src/components/clusterprovider/clusterproviderserver.ts index badd7cbf0..b76ff3d2a 100644 --- a/src/components/clusterprovider/clusterproviderserver.ts +++ b/src/components/clusterprovider/clusterproviderserver.ts @@ -2,7 +2,6 @@ import * as restify from 'restify'; import * as portfinder from 'portfinder'; import * as clusterproviderregistry from './clusterproviderregistry'; import { styles, script, waitScript } from '../../wizard'; -import TelemetryReporter from 'vscode-extension-telemetry'; import { reporter } from '../../telemetry'; let cpServer: restify.Server; diff --git a/src/components/clusterprovider/common/form.ts b/src/components/clusterprovider/common/form.ts index 5229a763e..38a8bcec7 100644 --- a/src/components/clusterprovider/common/form.ts +++ b/src/components/clusterprovider/common/form.ts @@ -37,4 +37,3 @@ export function formPage(fd: FormData): string { `; } - diff --git a/src/components/clusterprovider/minikube/minikubeclusterprovider.ts b/src/components/clusterprovider/minikube/minikubeclusterprovider.ts index dc2ec67b0..b3a7b6609 100644 --- a/src/components/clusterprovider/minikube/minikubeclusterprovider.ts +++ b/src/components/clusterprovider/minikube/minikubeclusterprovider.ts @@ -5,7 +5,7 @@ import * as clusterproviderregistry from '../clusterproviderregistry'; import { styles, formStyles, waitScript, ActionResult, Diagnostic, fromShellExitCodeOnly } from '../../../wizard'; import { propagationFields, formPage } from '../common/form'; import { refreshExplorer } from '../common/explorer'; -import { Errorable, succeeded, failed, Failed, Succeeded } from '../../../errorable'; +import { succeeded, Failed } from '../../../errorable'; import { Shell } from '../../../shell'; export interface Context { @@ -41,7 +41,7 @@ export async function init(registry: clusterproviderregistry.ClusterProviderRegi minikubeWizardServer.get('/configure', (req, resp, n) => htmlServer.handleGetConfigure(req, resp, n)); minikubeWizardServer.post('/configure', (req, resp, n) => htmlServer.handlePostConfigure(req, resp, n)); - registry.register({id: 'minikube', displayName: "Minikube local cluster", port: port, supportedActions: ['create','configure']}); + registry.register({id: 'minikube', displayName: "Minikube local cluster", port: port, supportedActions: ['create', 'configure']}); } } @@ -75,7 +75,7 @@ class HtmlServer { async handleRequest(handler: HtmlRequestHandler, request: restify.Request, requestData: any, response: restify.Response, next: restify.Next) { const html = await handler(request.query["step"], requestData, this.context); response.contentType = 'text/html'; - response.send("" + html + ""); + response.send(`${html}`); next(); } diff --git a/src/components/git/git.ts b/src/components/git/git.ts index 01983e623..f220f53c4 100644 --- a/src/components/git/git.ts +++ b/src/components/git/git.ts @@ -26,4 +26,3 @@ export class Git { return { succeeded: false, error: [ sr.stderr ] }; } } - diff --git a/src/components/installer/installer.ts b/src/components/installer/installer.ts index eef1c3676..d8bbda3ec 100644 --- a/src/components/installer/installer.ts +++ b/src/components/installer/installer.ts @@ -9,7 +9,6 @@ import * as tmp from 'tmp'; import * as vscode from 'vscode'; import { Shell, Platform } from '../../shell'; import { Errorable, failed, succeeded } from '../../errorable'; -import { exec } from 'child_process'; export async function installKubectl(shell: Shell): Promise> { const tool = 'kubectl'; @@ -137,7 +136,7 @@ async function downloadToTempFile(sourceUrl: string): Promise> async function downloadTo(sourceUrl: string, destinationFile: string): Promise> { try { - const buffer = await download(sourceUrl, path.dirname(destinationFile), { filename: path.basename(destinationFile) }); + await download(sourceUrl, path.dirname(destinationFile), { filename: path.basename(destinationFile) }); return { succeeded: true, result: null }; } catch (e) { return { succeeded: false, error: [e.message] }; diff --git a/src/components/kubectl/dashboard.ts b/src/components/kubectl/dashboard.ts index 7617978e0..582f5eb7a 100644 --- a/src/components/kubectl/dashboard.ts +++ b/src/components/kubectl/dashboard.ts @@ -11,7 +11,6 @@ import { Kubectl } from '../../kubectl'; import { Node, KubernetesCollection, Pod } from '../../kuberesources.objectmodel'; import { failed } from '../../errorable'; - const KUBE_DASHBOARD_URL = "http://localhost:8001/ui/"; const TERMINAL_NAME = "Kubernetes Dashboard"; const PROXY_OUTPUT_FILE = resolve(__dirname, 'proxy.out'); @@ -31,18 +30,17 @@ async function isAKSCluster (kubectl: Kubectl): Promise { if (failed(nodes)) { return false; } - const nodeItems = nodes.result.items; - const nodeCount = nodeItems.length; - for (let nodeItem of nodeItems) { - let isAKSNode = _isNodeAKS(nodeItem); + const nodeItems = nodes.result.items; + for (const nodeItem of nodeItems) { + const isAKSNode = _isNodeAKS(nodeItem); if (!isAKSNode) { return false; } } - return true; + return true; } function _isNodeAKS(node: Node): boolean { @@ -125,7 +123,7 @@ export async function dashboardKubernetes (kubectl: Kubectl): Promise { } // Read kubectl proxy's stdout as a stream. - const proxyStream = createReadStream( + createReadStream( PROXY_OUTPUT_FILE, {encoding: 'utf8'} ).on('data', onStreamData); diff --git a/src/components/kubectl/namespace.ts b/src/components/kubectl/namespace.ts new file mode 100644 index 000000000..1d520384f --- /dev/null +++ b/src/components/kubectl/namespace.ts @@ -0,0 +1,49 @@ +import { refreshExplorer } from '../clusterprovider/common/explorer'; +import { promptKindName } from '../../extension'; +import { host } from '../../host'; +import * as kubectlUtils from '../../kubectlUtils'; +import * as kuberesources from '../../kuberesources'; +import * as explorer from '../../explorer'; +import { Kubectl } from '../../kubectl'; + +export async function useNamespaceKubernetes(kubectl: Kubectl, explorerNode: explorer.KubernetesObject) { + if (explorerNode) { + if (await kubectlUtils.switchNamespace(kubectl, explorerNode.id)) { + refreshExplorer(); + host.showInformationMessage(`Switched to namespace ${explorerNode.id}`); + return; + } + } + + const currentNS = await kubectlUtils.currentNamespace(kubectl); + promptKindName( + [kuberesources.allKinds.namespace], + undefined, + { + prompt: 'What namespace do you want to use?', + placeHolder: 'Enter the namespace to switch to or press enter to select from available list', + filterNames: [currentNS] + }, + switchToNamespace.bind(this, kubectl, currentNS) + ); +} + +async function switchToNamespace (kubectl: Kubectl, currentNS: string, resource: string) { + if (!resource) { + return; + } + + let toSwitchNamespace = resource; + // resource will be of format /, when picked up from the quickpick + if (toSwitchNamespace.lastIndexOf('/') !== -1) { + toSwitchNamespace = toSwitchNamespace.substring(toSwitchNamespace.lastIndexOf('/') + 1); + } + + // Switch if an only if the currentNS and toSwitchNamespace are different + if (toSwitchNamespace && currentNS !== toSwitchNamespace) { + if (await kubectlUtils.switchNamespace(kubectl, toSwitchNamespace)) { + refreshExplorer(); + host.showInformationMessage(`Switched to namespace ${toSwitchNamespace}`); + } + } +} diff --git a/src/components/kubectl/port-forward.ts b/src/components/kubectl/port-forward.ts index f7b52f4c1..13a4e271c 100644 --- a/src/components/kubectl/port-forward.ts +++ b/src/components/kubectl/port-forward.ts @@ -29,7 +29,6 @@ interface PodFromDocument { readonly namespace?: string; } - type PortForwardFindPodsResult = PodFromDocument | FindPodsResult; function isFindResultFromDocument(obj: PortForwardFindPodsResult): obj is PodFromDocument { @@ -130,10 +129,10 @@ async function promptForPort (): Promise { * @returns A ValidationResult object describing the first error found. */ function validatePortMapping (portMapping: string): ValidationResult { - let portPairs = portMapping.split(' '); + const portPairs = portMapping.split(' '); const validationResults: ValidationResult[] = portPairs.map(validatePortPair); - return validationResults.find((result) => result.valid === false ); + return validationResults.find((result) => !result.valid ); } /** @@ -143,7 +142,7 @@ function validatePortMapping (portMapping: string): ValidationResult { */ function validatePortPair (portPair: string): ValidationResult { let localPort, targetPort; - let splitMapping = portPair.split(':'); + const splitMapping = portPair.split(':'); // User provided only the target port if (!portPair.includes(':') && Number(portPair)) { @@ -220,7 +219,7 @@ function buildPortPair(portPair: string): PortMapping { * Checks the open document and returns an object describing the Pod, if it can find one */ async function findPortForwardablePods (): Promise { - let kindFromEditor = tryFindKindNameFromEditor(); + const kindFromEditor = tryFindKindNameFromEditor(); // Find the pod type from the open editor. if (succeeded(kindFromEditor)) { diff --git a/src/configMap.ts b/src/configMap.ts index bc6528fd4..5e99adc7a 100644 --- a/src/configMap.ts +++ b/src/configMap.ts @@ -1,9 +1,7 @@ import * as vscode from 'vscode'; import { basename } from 'path'; import { fs } from './fs'; -import { shell } from './shell'; -import { host } from './host'; -import { create as kubectlCreate, Kubectl } from './kubectl'; +import { Kubectl } from './kubectl'; import { currentNamespace, DataHolder } from './kubectlUtils'; import { deleteMessageItems, overwriteMessageItems } from './extension'; import { KubernetesFileObject, KubernetesDataHolderResource, KubernetesExplorer } from './explorer'; @@ -23,12 +21,12 @@ export class ConfigMapTextProvider implements vscode.TextDocumentContentProvider } export function loadConfigMapData(obj: KubernetesFileObject) { - let encoded_data = obj.configData[obj.id]; - if (obj.resource == allKinds.configMap.abbreviation) { - encoded_data = Buffer.from(obj.configData[obj.id]).toString('base64'); + let encodedData = obj.configData[obj.id]; + if (obj.resource === allKinds.configMap.abbreviation) { + encodedData = Buffer.from(obj.configData[obj.id]).toString('base64'); } - const uri_str = `${uriScheme}://${obj.resource}/${encoded_data}/${obj.id}`; - const uri = vscode.Uri.parse(uri_str); + const uriStr = `${uriScheme}://${obj.resource}/${encodedData}/${obj.id}`; + const uri = vscode.Uri.parse(uriStr); vscode.workspace.openTextDocument(uri).then( (doc) => { vscode.window.showTextDocument(doc); @@ -39,7 +37,7 @@ export function loadConfigMapData(obj: KubernetesFileObject) { } function removeKey(dictionary: any, keyToDelete: string) { - let newData = {}; + const newData = {}; Object.keys(dictionary).forEach((key) => { if (key !== keyToDelete) { newData[key] = dictionary[key]; @@ -93,14 +91,14 @@ export async function addKubernetesConfigFile(kubectl: Kubectl, obj: KubernetesD const filePath = uri.fsPath; const fileName = basename(filePath); if (dataHolder.data[fileName]) { - let response = await vscode.window.showWarningMessage(`Are you sure you want to overwrite '${fileName}'? This can not be undone`, ...overwriteMessageItems); + const response = await vscode.window.showWarningMessage(`Are you sure you want to overwrite '${fileName}'? This can not be undone`, ...overwriteMessageItems); if (response.title !== overwriteMessageItems[0].title) { return; } } // TODO: I really don't like sync calls here... const buff = fs.readFileToBufferSync(filePath); - if (obj.resource == 'configmap') { + if (obj.resource === 'configmap') { dataHolder.data[fileName] = buff.toString(); } else { dataHolder.data[fileName] = buff.toString('base64'); @@ -108,7 +106,7 @@ export async function addKubernetesConfigFile(kubectl: Kubectl, obj: KubernetesD }); const out = JSON.stringify(dataHolder); const shellRes = await kubectl.invokeAsync(`replace -f - --namespace=${currentNS}`, out); - if (shellRes.code != 0) { + if (shellRes.code !== 0) { vscode.window.showErrorMessage('Failed to add file(s) to resource ${obj.id}: ' + shellRes.stderr); return; } diff --git a/src/debug/debugProvider.ts b/src/debug/debugProvider.ts index 7eeb8d494..3dbd43c5f 100644 --- a/src/debug/debugProvider.ts +++ b/src/debug/debugProvider.ts @@ -1,7 +1,4 @@ -import * as vscode from "vscode"; - import { Kubectl } from "../kubectl"; -import { ShellResult } from "../shell"; import { IDockerfile } from "../docker/parser"; export interface PortInfo { diff --git a/src/debug/debugSession.ts b/src/debug/debugSession.ts index 83b2e35ae..e4620c378 100644 --- a/src/debug/debugSession.ts +++ b/src/debug/debugSession.ts @@ -3,7 +3,7 @@ import * as fs from "fs"; import * as opn from 'opn'; import * as path from "path"; import * as portfinder from "portfinder"; -import { ChildProcess, spawn as spawnChildProcess } from "child_process"; +import { ChildProcess } from "child_process"; import { IDebugProvider } from "./debugProvider"; import * as providerRegistry from "./providerRegistry"; @@ -208,7 +208,7 @@ export class DebugSession implements IDebugSession { } private async pickupAndInstallDebugProvider(baseImage?: string): Promise { - let debugProvider: IDebugProvider = await providerRegistry.getDebugProvider(); + const debugProvider: IDebugProvider = await providerRegistry.getDebugProvider(); if (!debugProvider) { return; } else if (!await debugProvider.isDebuggerInstalled()) { @@ -262,7 +262,8 @@ export class DebugSession implements IDebugSession { private async setupPortForward(podName: string, debugPort: number, appPort?: number): Promise { kubeChannel.showOutput(`Setting up port forwarding on pod ${podName}...`, "Set up port forwarding"); const proxyResult = await this.createPortForward(this.kubectl, podName, debugPort, appPort); - kubeChannel.showOutput(`Created port-forward ${proxyResult.proxyDebugPort}:${debugPort} ${appPort ? proxyResult.proxyAppPort + ":" + appPort : ""}`); + const appPortStr = appPort ? `${proxyResult.proxyAppPort}:${appPort}` : ""; + kubeChannel.showOutput(`Created port-forward ${proxyResult.proxyDebugPort}:${debugPort} ${appPortStr}`); // Wait for the port-forward proxy to be ready. kubeChannel.showOutput("Waiting for port forwarding to be ready..."); @@ -326,20 +327,20 @@ export class DebugSession implements IDebugSession { } private async createPortForward(kubectl: Kubectl, podName: string, debugPort: number, appPort?: number): Promise { - let portMapping = []; + const portMapping = []; // Find a free local port for forwarding data to remote app port. let proxyAppPort = 0; if (appPort) { proxyAppPort = await portfinder.getPortPromise({ port: appPort }); - portMapping.push(proxyAppPort + ":" + appPort); + portMapping.push(`${proxyAppPort}:${appPort}`); } // Find a free local port for forwarding data to remote debug port. const proxyDebugPort = await portfinder.getPortPromise({ port: Math.max(10000, Number(proxyAppPort) + 1) }); - portMapping.push(proxyDebugPort + ":" + debugPort); + portMapping.push(`${proxyDebugPort}:${debugPort}`); return { proxyProcess: await kubectl.spawnAsChild(["port-forward", podName, ...portMapping]), diff --git a/src/docker/dockerUtils.ts b/src/docker/dockerUtils.ts index 38fb84ef5..e21a0fcfd 100644 --- a/src/docker/dockerUtils.ts +++ b/src/docker/dockerUtils.ts @@ -6,8 +6,7 @@ import * as url from "url"; import { kubeChannel } from "../kubeChannel"; import { Kubectl } from "../kubectl"; import { getCurrentClusterConfig } from "../kubectlUtils"; -import { shell, ShellResult } from "../shell"; -import { DockerfileParser } from "./dockerfileParser"; +import { shell } from "../shell"; export enum DockerClient { docker = "docker", @@ -46,7 +45,7 @@ async function getDefaultImageName(cwd: string, imagePrefix?: string): Promise { + this.runtime.on('end', () => { this.sendEvent(new TerminatedEvent()); }); } @@ -30,30 +25,30 @@ export class DraftDebugSession extends LoggingDebugSession { } protected configurationDoneRequest(response: DebugProtocol.ConfigurationDoneResponse, args: DebugProtocol.LaunchRequestArguments): void { - this._configurationDone.notify(); + this.configurationDone.notify(); } protected async launchRequest(response: DebugProtocol.LaunchResponse, args: DebugProtocol.LaunchRequestArguments) { // wait until configuration has finished (and configurationDoneRequest has been called) - await this._configurationDone.wait(1000); + await this.configurationDone.wait(1000); - //start a `draft up` and `draft connect` session and attach debugger - this._runtime.draftUpDebug(this.config); + // start a `draft up` and `draft connect` session and attach debugger + this.runtime.draftUpDebug(this.config); this.sendResponse(response); } protected evaluateRequest(response: DebugProtocol.EvaluateResponse, args: DebugProtocol.EvaluateArguments): void { - if (args['restart'] == true) { + if (args['restart'] === true) { // TODO - check for request type // // when a request is received (such as a file was saved), restart the Draft cycle - this._runtime.killConnect(); - this._runtime.draftUpDebug(this.config); + this.runtime.killConnect(); + this.runtime.draftUpDebug(this.config); } - if (args['stop'] == true) { - this._runtime.killConnect(); + if (args['stop'] === true) { + this.runtime.killConnect(); this.stop(); } diff --git a/src/draft/draft.ts b/src/draft/draft.ts index 0f945a523..32c4d1b05 100644 --- a/src/draft/draft.ts +++ b/src/draft/draft.ts @@ -82,7 +82,7 @@ async function packs(context: Context): Promise { async function invoke(context: Context, args: string): Promise { if (await checkPresent(context, CheckPresentMode.Alert)) { - const result = context.shell.exec(context.binPath + ' ' + args); + const result = context.shell.exec(`${context.binPath} ${args}`); return result; } } @@ -99,18 +99,6 @@ async function up(context: Context): Promise { } } -async function path(context: Context): Promise { - let bin = await pathCore(context); - return binutil.execPath(context.shell, bin); -} - -async function pathCore(context: Context): Promise { - if (await checkPresent(context, CheckPresentMode.Alert)) { - return context.binPath; - } - return undefined; -} - async function checkForDraftInternal(context: Context, mode: CheckPresentMode): Promise { const binName = 'draft'; const bin = context.host.getConfiguration('vs-kubernetes')[`vs-kubernetes.${binName}-path`]; diff --git a/src/draft/draftConfigurationProvider.ts b/src/draft/draftConfigurationProvider.ts index cc733492d..74408f370 100644 --- a/src/draft/draftConfigurationProvider.ts +++ b/src/draft/draftConfigurationProvider.ts @@ -3,28 +3,28 @@ import * as Net from 'net'; import { DraftDebugSession } from "./debugDebug"; export class DraftConfigurationProvider implements DebugConfigurationProvider { - private _server?: Net.Server; + private server?: Net.Server; constructor() { } resolveDebugConfiguration(folder: WorkspaceFolder | undefined, config: DebugConfiguration, token?: CancellationToken): ProviderResult { - if (!this._server) { - this._server = Net.createServer((socket) => { + if (!this.server) { + this.server = Net.createServer((socket) => { const session = new DraftDebugSession(); session.config = config; session.setRunAsServer(true); session.start(socket, socket); }).listen(0); } - config.debugServer = this._server.address().port; + config.debugServer = this.server.address().port; return config; } dispose() { - if (this._server) { - this._server.close(); + if (this.server) { + this.server.close(); } } } \ No newline at end of file diff --git a/src/draft/draftRuntime.ts b/src/draft/draftRuntime.ts index c9697e6fc..075b0f535 100644 --- a/src/draft/draftRuntime.ts +++ b/src/draft/draftRuntime.ts @@ -1,7 +1,6 @@ import * as vscode from 'vscode'; -import { LoggingDebugSession, InitializedEvent, TerminatedEvent } from 'vscode-debugadapter'; import { EventEmitter } from 'events'; -import { ChildProcess, exec, execFile, spawn } from 'child_process'; +import { ChildProcess, spawn } from 'child_process'; import { OutputChannel } from 'vscode'; import { Readable } from 'stream'; import { host } from '../host'; @@ -11,29 +10,29 @@ import { create as draftCreate, CheckPresentMode } from './draft'; import { installDependencies } from '../extension'; export class DraftRuntime extends EventEmitter { - private _draft = draftCreate(host, fs, shell, installDependencies); - private _connectProccess: ChildProcess; + private draft = draftCreate(host, fs, shell, installDependencies); + private connectProcess: ChildProcess; constructor() { super(); } public killConnect() { - this._connectProccess.kill('SIGTERM'); + this.connectProcess.kill('SIGTERM'); } public async draftUpDebug(config: vscode.DebugConfiguration) { - let output = vscode.window.createOutputChannel("draft"); + const output = vscode.window.createOutputChannel("draft"); output.show(); - let isPresent = await this._draft.checkPresent(CheckPresentMode.Alert); + const isPresent = await this.draft.checkPresent(CheckPresentMode.Alert); if (!isPresent) { host.showInformationMessage("Draft is not installed!"); return; } - if (!this._draft.isFolderMapped(vscode.workspace.rootPath)) { + if (!this.draft.isFolderMapped(vscode.workspace.rootPath)) { host.showErrorMessage("This folder does not contain a Draft app. Run draft create first!"); return; } @@ -42,8 +41,8 @@ export class DraftRuntime extends EventEmitter { await waitForProcessToExit(createProcess('draft', ['up'], output)); // wait for `draft connect` to be ready - this._connectProccess = createProcess('draft', ['connect'], output); - await waitConnectionReady(this._connectProccess, config); + this.connectProcess = createProcess('draft', ['connect'], output); + await waitConnectionReady(this.connectProcess, config); host.showInformationMessage(`attaching debugger`); @@ -60,7 +59,7 @@ function createProcess(cmd: string, args: string[], output: OutputChannel): Chil console.log(`started ${cmd} ${args.toString()}`); host.showInformationMessage(`starting ${cmd} ${args.toString()}`); - let proc = spawn(cmd, args, shell.execOpts()); + const proc = spawn(cmd, args, shell.execOpts()); console.log(process.env.PATH); // output data on the tab subscribeToDataEvent(proc.stdout, output); @@ -107,19 +106,23 @@ async function waitConnectionReady(proc: ChildProcess, config: vscode.DebugConfi function canAttachDebugger(data: string, config: vscode.DebugConfiguration): boolean { switch (config['original-debug'].type) { case 'node': { - if (config['original-debug'].localRoot == '' || config['original-debug'].localRoot == null) { + if (config['original-debug'].localRoot === '' || config['original-debug'].localRoot === null) { config['original-debug'].localRoot = vscode.workspace.rootPath; } - if (data.indexOf('Debugger listening') >= 0) + if (data.indexOf('Debugger listening') >= 0) { return true; + } + break; } case 'go': { - if (config["original-debug"].program == '' || config["original-debug"].program == null) { + if (config["original-debug"].program === '' || config["original-debug"].program === null) { config['original-debug'].program = vscode.workspace.rootPath; } - if (data.indexOf('API server listening') >= 0) + if (data.indexOf('API server listening') >= 0) { return true; + } + break; } } } diff --git a/src/explainer.ts b/src/explainer.ts index 066cd6ce2..ba47ebd02 100644 --- a/src/explainer.ts +++ b/src/explainer.ts @@ -123,7 +123,7 @@ function chaseFieldPath(swagger: any, currentProperty: TypeModel, currentPropert const currentPropertyTypeRef = currentProperty.$ref || (currentProperty.items ? currentProperty.items.$ref : undefined); if (currentPropertyTypeRef) { - let typeDefnPath: string[] = currentPropertyTypeRef.split('/'); + const typeDefnPath: string[] = currentPropertyTypeRef.split('/'); typeDefnPath.shift(); const currentPropertyTypeInfo = findTypeDefinition(swagger, typeDefnPath); if (currentPropertyTypeInfo) { @@ -167,12 +167,10 @@ function chaseFieldPath(swagger: any, currentProperty: TypeModel, currentPropert } } - function explainError(header: string, error: string) { return `**${header}:** ${error}`; } - function apiCredentials(kc: kubeconfig.KubeConfig) { return { endpoint: kc.endpoint, @@ -197,7 +195,7 @@ function findProperty(obj: any, name: string) { const n = (name + "").toLowerCase(); for (const p in obj) { const pinfo = obj[p]; - if ((p + "").toLowerCase() == n) { + if ((p + "").toLowerCase() === n) { return pinfo; } const gvks = pinfo["x-kubernetes-group-version-kind"]; @@ -207,14 +205,14 @@ function findProperty(obj: any, name: string) { const kind = gvk.kind; if (ver && kind) { const vk = `${ver}.${kind}`; - if (vk.toLowerCase() == n) { + if (vk.toLowerCase() === n) { return pinfo; } } } } const singname = singularizeVersionedName(name); - if (singname == name) { + if (singname === name) { return undefined; } else { return findProperty(obj, singname); diff --git a/src/explorer.ts b/src/explorer.ts index d50688f5e..d8aa9468b 100644 --- a/src/explorer.ts +++ b/src/explorer.ts @@ -1,13 +1,11 @@ import * as path from 'path'; import * as vscode from 'vscode'; -import * as shell from './shell'; import { Kubectl } from './kubectl'; import * as kubectlUtils from './kubectlUtils'; import { Host } from './host'; import * as kuberesources from './kuberesources'; import { failed } from './errorable'; -import { filter } from 'minimatch'; export function create(kubectl: Kubectl, host: Host): KubernetesExplorer { return new KubernetesExplorer(kubectl, host); @@ -43,8 +41,8 @@ export interface ResourceNode { } export class KubernetesExplorer implements vscode.TreeDataProvider { - private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); - readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; + private onDidChangeTreeDataEmitter: vscode.EventEmitter = new vscode.EventEmitter(); + readonly onDidChangeTreeData: vscode.Event = this.onDidChangeTreeDataEmitter.event; constructor(private readonly kubectl: Kubectl, private readonly host: Host) { host.onDidChangeConfiguration((change) => { @@ -66,14 +64,14 @@ export class KubernetesExplorer implements vscode.TreeDataProvider { const contexts = await kubectlUtils.getContexts(this.kubectl); return contexts.map((context): KubernetesContext => { // TODO: this is slightly hacky... - if (context.contextName == 'minikube') { + if (context.contextName === 'minikube') { return new MinikubeContext(context.contextName, context); } return new KubernetesContext(context.contextName, context); @@ -134,7 +132,6 @@ class MinikubeContext extends KubernetesContext { } } - abstract class KubernetesFolder implements KubernetesObject { constructor(readonly id: string, readonly displayName: string, readonly contextValue?: string) { } @@ -201,7 +198,7 @@ class KubernetesResource implements KubernetesObject, ResourceNode { readonly resourceId: string; constructor(readonly kind: kuberesources.ResourceKind, readonly id: string, readonly metadata?: any) { - this.resourceId = kind.abbreviation + '/' + id; + this.resourceId = `${kind.abbreviation}/${id}`; } get namespace(): string | null { @@ -213,7 +210,7 @@ class KubernetesResource implements KubernetesObject, ResourceNode { } getTreeItem(): vscode.TreeItem | Thenable { - let treeItem = new vscode.TreeItem(this.id, vscode.TreeItemCollapsibleState.None); + const treeItem = new vscode.TreeItem(this.id, vscode.TreeItemCollapsibleState.None); treeItem.command = { command: "extension.vsKubernetesLoad", title: "Load", @@ -221,8 +218,8 @@ class KubernetesResource implements KubernetesObject, ResourceNode { }; treeItem.contextValue = `vsKubernetes.resource`; if (this.kind === kuberesources.allKinds.pod || - this.kind == kuberesources.allKinds.secret || - this.kind == kuberesources.allKinds.configMap) { + this.kind === kuberesources.allKinds.secret || + this.kind === kuberesources.allKinds.configMap) { treeItem.contextValue = `vsKubernetes.resource.${this.kind.abbreviation}`; if (this.kind === kuberesources.allKinds.pod && this.metadata.status !== null) { treeItem.iconPath = getIconForPodStatus(this.metadata.status); @@ -364,10 +361,10 @@ export class KubernetesDataHolderResource extends KubernetesResource { } async getChildren(kubectl: Kubectl, host: Host): Promise { - if (!this.configData || this.configData.length == 0) { + if (!this.configData || this.configData.length === 0) { return []; } - let files = Object.keys(this.configData); + const files = Object.keys(this.configData); return files.map((f) => new KubernetesFileObject(this.configData, f, this.resource, this.id)); } } @@ -377,7 +374,7 @@ export class KubernetesFileObject implements KubernetesObject { } getTreeItem(): vscode.TreeItem | Thenable { - let treeItem = new vscode.TreeItem(this.id, vscode.TreeItemCollapsibleState.None); + const treeItem = new vscode.TreeItem(this.id, vscode.TreeItemCollapsibleState.None); treeItem.command = { command: "extension.vsKubernetesLoadConfigMapData", title: "Load", diff --git a/src/extension.ts b/src/extension.ts index 006c2ca88..3d3163ba8 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -19,21 +19,20 @@ import { pullAll } from 'lodash'; // Internal dependencies import { host } from './host'; -import { loadConfigMapData, addKubernetesConfigFile, deleteKubernetesConfigFile } from './configMap'; +import { addKubernetesConfigFile, deleteKubernetesConfigFile } from './configMap'; import * as explainer from './explainer'; import { shell, Shell, ShellResult, ShellHandler } from './shell'; import * as configmaps from './configMap'; import * as configureFromCluster from './configurefromcluster'; import * as createCluster from './createcluster'; import * as kuberesources from './kuberesources'; -import { useNamespaceKubernetes } from './kubeNamespace'; +import { useNamespaceKubernetes } from './components/kubectl/namespace'; import * as docker from './docker'; import { kubeChannel } from './kubeChannel'; -import * as kubeconfig from './kubeconfig'; -import { create as kubectlCreate, Kubectl } from './kubectl'; +import { create as kubectlCreate } from './kubectl'; import * as kubectlUtils from './kubectlUtils'; import * as explorer from './explorer'; -import { create as draftCreate, Draft, CheckPresentMode as DraftCheckPresentMode } from './draft/draft'; +import { create as draftCreate, CheckPresentMode as DraftCheckPresentMode } from './draft/draft'; import * as logger from './logger'; import * as helm from './helm'; import * as helmexec from './helm.exec'; @@ -56,6 +55,7 @@ import { registerYamlSchemaSupport } from './yaml-support/yaml-schema'; import * as clusterproviderregistry from './components/clusterprovider/clusterproviderregistry'; import * as azureclusterprovider from './components/clusterprovider/azure/azureclusterprovider'; import * as minikubeclusterprovider from './components/clusterprovider/minikube/minikubeclusterprovider'; +import { refreshExplorer } from './components/clusterprovider/common/explorer'; import { KubernetesCompletionProvider } from "./yaml-support/yaml-snippet"; import { showWorkspaceFolderPick } from './hostutils'; import { DraftConfigurationProvider } from './draft/draftConfigurationProvider'; @@ -132,7 +132,7 @@ export async function activate(context): Promise { registerCommand('extension.vsKubernetesGet', getKubernetes), registerCommand('extension.vsKubernetesRun', runKubernetes), registerCommand('extension.vsKubernetesShowLogs', logsKubernetes), - registerCommand('extension.vsKubernetesFollowLogs', (explorerNode: explorer.ResourceNode) => {logsKubernetes(explorerNode, true);}), + registerCommand('extension.vsKubernetesFollowLogs', (explorerNode: explorer.ResourceNode) => { logsKubernetes(explorerNode, true); }), registerCommand('extension.vsKubernetesExpose', exposeKubernetes), registerCommand('extension.vsKubernetesDescribe', describeKubernetes), registerCommand('extension.vsKubernetesSync', syncKubernetes), @@ -149,7 +149,7 @@ export async function activate(context): Promise { registerCommand('extension.vsKubernetesUseContext', useContextKubernetes), registerCommand('extension.vsKubernetesClusterInfo', clusterInfoKubernetes), registerCommand('extension.vsKubernetesDeleteContext', deleteContextKubernetes), - registerCommand('extension.vsKubernetesUseNamespace', () => { useNamespaceKubernetes(this, kubectl); } ), + registerCommand('extension.vsKubernetesUseNamespace', (obj) => { useNamespaceKubernetes(kubectl, obj); } ), registerCommand('extension.vsKubernetesDashboard', () => { dashboardKubernetes(kubectl); }), registerCommand('extension.vsMinikubeStop', stopMinikube), registerCommand('extension.vsMinikubeStart', startMinikube), @@ -223,22 +223,22 @@ export async function activate(context): Promise { return; } if (e === vscode.window.activeTextEditor.document) { - let doc = vscode.window.activeTextEditor.document; - if (doc.uri.scheme != "file") { + const doc = vscode.window.activeTextEditor.document; + if (doc.uri.scheme !== "file") { return; } - let u = vscode.Uri.parse(helm.PREVIEW_URI); + const u = vscode.Uri.parse(helm.PREVIEW_URI); previewProvider.update(u); } // if there is an active Draft debugging session, restart the cycle - if (draftDebugSession != undefined) { + if (draftDebugSession !== undefined) { const session = vscode.debug.activeDebugSession; // TODO - how do we make sure this doesn't affect all other debugging sessions? // TODO - maybe check to see if `draft.toml` is present in the workspace // TODO - check to make sure we enable this only when Draft is installed - if (session != undefined) { + if (session !== undefined) { draftDebugSession.customRequest('evaluate', { restart: true }); } } @@ -247,13 +247,13 @@ export async function activate(context): Promise { vscode.debug.onDidTerminateDebugSession((e) => { // if there is an active Draft debugging session, restart the cycle - if (draftDebugSession != undefined) { + if (draftDebugSession !== undefined) { const session = vscode.debug.activeDebugSession; // TODO - how do we make sure this doesn't affect all other debugging sessions? // TODO - maybe check to see if `draft.toml` is present in the workspace // TODO - check to make sure we enable this only when Draft is installed - if (session != undefined) { + if (session !== undefined) { draftDebugSession.customRequest('evaluate', { stop: true }); } } @@ -264,17 +264,16 @@ export async function activate(context): Promise { if (!editorIsActive()) { return; } - let doc = vscode.window.activeTextEditor.document; - if (doc.uri.scheme != "file") { + const doc = vscode.window.activeTextEditor.document; + if (doc.uri.scheme !== "file") { return; } - let u = vscode.Uri.parse(helm.PREVIEW_URI); + const u = vscode.Uri.parse(helm.PREVIEW_URI); previewProvider.update(u); }); - vscode.debug.onDidChangeActiveDebugSession((e: vscode.DebugSession)=> { - if (e != undefined) { + if (e !== undefined) { // keep a copy of the initial Draft debug session if (e.name.indexOf('Draft') >= 0) { draftDebugSession = e; @@ -329,13 +328,13 @@ function provideHover(document, position, token, syntax): Promise return; } - let property = findProperty(document.lineAt(position.line)), - field = syntax.parse(property), + const property = findProperty(document.lineAt(position.line)); + let field = syntax.parse(property), parentLine = syntax.findParent(document, position.line); while (parentLine !== -1) { - let parentProperty = findProperty(document.lineAt(parentLine)); - field = syntax.parse(parentProperty) + '.' + field; + const parentProperty = findProperty(document.lineAt(parentLine)); + field = `${syntax.parse(parentProperty)}.${field}`; parentLine = syntax.findParent(document, parentLine); } @@ -369,7 +368,7 @@ function provideHoverYaml(document, position, token) { } function findProperty(line) { - let ix = line.text.indexOf(':'); + const ix = line.text.indexOf(':'); return line.text.substring(line.firstNonWhitespaceCharacterIndex, ix); } @@ -399,9 +398,9 @@ function findParentJson(document, line) { } function findParentYaml(document, line) { - let indent = yamlIndentLevel(document.lineAt(line).text); + const indent = yamlIndentLevel(document.lineAt(line).text); while (line >= 0) { - let txt = document.lineAt(line); + const txt = document.lineAt(line); if (yamlIndentLevel(txt.text) < indent) { return line; } @@ -413,7 +412,6 @@ function findParentYaml(document, line) { function yamlIndentLevel(str) { let i = 0; - //eslint-disable-next-line no-constant-condition while (true) { if (str.length <= i || !isYamlIndentChar(str.charAt(i))) { return i; @@ -435,7 +433,7 @@ async function explain(obj, field) { let ref = obj.kind; if (field && field.length > 0) { - ref = ref + '.' + field; + ref = `${ref}.${field}`; } if (!swaggerSpecPromise) { @@ -449,8 +447,8 @@ async function explain(obj, field) { } function explainActiveWindow() { - let editor = vscode.window.activeTextEditor; - let bar = initStatusBar(); + const editor = vscode.window.activeTextEditor; + const bar = initStatusBar(); if (!editor) { vscode.window.showErrorMessage('No active editor!'); @@ -471,7 +469,6 @@ function explainActiveWindow() { } } - let statusBarItem; function initStatusBar() { @@ -487,17 +484,18 @@ function initStatusBar() { // Expects that it can append a filename to 'command' to create a complete kubectl command. // // @parameter command string The command to run -function maybeRunKubernetesCommandForActiveWindow(command, progressMessage) { - let text, proc; +function maybeRunKubernetesCommandForActiveWindow(command: string, progressMessage: string) { + let text: string; - let editor = vscode.window.activeTextEditor; + const editor = vscode.window.activeTextEditor; if (!editor) { vscode.window.showErrorMessage('This command operates on the open document. Open your Kubernetes resource file, and try again.'); return false; // No open text editor } - let namespace = vscode.workspace.getConfiguration('vs-kubernetes')['vs-kubernetes.namespace']; + + const namespace = vscode.workspace.getConfiguration('vs-kubernetes')['vs-kubernetes.namespace']; if (namespace) { - command = command + ' --namespace ' + namespace + ' '; + command = `${command} --namespace ${namespace} `; } const isKubernetesSyntax = (editor.document.languageId === 'json' || editor.document.languageId === 'yaml'); @@ -525,6 +523,7 @@ function maybeRunKubernetesCommandForActiveWindow(command, progressMessage) { } return false; } + // TODO: unify these paths now we handle non-file URIs if (editor.document.isDirty) { // TODO: I18n this? @@ -600,8 +599,8 @@ function getTextForActiveWindow(callback: (data: string | null, file: vscode.Uri if (editor.document.isDirty) { // TODO: I18n this? - let confirm = 'Save'; - let promise = vscode.window.showWarningMessage('You have unsaved changes!', confirm); + const confirm = 'Save'; + const promise = vscode.window.showWarningMessage('You have unsaved changes!', confirm); promise.then((value) => { if (!value) { return; @@ -653,14 +652,14 @@ function loadKubernetesCore(namespace: string | null, value: string) { } function exposeKubernetes() { - let kindName = findKindNameOrPrompt(kuberesources.exposableKinds, 'expose', { nameOptional: false}, (kindName: string) => { + findKindNameOrPrompt(kuberesources.exposableKinds, 'expose', { nameOptional: false}, (kindName: string) => { if (!kindName) { vscode.window.showErrorMessage('couldn\'t find a relevant type to expose.'); return; } let cmd = `expose ${kindName}`; - let ports = getPorts(); + const ports = getPorts(); if (ports && ports.length > 0) { cmd += ' --port=' + ports[0]; @@ -735,7 +734,7 @@ async function findPodsForApp(): Promise { if (!vscode.workspace.rootPath) { return { succeeded: true, pods: [] }; } - let appName = path.basename(vscode.workspace.rootPath); + const appName = path.basename(vscode.workspace.rootPath); return await findPodsByLabel(`run=${appName}`); } @@ -743,7 +742,7 @@ async function findDebugPodsForApp(): Promise { if (!vscode.workspace.rootPath) { return { succeeded: true, pods: [] }; } - let appName = path.basename(vscode.workspace.rootPath); + const appName = path.basename(vscode.workspace.rootPath); return await findPodsByLabel(`run=${appName}-debug`); } @@ -766,10 +765,10 @@ function _findNameAndImageInternal(fn) { const folderName = path.basename(vscode.workspace.rootPath); const name = docker.sanitiseTag(folderName); findVersion().then((version) => { - let image = name + ":" + version; - let user = vscode.workspace.getConfiguration().get("vsdocker.imageUser", null); + let image = `${name}:${version}`; + const user = vscode.workspace.getConfiguration().get("vsdocker.imageUser", null); if (user) { - image = user + '/' + image; + image = `${user}/${image}`; } fn(name.trim(), image.trim()); @@ -785,7 +784,7 @@ function scaleKubernetes() { function promptScaleKubernetes(kindName: string) { vscode.window.showInputBox({ prompt: `How many replicas would you like to scale ${kindName} to?` }).then((value) => { if (value) { - let replicas = parseFloat(value); + const replicas = parseFloat(value); if (Number.isInteger(replicas) && replicas >= 0) { invokeScaleKubernetes(kindName, replicas); } else { @@ -893,7 +892,7 @@ function findKindNamesForText(text): Errorable { } export function findKindNameOrPrompt(resourceKinds: kuberesources.ResourceKind[], descriptionVerb, opts, handler) { - let kindObject = tryFindKindNameFromEditor(); + const kindObject = tryFindKindNameFromEditor(); if (failed(kindObject)) { promptKindName(resourceKinds, descriptionVerb, opts, handler); } else { @@ -903,11 +902,13 @@ export function findKindNameOrPrompt(resourceKinds: kuberesources.ResourceKind[] export function promptKindName(resourceKinds: kuberesources.ResourceKind[], descriptionVerb, opts, handler) { let placeHolder: string = 'Empty string to be prompted'; - let prompt: string = "What resource do you want to " + descriptionVerb + "?"; + let prompt: string = `What resource do you want to ${descriptionVerb}?`; + if (opts) { placeHolder = opts.placeHolder || placeHolder; prompt = opts.prompt || prompt; } + vscode.window.showInputBox({ prompt, placeHolder}).then((resource) => { if (resource === '') { quickPickKindName(resourceKinds, opts, handler); @@ -933,7 +934,7 @@ function quickPickKindName(resourceKinds: kuberesources.ResourceKind[], opts, ha } function quickPickKindNameFromKind(resourceKind: kuberesources.ResourceKind, opts, handler) { - let kind = resourceKind.abbreviation; + const kind = resourceKind.abbreviation; kubectl.invoke("get " + kind, (code, stdout, stderr) => { if (code !== 0) { vscode.window.showErrorMessage(stderr); @@ -942,7 +943,7 @@ function quickPickKindNameFromKind(resourceKind: kuberesources.ResourceKind, opt let names = parseNamesFromKubectlLines(stdout); if (names.length === 0) { - vscode.window.showInformationMessage("No resources of type " + resourceKind.displayName + " in cluster"); + vscode.window.showInformationMessage(`No resources of type ${resourceKind.displayName} in cluster`); return; } @@ -958,7 +959,7 @@ function quickPickKindNameFromKind(resourceKind: kuberesources.ResourceKind, opt if (name === '(all)') { kindName = kind; } else { - kindName = kind + '/' + name; + kindName = `${kind}/${name}`; } handler(kindName); } @@ -966,7 +967,7 @@ function quickPickKindNameFromKind(resourceKind: kuberesources.ResourceKind, opt } else { vscode.window.showQuickPick(names).then((name) => { if (name) { - let kindName = kind + '/' + name; + const kindName = `${kind}/${name}`; handler(kindName); } }); @@ -982,10 +983,10 @@ function containsName(kindName) { } function parseNamesFromKubectlLines(text) { - let lines = text.split('\n'); + const lines = text.split('\n'); lines.shift(); - let names = lines.filter((line) => { + const names = lines.filter((line) => { return line.length > 0; }).map((line) => { return parseName(line); @@ -999,11 +1000,11 @@ function parseName(line) { } function findPod(callback: (pod: PodSummary) => void) { - let editor = vscode.window.activeTextEditor; + const editor = vscode.window.activeTextEditor; if (editor) { - let text = editor.document.getText(); + const text = editor.document.getText(); try { - let obj: {} = yaml.safeLoad(text); + const obj: {} = yaml.safeLoad(text); if (isPod(obj)) { callback({ name: obj.metadata.name, @@ -1074,6 +1075,7 @@ async function selectPod(scope: PodSelectionScope, fallback: PodSelectionFallbac vscode.window.showErrorMessage(`Couldn't find any pods ${scopeMessage}.`); return null; } + if (podList.length === 1) { return podList[0]; } @@ -1082,7 +1084,7 @@ async function selectPod(scope: PodSelectionScope, fallback: PodSelectionFallbac label: `${element.metadata.namespace || "default"}/${element.metadata.name}`, description: '', pod: element - };}); + }; }); const value = await vscode.window.showQuickPick(pickItems); @@ -1101,7 +1103,7 @@ async function logsKubernetes(explorerNode?: explorer.ResourceNode, follow?: boo getLogsForContainer(podSummary.name, podSummary.namespace, container.name, follow); } } else { - findPod((pod: PodSummary) => {getLogsForPod(pod, follow);}); + findPod((pod: PodSummary) => { getLogsForPod(pod, follow); }); } } @@ -1130,26 +1132,14 @@ function getLogsForContainer(podName: string, podNamespace: string | undefined, kubectl.invokeInSharedTerminal(cmd); } -function kubectlOutputTo(name: string) { - return (code, stdout, stderr) => kubectlOutput(code, stdout, stderr, name); -} - -function kubectlOutput(result, stdout, stderr, name) { - if (result !== 0) { - vscode.window.showErrorMessage('Command failed: ' + stderr); - return; - } - kubeChannel.showOutput(stdout, name); -} - function getPorts() { - let file = vscode.workspace.rootPath + '/Dockerfile'; + const file = vscode.workspace.rootPath + '/Dockerfile'; if (!fs.existsSync(file)) { return null; } try { - let data = fs.readFileSync(file, 'utf-8'); - let obj = dockerfileParse(data); + const data = fs.readFileSync(file, 'utf-8'); + const obj = dockerfileParse(data); return obj.expose; } catch (ex) { console.log(ex); @@ -1203,7 +1193,7 @@ async function selectContainerForPod(pod: PodSummary): Promise description: '', detail: element.image, container: element - };}); + }; }); const value = await vscode.window.showQuickPick(pickItems, { placeHolder: "Select container" }); @@ -1233,7 +1223,7 @@ async function terminalKubernetes(explorerNode?: explorer.ResourceNode) { } async function execKubernetesCore(isTerminal): Promise { - let opts: any = { prompt: 'Please provide a command to execute' }; + const opts: any = { prompt: 'Please provide a command to execute' }; if (isTerminal) { opts.value = 'bash'; @@ -1325,10 +1315,6 @@ async function syncKubernetes(): Promise { } } -export async function refreshExplorer() { - await vscode.commands.executeCommand("extension.vsKubernetesRefreshExplorer"); -} - async function reportDeleteResult(resourceId: string, shellResult: ShellResult) { if (shellResult.code !== 0) { await vscode.window.showErrorMessage(`Failed to delete resource '${resourceId}': ${shellResult.stderr}`); @@ -1469,7 +1455,7 @@ function diffKubernetesCore(callback: (r: DiffResult) => void): void { let fileFormat = "json"; if (data) { - fileFormat = (data.trim().length > 0 && data.trim()[0] == '{') ? "json" : "yaml"; + fileFormat = (data.trim().length > 0 && data.trim()[0] === '{') ? "json" : "yaml"; kindObject = findKindNameForText(data); if (failed(kindObject)) { callback({ result: DiffResultKind.NoKindName, reason: kindObject.error[0] }); @@ -1508,7 +1494,7 @@ function diffKubernetesCore(callback: (r: DiffResult) => void): void { } kubectl.invoke(` get -o ${fileFormat} ${kindName}`, (result, stdout, stderr) => { - if (result == 1 && stderr.indexOf('NotFound') >= 0) { + if (result === 1 && stderr.indexOf('NotFound') >= 0) { callback({ result: DiffResultKind.NoClusterResource, resourceName: kindName }); return; } @@ -1517,7 +1503,7 @@ function diffKubernetesCore(callback: (r: DiffResult) => void): void { return; } - let serverFile = path.join(os.tmpdir(), `server.${fileFormat}`); + const serverFile = path.join(os.tmpdir(), `server.${fileFormat}`); fs.writeFile(serverFile, stdout, handleError); vscode.commands.executeCommand( @@ -1549,7 +1535,7 @@ const debugKubernetes = async () => { if (debugProvider) { new DebugSession(kubectl).launch(workspaceFolder, debugProvider); } else { - buildPushThenExec(_debugInternal); + buildPushThenExec(debugInternal); } } }; @@ -1561,7 +1547,7 @@ const debugAttachKubernetes = async (explorerNode: explorer.KubernetesObject) => } }; -const _debugInternal = (name, image) => { +const debugInternal = (name, image) => { // TODO: optionalize/customize the '-debug' // TODO: make this smarter. vscode.window.showInputBox({ @@ -1572,11 +1558,11 @@ const _debugInternal = (name, image) => { return; } - _doDebug(name, image, cmd); + doDebug(name, image, cmd); }); }; -const _doDebug = async (name, image, cmd) => { +const doDebug = async (name, image, cmd) => { const deploymentName = `${name}-debug`; const runCmd = `run ${deploymentName} --image=${image} -i --attach=false -- ${cmd}`; console.log(runCmd); @@ -1601,7 +1587,7 @@ const _doDebug = async (name, image, cmd) => { return; } - let podName = podList[0].metadata.name; + const podName = podList[0].metadata.name; vscode.window.showInformationMessage('Debug pod running as: ' + podName); waitForRunningPod(podName, () => { @@ -1636,7 +1622,7 @@ const _doDebug = async (name, image, cmd) => { vscode.window.showErrorMessage('Failed to expose deployment: ' + stderr); return; } - vscode.window.showInformationMessage('Deployment exposed. Run Kubernetes Get > service ' + deploymentName + ' for IP address'); + vscode.window.showInformationMessage(`Deployment exposed. Run Kubernetes Get > service ${deploymentName} for IP address`); }); }); }); @@ -1664,8 +1650,7 @@ const waitForRunningPod = (name, callback) => { }; function exists(kind, name, handler) { - //eslint-disable-next-line no-unused-vars - kubectl.invoke('get ' + kind + ' ' + name, (result) => { + kubectl.invoke(`get ${kind} ${name}`, (result) => { handler(result === 0); }); } @@ -1679,9 +1664,8 @@ function serviceExists(serviceName, handler) { } function removeDebugKubernetes() { - //eslint-disable-next-line no-unused-vars findNameAndImage().then((name, image) => { - let deploymentName = name + '-debug'; + const deploymentName = name + '-debug'; deploymentExists(deploymentName, (deployment) => { serviceExists(deploymentName, (service) => { if (!deployment && !service) { @@ -1689,8 +1673,8 @@ function removeDebugKubernetes() { return; } - let toDelete = deployment ? ('deployment' + (service ? ' and service' : '')) : 'service'; - vscode.window.showWarningMessage('This will delete ' + toDelete + ' ' + deploymentName, 'Delete').then((opt) => { + const toDelete = deployment ? ('deployment' + (service ? ' and service' : '')) : 'service'; + vscode.window.showWarningMessage(`This will delete ${toDelete} ${deploymentName}`, 'Delete').then((opt) => { if (opt !== 'Delete') { return; } diff --git a/src/extensionUtils.ts b/src/extensionUtils.ts index ea9b75174..665a462b3 100644 --- a/src/extensionUtils.ts +++ b/src/extensionUtils.ts @@ -1,7 +1,7 @@ import * as path from "path"; import * as vscode from "vscode"; -import { shell, ShellResult } from "./shell"; +import { shell } from "./shell"; /** * Install a vscode extension programmatically. diff --git a/src/helm.completionProvider.ts b/src/helm.completionProvider.ts index 6f3434be2..4f717105e 100644 --- a/src/helm.completionProvider.ts +++ b/src/helm.completionProvider.ts @@ -5,7 +5,7 @@ import * as YAML from 'yamljs'; import * as exec from './helm.exec'; import * as path from 'path'; import * as _ from 'lodash'; -import {existsSync} from 'fs'; +import { existsSync } from 'fs'; export class HelmTemplateCompletionProvider implements vscode.CompletionItemProvider { @@ -25,14 +25,14 @@ export class HelmTemplateCompletionProvider implements vscode.CompletionItemProv } public refreshValues(options: exec.PickChartUIOptions) { - let ed = vscode.window.activeTextEditor; + const ed = vscode.window.activeTextEditor; if (!ed) { return; } - let self = this; + const self = this; exec.pickChartForFile(ed.document.fileName, options, (f) => { - let valsYaml = path.join(f, "values.yaml"); + const valsYaml = path.join(f, "values.yaml"); if (!existsSync(valsYaml)) { return; } @@ -46,7 +46,6 @@ export class HelmTemplateCompletionProvider implements vscode.CompletionItemProv } public provideCompletionItems(doc: vscode.TextDocument, pos: vscode.Position) { - // If the preceding character is a '.', we kick it into dot resolution mode. // Otherwise, we go with function completion. const wordPos = doc.getWordRangeAtPosition(pos); @@ -54,9 +53,7 @@ export class HelmTemplateCompletionProvider implements vscode.CompletionItemProv const line = doc.lineAt(pos.line).text; const lineUntil = line.substr(0, wordPos.start.character); - //logger.log(lineUntil) if (lineUntil.endsWith(".")) { - //logger.log("sending to dotCompletionItems ") return this.dotCompletionItems(doc, pos, word, lineUntil); } @@ -78,8 +75,8 @@ export class HelmTemplateCompletionProvider implements vscode.CompletionItemProv if (!_.isPlainObject(this.valuesCache)) { return; } - let keys = _.keys(this.valuesCache); - let res = []; + const keys = _.keys(this.valuesCache); + const res = []; keys.forEach((key) => { res.push(this.funcmap.v(key, ".Values."+key, "In values.yaml: " + this.valuesCache[key])); }); @@ -99,11 +96,10 @@ export class HelmTemplateCompletionProvider implements vscode.CompletionItemProv // If this does not match the valuesMatcher (Not a .Values.SOMETHING...) then // we return right away. - if (!res || res.length == 0) { + if (!res || res.length === 0) { return []; } - //logger.log("Match: " + res[0] + " ('"+res[1]+"' matches)") - if (res[1].length == 0 ) { + if (res[1].length === 0 ) { // This is probably impossible. It would match '.Values.', but that is // matched by a previous condition. return []; @@ -113,10 +109,9 @@ export class HelmTemplateCompletionProvider implements vscode.CompletionItemProv // tree to see what suggestions we can give based on the contents of the // current values.yaml file. const parts = res[1].split("."); - let words = []; let cache = this.valuesCache; for (const cur of parts) { - if (cur.length == 0) { + if (cur.length === 0) { // We hit the trailing dot. break; } @@ -127,10 +122,9 @@ export class HelmTemplateCompletionProvider implements vscode.CompletionItemProv cache = cache[cur]; } if (!cache) { - //logger.log("Found no matches for " + res[1]) return []; } - let k = []; + const k = []; _.keys(cache).forEach((item) => { // Build help text for each suggestion we found. k.push(this.v(item, res[0] + item, "In values.yaml: " + cache[item])); @@ -138,36 +132,11 @@ export class HelmTemplateCompletionProvider implements vscode.CompletionItemProv return k; } } + v(name: string, use: string, doc: string): vscode.CompletionItem { - let i = new vscode.CompletionItem(name, vscode.CompletionItemKind.Constant); + const i = new vscode.CompletionItem(name, vscode.CompletionItemKind.Constant); i.detail = use; i.documentation = doc; return i; } -/* - f(name: string, args: string, doc: string): vscode.CompletionItem { - let i = new vscode.CompletionItem(name, vscode.CompletionItemKind.Function); - i.detail = args; - i.documentation = doc; - return i; - } - withValues(fn) { - let doc = vscode.window.activeTextEditor.document; - exec.pickChartForFile(doc.fileName, (f) => { - let valsYaml = path.join(f, "values.yaml"); - let vals; - try { - vals = YAML.load(valsYaml); - } catch (err) { - logger.helm.log(err.message); - fn({}); - } - fn(vals); - }); - } - */ -} - -interface UIOptions { - readonly warnIfNoCharts?: boolean; } \ No newline at end of file diff --git a/src/helm.documentProvider.ts b/src/helm.documentProvider.ts index b7f9557dc..e6ac13949 100644 --- a/src/helm.documentProvider.ts +++ b/src/helm.documentProvider.ts @@ -18,9 +18,9 @@ export class HelmInspectDocumentProvider implements vscode.TextDocumentContentPr return new Promise((resolve, reject) => { console.log("provideTextDocumentContent called with uri " + uri.toString()); - let printer = (code, out, err) => { - if (code == 0) { - const p = (filepath.extname(uri.fsPath) == ".tgz") ? filepath.basename(uri.fsPath) : "Chart"; + const printer = (code, out, err) => { + if (code === 0) { + const p = (filepath.extname(uri.fsPath) === ".tgz") ? filepath.basename(uri.fsPath) : "Chart"; const title = "Inspect " + p; resolve(previewBody(title, out)); } @@ -29,7 +29,7 @@ export class HelmInspectDocumentProvider implements vscode.TextDocumentContentPr const file = uri.fsPath || uri.authority; const fi = fs.statSync(file); - if (!fi.isDirectory() && filepath.extname(file) == ".tgz") { + if (!fi.isDirectory() && filepath.extname(file) === ".tgz") { exec.helmExec(`inspect values "${file}"`, printer); return; } else if (fi.isDirectory() && fs.existsSync(filepath.join(file, "Chart.yaml"))) { @@ -46,25 +46,24 @@ export class HelmInspectDocumentProvider implements vscode.TextDocumentContentPr // Provide an HTML-formatted preview window. export class HelmTemplatePreviewDocumentProvider implements vscode.TextDocumentContentProvider { - private _onDidChange = new vscode.EventEmitter(); + private onDidChangeEmitter = new vscode.EventEmitter(); get onDidChange(): vscode.Event { - return this._onDidChange.event; + return this.onDidChangeEmitter.event; } public update(uri: vscode.Uri) { - this._onDidChange.fire(uri); + this.onDidChangeEmitter.fire(uri); } public provideTextDocumentContent(uri: vscode.Uri, tok: vscode.CancellationToken): vscode.ProviderResult { return new Promise((resolve, reject) => { // The URI is the encapsulated path to the template to render. - //let tpl = uri.fsPath if (!vscode.window.activeTextEditor) { logger.helm.log("FIXME: no editor selected"); return; } - let tpl = vscode.window.activeTextEditor.document.fileName; + const tpl = vscode.window.activeTextEditor.document.fileName; // First, we need to get the top-most chart: exec.pickChartForFile(tpl, { warnIfNoCharts: true }, (chartPath) => { @@ -74,18 +73,17 @@ export class HelmTemplatePreviewDocumentProvider implements vscode.TextDocumentC } const reltpl = filepath.relative(chartPath, tpl); exec.helmExec(`template "${chartPath}" --execute "${reltpl}"`, (code, out, err) => { - if (code != 0) { + if (code !== 0) { resolve(previewBody("Chart Preview", "Failed template call." + err, true)); return; } - if (filepath.basename(reltpl) != "NOTES.txt") { + if (filepath.basename(reltpl) !== "NOTES.txt") { try { - const res = YAML.parse(out); + YAML.parse(out); } catch (e) { // TODO: Figure out the best way to display this message, but have it go away when the // file parses correctly. - //resolve(previewBody("Chart Preview", "Invalid YAML: " + err.message, true)) vscode.window.showErrorMessage(`YAML failed to parse: ${ e.message }`); } } diff --git a/src/helm.exec.ts b/src/helm.exec.ts index 01a678df9..682478bb2 100644 --- a/src/helm.exec.ts +++ b/src/helm.exec.ts @@ -22,7 +22,7 @@ export enum EnsureMode { export function helmVersion() { helmExec("version -c", (code, out, err) => { - if (code != 0) { + if (code !== 0) { vscode.window.showErrorMessage(err); return; } @@ -36,7 +36,7 @@ export function helmVersion() { export function helmTemplate() { pickChart((path) => { helmExec(`template "${path}"`, (code, out, err) => { - if (code != 0) { + if (code !== 0) { vscode.window.showErrorMessage(err); return; } @@ -47,13 +47,13 @@ export function helmTemplate() { } export function helmTemplatePreview() { - let editor = vscode.window.activeTextEditor; + const editor = vscode.window.activeTextEditor; if (!editor) { vscode.window.showInformationMessage("No active editor."); return; } - let filePath = editor.document.fileName; + const filePath = editor.document.fileName; if (filePath.indexOf("templates") < 0 ) { vscode.window.showInformationMessage("Not a template: " +filePath); return; @@ -63,8 +63,8 @@ export function helmTemplatePreview() { return; } - let u = vscode.Uri.parse(helm.PREVIEW_URI); - let f = filepath.basename(filePath); + const u = vscode.Uri.parse(helm.PREVIEW_URI); + const f = filepath.basename(filePath); vscode.commands.executeCommand("vscode.previewHtml", u, vscode.ViewColumn.Two, `Preview ${ f }`); helm.recordPreviewHasBeenShown(); } @@ -75,7 +75,7 @@ export function helmDepUp() { helmExec(`dep up "${path}"`, (code, out, err) => { logger.log(out); logger.log(err); - if (code != 0) { + if (code !== 0) { logger.log("⎈⎈⎈ UPDATE FAILED"); } }); @@ -93,7 +93,7 @@ export async function helmCreate(): Promise { }).then((name) => { const fullpath = filepath.join(folder.uri.fsPath, name); helmExec(`create "${fullpath}"`, (code, out, err) => { - if (code != 0) { + if (code !== 0) { vscode.window.showErrorMessage(err); } }); @@ -107,7 +107,7 @@ export function helmLint() { helmExec(`lint "${path}"`, (code, out, err) => { logger.log(out); logger.log(err); - if (code != 0) { + if (code !== 0) { logger.log("⎈⎈⎈ LINTING FAILED"); } }); @@ -124,7 +124,7 @@ export function helmInspectValues(u: vscode.Uri) { if (!ensureHelm(EnsureMode.Alert)) { return; } - let uri = vscode.Uri.parse("helm-inspect-values://" + u.fsPath); + const uri = vscode.Uri.parse("helm-inspect-values://" + u.fsPath); vscode.commands.executeCommand("vscode.previewHtml", uri, vscode.ViewColumn.Two, "Inspect"); } @@ -135,7 +135,7 @@ export function helmDryRun() { helmExec(`install --dry-run --debug "${path}"`, (code, out, err) => { logger.log(out); logger.log(err); - if (code != 0) { + if (code !== 0) { logger.log("⎈⎈⎈ INSTALL FAILED"); } }); @@ -153,17 +153,17 @@ export function pickChart(fn) { return; } vscode.workspace.findFiles("**/Chart.yaml", "", 1024).then((matches) => { - switch(matches.length) { + switch (matches.length) { case 0: vscode.window.showErrorMessage("No charts found"); return; case 1: // Assume that if there is only one chart, that's the one to run. - let p = filepath.dirname(matches[0].fsPath); + const p = filepath.dirname(matches[0].fsPath); fn(p); return; default: - let paths = []; + const paths = []; // TODO: This would be so much cooler if the QuickPick parsed the Chart.yaml // and showed the chart name instead of the path. matches.forEach((item) => { @@ -187,7 +187,7 @@ class Chart { // Load a chart object export function loadChartMetadata(chartDir: string): Chart { - let f = filepath.join(chartDir, "Chart.yaml"); + const f = filepath.join(chartDir, "Chart.yaml"); let c; try { c = YAML.load(f); @@ -200,8 +200,7 @@ export function loadChartMetadata(chartDir: string): Chart { // Given a file, show any charts that this file belongs to. export function pickChartForFile(file: string, options: PickChartUIOptions, fn) { vscode.workspace.findFiles("**/Chart.yaml", "", 1024).then((matches) => { - //logger.log(`Found ${ matches.length } charts`) - switch(matches.length) { + switch (matches.length) { case 0: if (options.warnIfNoCharts) { vscode.window.showErrorMessage("No charts found"); @@ -209,15 +208,15 @@ export function pickChartForFile(file: string, options: PickChartUIOptions, fn) return; case 1: // Assume that if there is only one chart, that's the one to run. - let p = filepath.dirname(matches[0].fsPath); + const p = filepath.dirname(matches[0].fsPath); fn(p); return; default: - let paths = []; + const paths = []; matches.forEach((item) => { - let dirname = filepath.dirname(item.fsPath); - let rel = filepath.relative(dirname, file); + const dirname = filepath.dirname(item.fsPath); + const rel = filepath.relative(dirname, file); // If the present file is not in a subdirectory of the parent chart, skip the chart. if (rel.indexOf("..") >= 0) { @@ -229,7 +228,7 @@ export function pickChartForFile(file: string, options: PickChartUIOptions, fn) ); }); - if (paths.length == 0) { + if (paths.length === 0) { if (options.warnIfNoCharts) { vscode.window.showErrorMessage("Chart not found for " + file); } @@ -257,7 +256,7 @@ export function helmExec(args: string, fn) { } const configuredBin: string | undefined = vscode.workspace.getConfiguration('vs-kubernetes')['vs-kubernetes.helm-path']; const bin = configuredBin ? `"${configuredBin}"` : "helm"; - const cmd = bin + " " + args; + const cmd = `${bin} ${args}`; shell.exec(cmd, fn); } @@ -308,12 +307,12 @@ export function insertRequirement() { prompt: "Chart", placeHolder: "stable/redis", }).then((val) => { - let req = searchForChart(val); + const req = searchForChart(val); if (!req) { vscode.window.showErrorMessage(`Chart ${ val } not found`); return; } - let ed = vscode.window.activeTextEditor; + const ed = vscode.window.activeTextEditor; if (!ed) { logger.log(YAML.stringify(req)); return; @@ -324,27 +323,24 @@ export function insertRequirement() { // searchForChart takes a 'repo/name' and returns an entry suitable for requirements export function searchForChart(name: string, version?: string): Requirement { - let parts = name.split("/", 2); - if (parts.length != 2) { + const parts = name.split("/", 2); + if (parts.length !== 2) { logger.log("Chart should be of the form REPO/CHARTNAME"); return; } - let hh = helmHome(); - let reposFile = filepath.join(hh, "repository", "repositories.yaml"); + const hh = helmHome(); + const reposFile = filepath.join(hh, "repository", "repositories.yaml"); if (!fs.existsSync(reposFile)) { - vscode.window.showErrorMessage("Helm repositories file " + reposFile + " not found."); + vscode.window.showErrorMessage(`Helm repositories file ${reposFile} not found.`); return; } - let repos = YAML.load(reposFile); + const repos = YAML.load(reposFile); let req; repos.repositories.forEach((repo) => { - //logger.log("repo: " + repo.name) - if (repo.name == parts[0]) { - //let cache = YAML.load(filepath.join(hh, "repository", "cache", repo.cache)) - let cache = YAML.load(repo.cache); + if (repo.name === parts[0]) { + const cache = YAML.load(repo.cache); _.each(cache.entries, (releases, name) => { - //logger.log("entry: " + name) - if (name == parts[1]) { + if (name === parts[1]) { req = new Requirement(); req.repository = repo.url; req.name = name; @@ -359,6 +355,6 @@ export function searchForChart(name: string, version?: string): Requirement { } export function helmHome(): string { - let h = process.env.HOME; + const h = process.env.HOME; return process.env["HELM_HOME"] || filepath.join(h, '.helm'); } \ No newline at end of file diff --git a/src/helm.funcmap.ts b/src/helm.funcmap.ts index faf024d2f..8714cbf40 100644 --- a/src/helm.funcmap.ts +++ b/src/helm.funcmap.ts @@ -12,9 +12,9 @@ export class FuncMap { public helmVals(): vscode.CompletionItem[] { return [ this.v("Values", ".Values", `The values made available through values.yaml, --set and -f.`), - this.v("Chart",".Chart","Chart metadata"), - this.v("Files",".Files.Get $str","access non-template files within the chart"), - this.v("Capabilities",".Capabilities.KubeVersion ","access capabilities of Kubernetes"), + this.v("Chart", ".Chart", "Chart metadata"), + this.v("Files", ".Files.Get $str", "access non-template files within the chart"), + this.v("Capabilities", ".Capabilities.KubeVersion ", "access capabilities of Kubernetes"), this.v("Release", ".Release", `Built-in release values. Attributes include: - .Release.Name: Name of the release - .Release.Time: Time release was executed @@ -221,29 +221,29 @@ export class FuncMap { this.f("expandenv", "expandenv $str", "(UNSUPPORTED IN HELM) expand env vars in string"), // SemVer this.f("semver", "semver $version", "parse a SemVer string (1.2.3-alpha.4+1234). [Reference](http://masterminds.github.io/sprig/semver.html)"), - this.f("semverCompare","semverCompare $ver1 $ver2","Compare $ver1 and $ver2. $ver1 can be a [SemVer range]((http://masterminds.github.io/sprig/semver.html)."), + this.f("semverCompare", "semverCompare $ver1 $ver2", "Compare $ver1 and $ver2. $ver1 can be a [SemVer range]((http://masterminds.github.io/sprig/semver.html)."), // Reflection - this.f("kindOf","kindOf $val","return the Go kind (primitive type) of a value"), - this.f("kindIs","kindIs $kind $val","returns true if $val is of kind $kind"), - this.f("typeOf","typeOf $val","returns a string indicate the type of $val"), - this.f("typeIs","typeIs $type $val","returns true if $val is of type $type"), - this.f("typeIsLike","typeIsLike $substr $val","returns true if $substr is found in $val's type"), + this.f("kindOf", "kindOf $val", "return the Go kind (primitive type) of a value"), + this.f("kindIs", "kindIs $kind $val", "returns true if $val is of kind $kind"), + this.f("typeOf", "typeOf $val", "returns a string indicate the type of $val"), + this.f("typeIs", "typeIs $type $val", "returns true if $val is of type $type"), + this.f("typeIsLike", "typeIsLike $substr $val", "returns true if $substr is found in $val's type"), // Crypto - this.f("sha256sum","sha256sum $str","generate a SHA-256 sum of $str"), - this.f("derivePassword","derivePassword $counter $long $pass $user $domain","generate a password from [Master Password](http://masterpasswordapp.com/algorithm.html) spec"), - this.f("generatePrivateKey","generatePrivateKey 'ecdsa'","generate private PEM key (takes dsa, rsa, or ecdsa)"), + this.f("sha256sum", "sha256sum $str", "generate a SHA-256 sum of $str"), + this.f("derivePassword", "derivePassword $counter $long $pass $user $domain", "generate a password from [Master Password](http://masterpasswordapp.com/algorithm.html) spec"), + this.f("generatePrivateKey", "generatePrivateKey 'ecdsa'", "generate private PEM key (takes dsa, rsa, or ecdsa)"), ] } public f(name: string, args: string, doc: string): vscode.CompletionItem { - let i = new vscode.CompletionItem(name, vscode.CompletionItemKind.Function) + const i = new vscode.CompletionItem(name, vscode.CompletionItemKind.Function) i.detail = args i.documentation = doc return i } public v(name: string, use: string, doc: string): vscode.CompletionItem { - let i = new vscode.CompletionItem(name, vscode.CompletionItemKind.Constant) + const i = new vscode.CompletionItem(name, vscode.CompletionItemKind.Constant) i.detail = use i.documentation = doc return i diff --git a/src/helm.hoverProvider.ts b/src/helm.hoverProvider.ts index 6536c2837..1ea1d78d1 100644 --- a/src/helm.hoverProvider.ts +++ b/src/helm.hoverProvider.ts @@ -3,7 +3,6 @@ import { FuncMap } from './helm.funcmap'; import { Resources } from './helm.resources'; import { isPositionInKey } from "./yaml-support/yaml-util"; - // Provide hover support export class HelmTemplateHoverProvider implements vscode.HoverProvider { private funcmap; @@ -11,29 +10,29 @@ export class HelmTemplateHoverProvider implements vscode.HoverProvider { private resmap; public constructor() { - let fm = new FuncMap(); - let rs = new Resources(); + const fm = new FuncMap(); + const rs = new Resources(); this.funcmap = fm.all(); this.valmap = fm.helmVals(); this.resmap = rs.all(); } public provideHover(doc: vscode.TextDocument, pos: vscode.Position, tok: vscode.CancellationToken): vscode.ProviderResult { - let wordRange = doc.getWordRangeAtPosition(pos); - let word = wordRange ? doc.getText(wordRange) : ""; - if (word == "") { + const wordRange = doc.getWordRangeAtPosition(pos); + const word = wordRange ? doc.getText(wordRange) : ""; + if (word === "") { return Promise.resolve(null); } if (this.inActionVal(doc, pos, word)) { - let found = this.findVal(word); + const found = this.findVal(word); if (found) { return new vscode.Hover(found, wordRange); } } if (this.inAction(doc, pos, word)) { - let found = this.findFunc(word); + const found = this.findFunc(word); if (found) { return new vscode.Hover(found, wordRange); } @@ -52,7 +51,7 @@ export class HelmTemplateHoverProvider implements vscode.HoverProvider { } catch (ex) { // ignore since the editing yaml may not be able to parse } - let found = this.findResourceDef(word); + const found = this.findResourceDef(word); if (found) { return new vscode.Hover(found, wordRange); } @@ -61,42 +60,42 @@ export class HelmTemplateHoverProvider implements vscode.HoverProvider { } private inAction(doc: vscode.TextDocument, pos: vscode.Position, word: string): boolean { - let lineText = doc.lineAt(pos.line).text; - let r = new RegExp("{{[^}]*[\\s\\(|]?("+word+")\\s[^{]*}}"); + const lineText = doc.lineAt(pos.line).text; + const r = new RegExp(`{{[^}]*[\\s\\(|]?(${word})\\s[^{]*}}`); return r.test(lineText); } private notInAction(doc: vscode.TextDocument, pos: vscode.Position, word: string): boolean { - let lineText = doc.lineAt(pos.line).text; - let r = new RegExp("(^|})[^{]*("+word+")"); + const lineText = doc.lineAt(pos.line).text; + const r = new RegExp(`(^|})[^{]*(${word})`); return r.test(lineText); } - private findFunc(word: string): vscode.MarkedString[] | string{ + private findFunc(word: string): vscode.MarkedString[] | string { for (const item of this.funcmap) { - if (item.label == word) { - return [{language: "helm", value:`{{ ${ item.detail } }}`}, `${ item.documentation }`]; + if (item.label === word) { + return [{language: "helm", value: `{{ ${ item.detail } }}`}, `${ item.documentation }`]; } } } private inActionVal(doc: vscode.TextDocument, pos: vscode.Position, word: string): boolean { - let lineText = doc.lineAt(pos.line).text; - let r = new RegExp("{{[^}]*\\.("+word+")[\\.\\s]?[^{]*}}"); + const lineText = doc.lineAt(pos.line).text; + const r = new RegExp(`{{[^}]*\\.(${word})[\\.\\s]?[^{]*}}`); return r.test(lineText); } - private findVal(word: string): vscode.MarkedString[] | string{ + private findVal(word: string): vscode.MarkedString[] | string { for (const item of this.valmap) { - if (item.label == word) { - return [{language: "helm", value:`{{ ${ item.detail } }}`}, `${ item.documentation }`]; + if (item.label === word) { + return [{language: "helm", value: `{{ ${ item.detail } }}`}, `${ item.documentation }`]; } } } private findResourceDef(word: string): vscode.MarkedString[] | string { for (const item of this.resmap) { - if (item.label == word) { - return [{language: "helm", value:`${ item.detail }`}, `${ item.documentation }`]; + if (item.label === word) { + return [{language: "helm", value: `${ item.detail }`}, `${ item.documentation }`]; } } } diff --git a/src/helm.requirementsCodeLens.ts b/src/helm.requirementsCodeLens.ts index dc43fb418..5f28d1f22 100644 --- a/src/helm.requirementsCodeLens.ts +++ b/src/helm.requirementsCodeLens.ts @@ -7,18 +7,18 @@ export class HelmRequirementsCodeLensProvider implements vscode.CodeLensProvider } // Find the dependencies section - let i = doc.getText().indexOf("dependencies:"); - let start = doc.positionAt(i); - let range = doc.getWordRangeAtPosition(start); + const i = doc.getText().indexOf("dependencies:"); + const start = doc.positionAt(i); + const range = doc.getWordRangeAtPosition(start); if (range.isEmpty) { return; } - let update = new vscode.CodeLens(range, { + const update = new vscode.CodeLens(range, { title: "update dependencies", command: "extension.helmDepUp" }); - let insert = new vscode.CodeLens(range, { + const insert = new vscode.CodeLens(range, { title: "insert dependency", command: "extension.helmInsertReq", }); diff --git a/src/helm.resources.ts b/src/helm.resources.ts index e80d9539a..d2ad06a8e 100644 --- a/src/helm.resources.ts +++ b/src/helm.resources.ts @@ -8,15 +8,15 @@ import { shell } from './shell'; // Resources describes Kubernetes resource keywords. export class Resources { public all(): vscode.CompletionItem[] { - let home = shell.home(); - let schemaDir = filepath.join(home, ".kube/schema"); + const home = shell.home(); + const schemaDir = filepath.join(home, ".kube/schema"); if (!shelljs.test("-d", schemaDir)) { // Return the default set. return this.v1(); } // Otherwise, try to dynamically build completion items from the // entire schema. - let kversion = _.last(shelljs.ls(schemaDir)); + const kversion = _.last(shelljs.ls(schemaDir)); console.log("Loading schema for version " + kversion); // Inside of the schemaDir, there are some top-level copies of the schemata. @@ -25,20 +25,20 @@ export class Resources { // more likely to get the ones that this user is actually using, including // TPRs. let res = []; - let path = filepath.join(schemaDir, kversion); + const path = filepath.join(schemaDir, kversion); shelljs.ls(path).forEach((item) => { - let itemPath = filepath.join(path, item); + const itemPath = filepath.join(path, item); if (shelljs.test('-d', itemPath)) { return; } - let schema = JSON.parse(shelljs.cat(itemPath)); + const schema = JSON.parse(shelljs.cat(itemPath)); if (!schema.models) { return; } console.log("Adding schema " + itemPath); res = res.concat(this.fromSchema(schema.models)); }); - console.log("Attached " + res.length + " resource kinds"); + console.log(`Attached ${res.length} resource kinds`); return res; } @@ -48,11 +48,10 @@ export class Resources { // Extract hover documentation from a Swagger model. fromSchema(schema): vscode.CompletionItem[] { - let res = []; + const res = []; _.each(schema, (v, k) => { - let i = k.lastIndexOf("."); - //let version = k.substr(0, i) - let kind = k.substr(i+1); + const i = k.lastIndexOf("."); + const kind = k.substr(i+1); res.push(val(kind, `kind: ${ kind }`, v.description)); _.each(v.properties, (spec, label) => { let type = "undefined"; @@ -65,7 +64,7 @@ export class Resources { break; case "array": // Try to give a pretty type. - if(spec.items.type) { + if (spec.items.type) { type = spec.items.type + "[]"; break; } else if (spec.items["$ref"]) { @@ -88,13 +87,14 @@ export class Resources { } function d(name: string, use: string, doc: string): vscode.CompletionItem { - let i = new vscode.CompletionItem(name, vscode.CompletionItemKind.Variable); + const i = new vscode.CompletionItem(name, vscode.CompletionItemKind.Variable); i.detail = use; i.documentation = doc; return i; } + function val(name: string, use: string, doc: string): vscode.CompletionItem { - let i = new vscode.CompletionItem(name, vscode.CompletionItemKind.Value); + const i = new vscode.CompletionItem(name, vscode.CompletionItemKind.Value); i.detail = use; i.documentation = doc; return i; diff --git a/src/hostutils.ts b/src/hostutils.ts index 4be9c4d1c..18fef281f 100644 --- a/src/hostutils.ts +++ b/src/hostutils.ts @@ -9,4 +9,3 @@ export async function showWorkspaceFolderPick(): Promise } return await vscode.window.showWorkspaceFolderPick(); } - diff --git a/src/kubeNamespace.ts b/src/kubeNamespace.ts deleted file mode 100644 index a516e84bc..000000000 --- a/src/kubeNamespace.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { refreshExplorer, promptKindName } from './extension'; -import * as kubectlUtils from './kubectlUtils'; -import * as kuberesources from './kuberesources'; -import * as explorer from './explorer'; -import { Kubectl } from './kubectl'; - -export async function useNamespaceKubernetes(explorerNode: explorer.KubernetesObject, kubectl: Kubectl) { - if (explorerNode) { - if (await kubectlUtils.switchNamespace(kubectl, explorerNode.id)) { - refreshExplorer(); - return; - } - } else { - const currentNS = await kubectlUtils.currentNamespace(kubectl); - promptKindName([kuberesources.allKinds.namespace], undefined, - { - prompt: 'What namespace do you want to use?', - placeHolder: 'Enter the namespace to switch to or press enter to select from available list', - filterNames: [currentNS] - }, - async (resource) => { - if (resource) { - let toSwitchNamespace = resource; - // resource will be of format /, when picked up from the quickpick - if (toSwitchNamespace.lastIndexOf('/') !== -1) { - toSwitchNamespace = toSwitchNamespace.substring(toSwitchNamespace.lastIndexOf('/') + 1); - } - // Switch if an only if the currentNS and toSwitchNamespace are different - if (toSwitchNamespace && currentNS !== toSwitchNamespace) { - const promiseSwitchNS = await kubectlUtils.switchNamespace(kubectl, toSwitchNamespace); - if (promiseSwitchNS) { - refreshExplorer(); - } - } - } - }); - } -} diff --git a/src/kubeconfig.ts b/src/kubeconfig.ts index ae2235ec9..4498882d6 100644 --- a/src/kubeconfig.ts +++ b/src/kubeconfig.ts @@ -1,6 +1,5 @@ 'use strict'; -import { host } from './host'; import { shell } from './shell'; import { fs } from './fs'; import * as yaml from 'js-yaml'; @@ -15,7 +14,6 @@ export function readKubectlConfig(): Promise { } const kcconfigf = data; const kcconfig = yaml.safeLoad(kcconfigf); - const apiVersion = kcconfig['apiVersion']; const currentContextName = kcconfig['current-context']; const currentContextDef = kcconfig['contexts'].find((c) => c['name'] === currentContextName); if (!currentContextDef) { diff --git a/src/kubectl.ts b/src/kubectl.ts index 468fdd5c2..1578a4511 100644 --- a/src/kubectl.ts +++ b/src/kubectl.ts @@ -118,7 +118,7 @@ async function checkForKubectlInternal(context: Context, errorMessageMode: Check const contextMessage = getCheckKubectlContextMessage(errorMessageMode); const inferFailedMessage = 'Could not find "kubectl" binary.' + contextMessage; - const configuredFileMissingMessage = bin + ' does not exist!' + contextMessage; + const configuredFileMissingMessage = `${bin} does not exist! ${contextMessage}`; return await binutil.checkForBinary(context, bin, binName, inferFailedMessage, configuredFileMissingMessage, errorMessageMode !== 'silent'); } @@ -151,7 +151,7 @@ async function invokeWithProgress(context: Context, command: string, progressMes async function invokeAsync(context: Context, command: string, stdin?: string): Promise { if (await checkPresent(context, 'command')) { const bin = baseKubectlPath(context); - let cmd = bin + ' ' + command; + const cmd = `${bin} ${command}`; return await context.shell.exec(cmd, stdin); } else { return { code: -1, stdout: '', stderr: '' }; @@ -190,7 +190,7 @@ async function runAsTerminal(context: Context, command: string[], terminalName: async function kubectlInternal(context: Context, command: string, handler: ShellHandler): Promise { if (await checkPresent(context, 'command')) { const bin = baseKubectlPath(context); - let cmd = bin + ' ' + command; + const cmd = `${bin} ${command}`; context.shell.exec(cmd, null).then(({code, stdout, stderr}) => handler(code, stdout, stderr)); } } @@ -237,6 +237,6 @@ async function asJson(context: Context, command: string): Promise { - let ns = namespace || await currentNamespace(kubectl); + const ns = namespace || await currentNamespace(kubectl); let nsFlag = `--namespace=${ns}`; if (ns === 'all') { nsFlag = '--all-namespaces'; @@ -181,7 +181,7 @@ export async function getPods(kubectl: Kubectl, selector: any, namespace: string } if (matchLabelObj) { Object.keys(matchLabelObj).forEach((key) => { - labels.push(key + "=" + matchLabelObj[key]); + labels.push(`${key}=${matchLabelObj[key]}`); }); } let labelStr = ""; @@ -244,13 +244,15 @@ export async function switchNamespace(kubectl: Kubectl, namespace: string): Prom * @return the deployment name. */ export async function runAsDeployment(kubectl: Kubectl, deploymentName: string, image: string, exposedPorts: number[], env: any): Promise { - let imageName = image.split(":")[0]; - let imagePrefix = imageName.substring(0, imageName.lastIndexOf("/")+1); + const imageName = image.split(":")[0]; + const imagePrefix = imageName.substring(0, imageName.lastIndexOf("/")+1); + if (!deploymentName) { - let baseName = imageName.substring(imageName.lastIndexOf("/")+1); - const deploymentName = `${baseName}-${Date.now()}`; + const baseName = imageName.substring(imageName.lastIndexOf("/")+1); + deploymentName = `${baseName}-${Date.now()}`; } - let runCmd = [ + + const runCmd = [ "run", deploymentName, `--image=${image}`, @@ -258,10 +260,12 @@ export async function runAsDeployment(kubectl: Kubectl, deploymentName: string, ...exposedPorts.map((port) => `--port=${port}`), ...Object.keys(env || {}).map((key) => `--env="${key}=${env[key]}"`) ]; + const runResult = await kubectl.invokeAsync(runCmd.join(" ")); if (runResult.code !== 0) { throw new Error(`Failed to run the image "${image}" on Kubernetes: ${runResult.stderr}`); } + return deploymentName; } diff --git a/src/kuberesources.virtualfs.ts b/src/kuberesources.virtualfs.ts index 18ef82e3d..84ceb1e65 100644 --- a/src/kuberesources.virtualfs.ts +++ b/src/kuberesources.virtualfs.ts @@ -11,9 +11,9 @@ export const K8S_RESOURCE_SCHEME = "k8smsx"; export class KubernetesResourceVirtualFileSystemProvider implements FileSystemProvider { constructor(private readonly kubectl: Kubectl, private readonly host: Host, private readonly rootPath: string) { } - private readonly _onDidChangeFile: EventEmitter = new EventEmitter(); + private readonly onDidChangeFileEmitter: EventEmitter = new EventEmitter(); - onDidChangeFile: Event = this._onDidChangeFile.event; + onDidChangeFile: Event = this.onDidChangeFileEmitter.event; watch(uri: Uri, options: { recursive: boolean; excludes: string[] }): Disposable { // It would be quite neat to implement this to watch for changes diff --git a/src/logger.ts b/src/logger.ts index 5805d3ecb..897e2cb71 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,6 +1,6 @@ import * as vscode from 'vscode'; -const HelmChannel = "Helm"; +const HELM_CHANNEL = "Helm"; interface Logger extends vscode.Disposable { log(msg: string): void; @@ -11,7 +11,7 @@ interface Logger extends vscode.Disposable { // A console is disposable, since it allocates a channel. class LoggingConsole implements Logger { channel: vscode.OutputChannel; - constructor(channelName: string){ + constructor(channelName: string) { this.channel = vscode.window.createOutputChannel(channelName); } log(msg: string) { @@ -24,4 +24,4 @@ class LoggingConsole implements Logger { } } -export const helm: Logger = new LoggingConsole(HelmChannel); +export const helm: Logger = new LoggingConsole(HELM_CHANNEL); diff --git a/src/schema-formatting.ts b/src/schema-formatting.ts index b917375fd..ea12e36da 100644 --- a/src/schema-formatting.ts +++ b/src/schema-formatting.ts @@ -8,7 +8,7 @@ export interface Typed { // get type description defined in JSON-schema export function formatType(p: Typed): string { const baseType = p.type || 'object'; - if (baseType == 'array') { + if (baseType === 'array') { return formatType(p.items) + '[]'; } return baseType; diff --git a/src/shell.ts b/src/shell.ts index cbe73e107..e15f8a89f 100644 --- a/src/shell.ts +++ b/src/shell.ts @@ -107,7 +107,7 @@ async function exec(cmd: string, stdin?: string): Promise { function execCore(cmd: string, opts: any, stdin?: string): Promise { return new Promise((resolve, reject) => { - let proc = shelljs.exec(cmd, opts, (code, stdout, stderr) => resolve({code : code, stdout : stdout, stderr : stderr})); + const proc = shelljs.exec(cmd, opts, (code, stdout, stderr) => resolve({code : code, stdout : stdout, stderr : stderr})); if (stdin) { proc.stdin.end(stdin); } @@ -115,8 +115,8 @@ function execCore(cmd: string, opts: any, stdin?: string): Promise } export function shellEnvironment(baseEnvironment: any): any { - let env = Object.assign({}, baseEnvironment); - let pathVariable = pathVariableName(env); + const env = Object.assign({}, baseEnvironment); + const pathVariable = pathVariableName(env); for (const tool of ['kubectl', 'helm', 'draft']) { const toolPath = vscode.workspace.getConfiguration('vs-kubernetes')[`vs-kubernetes.${tool}-path`]; if (toolPath) { diff --git a/src/telemetry-helper.ts b/src/telemetry-helper.ts index 615910779..8b63ddbaa 100644 --- a/src/telemetry-helper.ts +++ b/src/telemetry-helper.ts @@ -1,4 +1,3 @@ -import TelemetryReporter from 'vscode-extension-telemetry'; import { reporter } from './telemetry'; export function telemetrise(command: string, callback: (...args: any[]) => any): (...args: any[]) => any { diff --git a/src/telemetry.ts b/src/telemetry.ts index 7d15b1417..dfc6c230a 100644 --- a/src/telemetry.ts +++ b/src/telemetry.ts @@ -7,7 +7,7 @@ export class Reporter extends vscode.Disposable { constructor(ctx: vscode.ExtensionContext) { super(() => reporter.dispose()); - let packageInfo = getPackageInfo(ctx); + const packageInfo = getPackageInfo(ctx); reporter = packageInfo && new TelemetryReporter(packageInfo.name, packageInfo.version, packageInfo.aiKey); } @@ -20,7 +20,7 @@ interface IPackageInfo { } function getPackageInfo(context: vscode.ExtensionContext): IPackageInfo { - let extensionPackage = require(context.asAbsolutePath('./package.json')); + const extensionPackage = require(context.asAbsolutePath('./package.json')); if (extensionPackage) { return { name: extensionPackage.name, diff --git a/src/wizard.ts b/src/wizard.ts index 287b003cf..a3bcbcfc7 100644 --- a/src/wizard.ts +++ b/src/wizard.ts @@ -128,4 +128,3 @@ export function fromShellJson(sr: ShellResult, processor?: (raw: any) => T): } return { succeeded: false, error: [ sr.stderr ] }; } - diff --git a/src/yaml-support/yaml-locator.ts b/src/yaml-support/yaml-locator.ts index 8982fb5b5..ff8e9b7da 100644 --- a/src/yaml-support/yaml-locator.ts +++ b/src/yaml-support/yaml-locator.ts @@ -48,7 +48,7 @@ export interface YamlMatchedElement { */ export class YamlLocator { // a mapping of URIs to cached documents - private _cache: { [key: string]: YamlCachedDocuments; } = {}; + private cache: { [key: string]: YamlCachedDocuments; } = {}; /** * Parse the yaml text and find the best node&document for the given position. @@ -60,7 +60,7 @@ export class YamlLocator { public getMatchedElement(textDocument: vscode.TextDocument, pos: vscode.Position): YamlMatchedElement { const key: string = textDocument.uri.toString(); this.ensureCache(key, textDocument); - const cacheEntry = this._cache[key]; + const cacheEntry = this.cache[key]; // findNodeAtPosition will find the matched node at given position return findNodeAtPosition(cacheEntry.yamlDocs, cacheEntry.lineLengths, pos.line, pos.character); } @@ -75,21 +75,21 @@ export class YamlLocator { public getYamlDocuments(textDocument: vscode.TextDocument): YamlDocument[] { const key: string = textDocument.uri.toString(); this.ensureCache(key, textDocument); - return this._cache[key].yamlDocs; + return this.cache[key].yamlDocs; } private ensureCache(key: string, textDocument: vscode.TextDocument): void { - if (!this._cache[key]) { - this._cache[key] = { version: -1 }; + if (!this.cache[key]) { + this.cache[key] = { version: -1 }; } - if (this._cache[key].version !== textDocument.version) { + if (this.cache[key].version !== textDocument.version) { // the document and line lengths from parse method is cached into YamlCachedDocuments to avoid duplicate // parse against the same text. const { documents, lineLengths } = parse(textDocument.getText()); - this._cache[key].yamlDocs = documents; - this._cache[key].lineLengths = lineLengths; - this._cache[key].version = textDocument.version; + this.cache[key].yamlDocs = documents; + this.cache[key].lineLengths = lineLengths; + this.cache[key].version = textDocument.version; } } } diff --git a/src/yaml-support/yaml-schema.ts b/src/yaml-support/yaml-schema.ts index 1459a1bee..ea5f98d44 100644 --- a/src/yaml-support/yaml-schema.ts +++ b/src/yaml-support/yaml-schema.ts @@ -30,20 +30,20 @@ declare type YamlSchemaContributor = (schema: string, class KubernetesSchemaHolder { // the schema for kubernetes - private _definitions: { [key: string]: KubernetesSchema; } = {}; + private definitions: { [key: string]: KubernetesSchema; } = {}; - private _schemaEnums: { [key: string]: { [key: string]: [string[]] }; }; + private schemaEnums: { [key: string]: { [key: string]: [string[]] }; }; // load the kubernetes schema and make some modifications to $ref node public loadSchema(schemaFile: string, schemaEnumFile?: string): void { const schemaRaw = util.loadJson(schemaFile); - this._schemaEnums = schemaEnumFile ? util.loadJson(schemaEnumFile) : {}; + this.schemaEnums = schemaEnumFile ? util.loadJson(schemaEnumFile) : {}; const definitions = schemaRaw.definitions; for (const name of Object.keys(definitions)) { this.saveSchemaWithManifestStyleKeys(name, definitions[name]); } - for (const schema of _.values(this._definitions) ) { + for (const schema of _.values(this.definitions) ) { if (schema.properties) { // the swagger schema has very short description on properties, we need to get the actual type of // the property and provide more description/properties details, just like `kubernetes explain` do. @@ -77,7 +77,7 @@ class KubernetesSchemaHolder { // get kubernetes schema by the key public lookup(key: string): KubernetesSchema { - return key ? this._definitions[key.toLowerCase()] : undefined; + return key ? this.definitions[key.toLowerCase()] : undefined; } /** @@ -135,10 +135,10 @@ class KubernetesSchemaHolder { // add enum field for pre-defined enums in schema-enums json file private loadEnumsForKubernetesSchema(node: KubernetesSchema) { - if (node.properties && this._schemaEnums[node.name]) { + if (node.properties && this.schemaEnums[node.name]) { _.each(node.properties, (propSchema, propKey) => { - if (this._schemaEnums[node.name][propKey]) { - propSchema.enum = this._schemaEnums[node.name][propKey]; + if (this.schemaEnums[node.name][propKey]) { + propSchema.enum = this.schemaEnums[node.name][propKey]; } }); } @@ -147,10 +147,10 @@ class KubernetesSchemaHolder { // save the schema to the _definitions private saveSchema(schema: KubernetesSchema): void { if (schema.name) { - this._definitions[schema.name.toLowerCase()] = schema; + this.definitions[schema.name.toLowerCase()] = schema; } if (schema.id) { - this._definitions[schema.id.toLowerCase()] = schema; + this.definitions[schema.id.toLowerCase()] = schema; } } @@ -209,18 +209,18 @@ function requestYamlSchemaUriCallback(resource: string): string { // see docs from YamlSchemaContributor function requestYamlSchemaContentCallback(uri: string): string { - const _uri = Uri.parse(uri); - if (_uri.scheme !== KUBERNETES_SCHEMA) { + const parsedUri = Uri.parse(uri); + if (parsedUri.scheme !== KUBERNETES_SCHEMA) { return undefined; } - if (!_uri.path || !_uri.path.startsWith('/')) { + if (!parsedUri.path || !parsedUri.path.startsWith('/')) { return undefined; } // slice(1) to remove the first '/' in schema // eg: kubernetes://schema/io.k8s.kubernetes.pkg.apis.extensions.v1beta1.httpingresspath will have // path '/io.k8s.kubernetes.pkg.apis.extensions.v1beta1.httpingresspath' - const manifestType = _uri.path.slice(1); + const manifestType = parsedUri.path.slice(1); // if it is a multiple choice, make an 'oneof' schema. if (manifestType.includes('+')) { const manifestRefList = manifestType.split('+').map(util.makeRefOnKubernetes); @@ -278,7 +278,6 @@ function getManifestStyleSchemas(originalSchema: any): KubernetesSchema[] { return schemas; } - // convert '#/definitions/com.github.openshift.origin.pkg.build.apis.build.v1.ImageLabel' to // 'com.github.openshift.origin.pkg.build.apis.build.v1.ImageLabel' function getNameInDefinitions ($ref: string): string { @@ -290,7 +289,6 @@ function getNameInDefinitions ($ref: string): string { } } - // find redhat.vscode-yaml extension and try to activate it to get the yaml contributor async function activateYamlExtension(): Promise<{registerContributor: YamlSchemaContributor}> { const ext: vscode.Extension = vscode.extensions.getExtension(VSCODE_YAML_EXTENSION_ID); @@ -306,4 +304,3 @@ async function activateYamlExtension(): Promise<{registerContributor: YamlSchema } return yamlPlugin; } - diff --git a/src/yaml-support/yaml-snippet.ts b/src/yaml-support/yaml-snippet.ts index b75e64674..006645449 100644 --- a/src/yaml-support/yaml-snippet.ts +++ b/src/yaml-support/yaml-snippet.ts @@ -12,13 +12,12 @@ export interface CodeSnippet { readonly body: string; } - /** * A kubernetes completion provider provides yaml code snippets for kubernetes, eg: service, deployment. */ export class KubernetesCompletionProvider implements vscode.CompletionItemProvider { // storing all loaded yaml code snippets from ../../snippets folder - private _snippets: CodeSnippet[] = []; + private snippets: CodeSnippet[] = []; // default constructor public constructor() { @@ -41,14 +40,14 @@ export class KubernetesCompletionProvider implements vscode.CompletionItemProvid // load yaml code snippets from ../../snippets folder private loadCodeSnippets(): void { const snippetRoot = path.join(__dirname, '../../../snippets'); - this._snippets = fs.readdirSync(snippetRoot) + this.snippets = fs.readdirSync(snippetRoot) .filter((filename: string): boolean => filename.endsWith('.yaml')) .map((filename: string): CodeSnippet => this.readYamlCodeSnippet(path.join(snippetRoot, filename))); } // filter all internal code snippets using the parameter word private filterCodeSnippets(word: string): CodeSnippet[] { - return this._snippets.filter((snippet: CodeSnippet): boolean => + return this.snippets.filter((snippet: CodeSnippet): boolean => fuzzysearch(word.toLowerCase(), snippet.name.toLowerCase())); } diff --git a/src/yaml-support/yaml-util.ts b/src/yaml-support/yaml-util.ts index 5f7a83061..ff8511814 100644 --- a/src/yaml-support/yaml-util.ts +++ b/src/yaml-support/yaml-util.ts @@ -80,7 +80,7 @@ export function makeRefOnKubernetes(id: string): { $ref: string } { export function parseKubernetesGroupVersionKind(groupKindNodeItem: any): {id: string, apiVersion: string, kind: string} { const group = getStringValue(groupKindNodeItem, 'group', StringComparison.OrdinalIgnoreCase); const version = getStringValue(groupKindNodeItem, 'version', StringComparison.OrdinalIgnoreCase); - const apiVersion = group ? group + '/' + version: version; + const apiVersion = group ? `${group}/${version}`: version; const kind = getStringValue(groupKindNodeItem, 'kind', StringComparison.OrdinalIgnoreCase); return { id: apiVersion + GROUP_VERSION_KIND_SEPARATOR + kind, apiVersion, kind }; } @@ -116,9 +116,9 @@ function getStringValue(node, key: string, ignoreCase: StringComparison = String return node[key]; } if (ignoreCase === StringComparison.OrdinalIgnoreCase) { - for (const _key of Object.keys(node)) { - if (equalIgnoreCase(key, _key)) { - return node[_key]; + for (const nodeKey of Object.keys(node)) { + if (equalIgnoreCase(key, nodeKey)) { + return node[nodeKey]; } } } diff --git a/test/draft.test.ts b/test/draft.test.ts index bfc7abb69..1c33cbd30 100644 --- a/test/draft.test.ts +++ b/test/draft.test.ts @@ -1,14 +1,9 @@ -import * as vscode from 'vscode'; import * as assert from 'assert'; import * as textassert from './textassert'; import * as fakes from './fakes'; -import { Host } from '../src/host'; -import { Shell, ShellResult } from '../src/shell'; -import { FS } from '../src/fs'; import { create as draftCreate, CheckPresentMode as DraftCheckPresentMode } from '../src/draft/draft'; -import * as kuberesources from '../src/kuberesources'; interface FakeContext { host?: any; @@ -38,6 +33,7 @@ suite("draft tests", () => { suite("If draft is not on the path", () => { test("...and configuration is not present, then checkPresent reports an error", async () => { + /* tslint:disable-next-line:prefer-const */ let errors: string[] = []; const draft = draftCreateWithFakes({ host: fakes.host({errors: errors}) @@ -49,6 +45,7 @@ suite("draft tests", () => { }); test("...and configuration is present but file doesn't exist, then checkPresent reports an error", async () => { + /* tslint:disable-next-line:prefer-const */ let errors: string[] = []; const draft = draftCreateWithFakes({ host: fakes.host({errors: errors, configuration: draftFakePathConfig()}) @@ -60,6 +57,7 @@ suite("draft tests", () => { }); test("...and in silent mode, then no errors are reported", async () => { + /* tslint:disable-next-line:prefer-const */ let errors: string[] = []; const draft = draftCreateWithFakes({ host: fakes.host({errors: errors}) @@ -70,9 +68,10 @@ suite("draft tests", () => { }); test("...and configuration is present and file exists, then checkPresent does not report any messages", async () => { + /* tslint:disable-next-line:prefer-const */ let errors = []; - let warnings: string[] = []; - let infos: string[] = []; + const warnings: string[] = []; + const infos: string[] = []; const draft = draftCreateWithFakes({ host: fakes.host({errors: errors, warnings: warnings, infos: infos, configuration: draftFakePathConfig()}), fs: fakes.fs({existentPaths: [draftFakePath]}) @@ -97,9 +96,10 @@ suite("draft tests", () => { suite("If draft is on the path", () => { test("...no messages are reported on Windows", async () => { + /* tslint:disable-next-line:prefer-const */ let errors: string[] = []; - let warnings: string[] = []; - let infos: string[] = []; + const warnings: string[] = []; + const infos: string[] = []; const draft = draftCreateWithFakes({ host: fakes.host({errors: errors, warnings: warnings, infos: infos}), shell: fakes.shell({recognisedCommands: [{command: 'where.exe draft.exe', code: 0, stdout: 'c:\\draft.exe'}]}) @@ -111,9 +111,10 @@ suite("draft tests", () => { }); test("...no messages are reported on Unix", async () => { + /* tslint:disable-next-line:prefer-const */ let errors: string[] = []; - let warnings: string[] = []; - let infos: string[] = []; + const warnings: string[] = []; + const infos: string[] = []; const draft = draftCreateWithFakes({ host: fakes.host({errors: errors, warnings: warnings, infos: infos}), shell: fakes.shell({isWindows: false, isUnix: true, recognisedCommands: [{command: 'which draft', code: 0, stdout: '/usr/bin/draft'}]}) @@ -216,7 +217,8 @@ suite("draft tests", () => { onDirSync: (path) => { probedPath = path; return []; } }) }); - const packs = await draft.packs(); + + await draft.packs(); assert.equal(probedPath, 'c:\\itowlson\\.draft\\packs'); }); diff --git a/test/explorer.test.ts b/test/explorer.test.ts index 6e974deb4..e30221d58 100644 --- a/test/explorer.test.ts +++ b/test/explorer.test.ts @@ -3,11 +3,9 @@ import * as path from 'path'; import * as vscode from 'vscode'; import * as assert from 'assert'; -import * as textassert from './textassert'; import * as fakes from './fakes'; -import { Host } from '../src/host'; -import { Shell, ShellResult } from '../src/shell'; +import { ShellResult } from '../src/shell'; import * as kubeExplorer from '../src/explorer'; import * as kuberesources from '../src/kuberesources'; @@ -62,7 +60,7 @@ suite("Explorer tests", () => { kubectl: fakes.kubectl({ asLines: (c) => { command = c; return ["a"]; } }) }); const parent: any = kubeExplorer.createKubernetesResourceFolder(kuberesources.allKinds.pod); - const nodes = await explorer.getChildren(parent); + await explorer.getChildren(parent); assert.equal(command, "get pod"); }); @@ -96,13 +94,13 @@ suite("Explorer tests", () => { }); test("...and kubectl fails, the error is displayed", async () => { - let errors: string[] = []; + const errors: string[] = []; const explorer = explorerCreateWithFakes({ kubectl: fakes.kubectl({ asLines: (_) => { return { code: 1, stdout: "", stderr: "Oh no!"}; } }), host: fakes.host({errors: errors}) }); const parent: any = kubeExplorer.createKubernetesResourceFolder(kuberesources.allKinds.pod); - const nodes = await explorer.getChildren(parent); + await explorer.getChildren(parent); assert.equal(errors.length, 1); assert.equal(errors[0], "Oh no!"); }); diff --git a/test/kubectl.test.ts b/test/kubectl.test.ts index bd1ff658f..3876a5c88 100644 --- a/test/kubectl.test.ts +++ b/test/kubectl.test.ts @@ -2,10 +2,7 @@ import * as assert from 'assert'; import * as textassert from './textassert'; import * as fakes from './fakes'; -import { Host } from '../src/host'; -import { Shell, ShellResult } from '../src/shell'; -import { FS } from '../src/fs'; -import { create as kubectlCreate, Kubectl } from '../src/kubectl'; +import { create as kubectlCreate } from '../src/kubectl'; interface FakeContext { host?: any; @@ -41,7 +38,7 @@ suite("kubectl tests", () => { }); test("...and configuration is not present, then checkPresent reports an error", async () => { - let errors: string[] = []; + const errors: string[] = []; const kubectl = kubectlCreateWithFakes({ host: fakes.host({errors: errors}) }); @@ -51,7 +48,7 @@ suite("kubectl tests", () => { }); test("...the error message is appropriate for activation", async () => { - let errors: string[] = []; + const errors: string[] = []; const kubectl = kubectlCreateWithFakes({ host: fakes.host({errors: errors}) }); @@ -61,7 +58,7 @@ suite("kubectl tests", () => { }); test("...the error message is appropriate for command invocation", async () => { - let errors: string[] = []; + const errors: string[] = []; const kubectl = kubectlCreateWithFakes({ host: fakes.host({errors: errors}) }); @@ -77,7 +74,7 @@ suite("kubectl tests", () => { }); test("...and configuration is present but file doesn't exist, then checkPresent reports an error", async () => { - let errors: string[] = []; + const errors: string[] = []; const kubectl = kubectlCreateWithFakes({ host: fakes.host({errors: errors, configuration: kcFakePathConfig()}) }); @@ -87,9 +84,9 @@ suite("kubectl tests", () => { }); test("...and configuration is present and file exists, then checkPresent does not report any messages", async () => { - let errors = []; - let warnings: string[] = []; - let infos: string[] = []; + const errors = []; + const warnings: string[] = []; + const infos: string[] = []; const kubectl = kubectlCreateWithFakes({ host: fakes.host({errors: errors, warnings: warnings, infos: infos, configuration: kcFakePathConfig()}), fs: fakes.fs({existentPaths: [kcFakePath]}) @@ -121,9 +118,9 @@ suite("kubectl tests", () => { }); test("...no messages are reported on Windows", async () => { - let errors: string[] = []; - let warnings: string[] = []; - let infos: string[] = []; + const errors: string[] = []; + const warnings: string[] = []; + const infos: string[] = []; const kubectl = kubectlCreateWithFakes({ host: fakes.host({errors: errors, warnings: warnings, infos: infos}), shell: fakes.shell({recognisedCommands: [{command: 'where.exe kubectl.exe', code: 0, stdout: 'c:\\kubectl.exe'}]}) @@ -143,9 +140,9 @@ suite("kubectl tests", () => { }); test("...no messages are reported on Unix", async () => { - let errors: string[] = []; - let warnings: string[] = []; - let infos: string[] = []; + const errors: string[] = []; + const warnings: string[] = []; + const infos: string[] = []; const kubectl = kubectlCreateWithFakes({ host: fakes.host({errors: errors, warnings: warnings, infos: infos}), shell: fakes.shell({isWindows: false, isUnix: true, recognisedCommands: [{command: 'which kubectl', code: 0, stdout: '/usr/bin/kubectl'}]}) @@ -165,7 +162,7 @@ suite("kubectl tests", () => { suite("If kubectl is not present", () => { test("...checkPresent error handling is invoked", async () => { - let errors: string[] = []; + const errors: string[] = []; const kubectl = kubectlCreateWithFakes({ host: fakes.host({errors: errors}) }); @@ -206,7 +203,7 @@ suite("kubectl tests", () => { }); test("...but not on the path, we call it using the full path", async () => { - let invoked = []; + const invoked = []; const kubectl = kubectlCreateWithFakes({ host: fakes.host({configuration: kcFakePathConfig()}), shell: fakes.shell({ @@ -219,7 +216,7 @@ suite("kubectl tests", () => { }); await kubectl.invoke('get', (code, stdout, stderr) => { return; }); // TODO: replace with a collectionassert.exists - let hasMatchingInvoke = invoked.indexOf(kcFakePath + " get") >= 0; + const hasMatchingInvoke = invoked.indexOf(kcFakePath + " get") >= 0; assert.equal(hasMatchingInvoke, true); }); @@ -262,9 +259,9 @@ suite("kubectl tests", () => { test("...if there is no callback, and kubectl succeeds, we show the kubectl output as info", async () => { const fakeKubectlResult = { code: 0, stdout: 'kubectl out', stderr: 'kubectl err' }; - let errors: string[] = []; - let warnings: string[] = []; - let infos: string[] = []; + const errors: string[] = []; + const warnings: string[] = []; + const infos: string[] = []; const kubectl = kubectlCreateWithFakes({ host: fakes.host({errors: errors, warnings: warnings, infos: infos}), shell: fakes.shell({ @@ -284,9 +281,9 @@ suite("kubectl tests", () => { test("...if there is no callback, and kubectl fails, we show the kubectl error as error", async () => { const fakeKubectlResult = { code: 1, stdout: 'kubectl out', stderr: 'kubectl err' }; - let errors: string[] = []; - let warnings: string[] = []; - let infos: string[] = []; + const errors: string[] = []; + const warnings: string[] = []; + const infos: string[] = []; const kubectl = kubectlCreateWithFakes({ host: fakes.host({errors: errors, warnings: warnings, infos: infos}), shell: fakes.shell({ diff --git a/tslint.json b/tslint.json index 594d76243..106db2375 100644 --- a/tslint.json +++ b/tslint.json @@ -1,15 +1,35 @@ { "rules": { + "encoding": true, "only-arrow-functions": [ true, "allow-declarations", "allow-named-functions" ], "no-var-keyword": true, + "no-unused-variable": true, "object-literal-key-quotes": [ true, "as-needed" ], + "comment-format": [true, "check-space"], + "curly": [true, "ignore-same-line"], + "triple-equals": true, + "prefer-const": true, "prefer-for-of": true, + "variable-name": [true, "ban-keywords", "check-format"], + "switch-final-break": [true, "always"], + "prefer-template": [true, "allow-single-concat"], "semicolon": [true, "always"], "arrow-parens": true, + "no-consecutive-blank-lines": true, + "no-boolean-literal-compare": true, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-module", + "check-separator", + "check-type", + "check-preblock" + ], "typedef-whitespace": [ true, {