From e10d5797a248202791462e7757cbb55c5b7cc39e Mon Sep 17 00:00:00 2001 From: Florent Benoit Date: Wed, 10 Mar 2021 13:57:30 +0100 Subject: [PATCH] feat(task-plugin): bump to devfile 2.0 API Change-Id: Ib64a9a1b8e4f15ffba869e79bfe7aa1aa0a87b00 Signed-off-by: Florent Benoit --- .../task-plugin/src/che-workspace-client.ts | 102 ++++-------------- .../src/machine/machines-picker.ts | 23 +--- .../src/task/backward-compatibility.ts | 17 ++- .../task-plugin/src/task/che-task-provider.ts | 58 ++-------- .../src/variable/server-variable-resolver.ts | 62 ++++++----- 5 files changed, 74 insertions(+), 188 deletions(-) diff --git a/plugins/task-plugin/src/che-workspace-client.ts b/plugins/task-plugin/src/che-workspace-client.ts index 41d201f8df..e975881df0 100644 --- a/plugins/task-plugin/src/che-workspace-client.ts +++ b/plugins/task-plugin/src/che-workspace-client.ts @@ -1,5 +1,5 @@ /********************************************************************** - * Copyright (c) 2019-2020 Red Hat, Inc. + * Copyright (c) 2019-2021 Red Hat, Inc. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -15,12 +15,7 @@ import { injectable } from 'inversify'; const TERMINAL_SERVER_TYPE = 'terminal'; -export const RECIPE_CONTAINER_SOURCE = 'recipe'; -export const CONTAINER_SOURCE_ATTRIBUTE = 'source'; - -export interface WorkspaceContainer extends cheApi.workspace.Machine { - name: string; -} +export interface WorkspaceContainer extends che.devfile.DevfileComponentStatus {} @injectable() export class CheWorkspaceClient { @@ -30,57 +25,8 @@ export class CheWorkspaceClient { return workspace.links; } - /** Returns array of containers' names for the current workspace. */ - async getContainersNames(): Promise { - const containerNames: string[] = []; - - try { - const containers = await this.getMachines(); - for (const containerName in containers) { - if (containers.hasOwnProperty(containerName)) { - containerNames.push(containerName); - } - } - } catch (error) { - } finally { - return containerNames; - } - } - - async getMachines(): Promise<{ [attrName: string]: cheApi.workspace.Machine }> { - const workspace = await this.getCurrentWorkspace(); - const runtime = workspace.runtime; - if (!runtime) { - throw new Error('Workspace is not running.'); - } - - const machines = runtime.machines; - if (!machines) { - throw new Error('No machines for current workspace is found.'); - } - return machines; - } - - async getContainers(): Promise { - const containers: WorkspaceContainer[] = []; - try { - const workspace = await this.getCurrentWorkspace(); - - if (workspace.runtime && workspace.runtime.machines) { - const machines = workspace.runtime.machines; - for (const machineName in machines) { - if (!machines.hasOwnProperty(machineName)) { - continue; - } - const container: WorkspaceContainer = { name: machineName, ...machines[machineName] }; - containers.push(container); - } - } - } catch (e) { - throw new Error('Unable to get list workspace containers. Cause: ' + e); - } - - return containers; + async getComponentStatuses(): Promise { + return che.devfile.getComponentStatuses(); } async getCommands(): Promise { @@ -105,34 +51,28 @@ export class CheWorkspaceClient { } async getMachineExecServerURL(): Promise { - const machineExecServer = await this.getMachineExecServer(); - if (!machineExecServer) { - throw new Error(`No server with type ${TERMINAL_SERVER_TYPE} found.`); + const machineExecEndpoint = await this.getMachineExecEndpoint(); + if (!machineExecEndpoint) { + throw new Error(`No endpoint with type ${TERMINAL_SERVER_TYPE} found.`); } - if (!machineExecServer.attributes!.port) { - throw new Error('No machine-exec-server attributes.port found'); + const port = machineExecEndpoint.attributes?.port || machineExecEndpoint.attributes?.targetPort; + if (!port) { + throw new Error(`No attribute port or targetPort found in endpoint ${JSON.stringify(machineExecEndpoint)}`); } - return `ws://127.0.0.1:${machineExecServer.attributes!.port}`; + return `ws://127.0.0.1:${port}`; } - protected async getMachineExecServer(): Promise { - const machines = await this.getMachines(); - for (const machineName in machines) { - if (!machines.hasOwnProperty(machineName)) { - continue; - } - const servers = machines[machineName].servers!; - for (const serverName in servers) { - if (!servers.hasOwnProperty(serverName)) { - continue; - } - - const serverAttributes = servers[serverName].attributes; - if (serverAttributes && serverAttributes['type'] === TERMINAL_SERVER_TYPE) { - return servers[serverName]; + protected async getMachineExecEndpoint(): Promise { + const devfile = await che.devfile.get(); + if (devfile.components) { + devfile.components.forEach(component => { + if (component.container && component.container.endpoints) { + return Object.values(component.container.endpoints).find( + exposedEndpoint => exposedEndpoint.attributes && exposedEndpoint.attributes.type === TERMINAL_SERVER_TYPE + ); } - } + }); } - return undefined; + return; } } diff --git a/plugins/task-plugin/src/machine/machines-picker.ts b/plugins/task-plugin/src/machine/machines-picker.ts index fa86704025..11fa56fd77 100644 --- a/plugins/task-plugin/src/machine/machines-picker.ts +++ b/plugins/task-plugin/src/machine/machines-picker.ts @@ -1,5 +1,5 @@ /********************************************************************** - * Copyright (c) 2019-2020 Red Hat, Inc. + * Copyright (c) 2019-2021 Red Hat, Inc. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -8,12 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 ***********************************************************************/ -import { - CONTAINER_SOURCE_ATTRIBUTE, - CheWorkspaceClient, - RECIPE_CONTAINER_SOURCE, - WorkspaceContainer, -} from '../che-workspace-client'; +import { CheWorkspaceClient, WorkspaceContainer } from '../che-workspace-client'; import { QuickPickItem, window } from '@theia/plugin'; import { inject, injectable } from 'inversify'; @@ -60,7 +55,7 @@ export class MachinesPicker { } private async pickContainerFromClient(): Promise { - const containers = await this.cheWorkspaceClient.getContainers(); + const containers = await this.cheWorkspaceClient.getComponentStatuses(); if (containers.length === 1) { return Promise.resolve(containers[0].name); @@ -74,8 +69,8 @@ export class MachinesPicker { private toQuickPickItems(containers: WorkspaceContainer[]): QuickPickItem[] { const items: QuickPickItem[] = []; - const devContainers = containers.filter(container => this.isDevContainer(container)); - const toolingContainers = containers.filter(container => !this.isDevContainer(container)); + const devContainers = containers.filter(container => container.isUser); + const toolingContainers = containers.filter(container => !container.isUser); items.push( ...devContainers.map( @@ -109,12 +104,4 @@ export class MachinesPicker { return items; } - - private isDevContainer(container: WorkspaceContainer): boolean { - return ( - container.attributes !== undefined && - (!container.attributes[CONTAINER_SOURCE_ATTRIBUTE] || - container.attributes[CONTAINER_SOURCE_ATTRIBUTE] === RECIPE_CONTAINER_SOURCE) - ); - } } diff --git a/plugins/task-plugin/src/task/backward-compatibility.ts b/plugins/task-plugin/src/task/backward-compatibility.ts index 6ec8ba4c28..69c672c214 100644 --- a/plugins/task-plugin/src/task/backward-compatibility.ts +++ b/plugins/task-plugin/src/task/backward-compatibility.ts @@ -1,5 +1,5 @@ /********************************************************************** - * Copyright (c) 2019-2020 Red Hat, Inc. + * Copyright (c) 2019-2021 Red Hat, Inc. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -13,9 +13,7 @@ import * as che from '@eclipse-che/plugin'; import { inject, injectable } from 'inversify'; import { CHE_TASK_TYPE } from './task-protocol'; -import { COMPONENT_ATTRIBUTE } from '../machine/machines-picker'; import { CheWorkspaceClient } from '../che-workspace-client'; -import { getAttribute } from '../utils'; /** Contains logic to provide backward compatibility. */ @injectable() @@ -61,7 +59,7 @@ export class BackwardCompatibilityResolver { return configs; } - const containers = await this.cheWorkspaceClient.getMachines(); + const containers = await this.cheWorkspaceClient.getComponentStatuses(); for (const config of configs) { if (config.type !== CHE_TASK_TYPE) { continue; @@ -76,14 +74,11 @@ export class BackwardCompatibilityResolver { target.containerName = undefined; target.component = ''; - if (!containers.hasOwnProperty(containerName)) { + const matchingComponent = containers.find(component => component.name === containerName); + if (!matchingComponent) { continue; - } - - const container = containers[containerName]; - const component = getAttribute(COMPONENT_ATTRIBUTE, container.attributes); - if (component) { - target.component = component; + } else { + target.component = matchingComponent.name; } } return configs; diff --git a/plugins/task-plugin/src/task/che-task-provider.ts b/plugins/task-plugin/src/task/che-task-provider.ts index 0e321326b9..71b88fabb0 100644 --- a/plugins/task-plugin/src/task/che-task-provider.ts +++ b/plugins/task-plugin/src/task/che-task-provider.ts @@ -1,5 +1,5 @@ /********************************************************************** - * Copyright (c) 2019-2020 Red Hat, Inc. + * Copyright (c) 2019-2021 Red Hat, Inc. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -11,13 +11,11 @@ import * as che from '@eclipse-che/plugin'; import { CHE_TASK_TYPE, CheTaskDefinition, Target } from './task-protocol'; -import { COMPONENT_ATTRIBUTE, MachinesPicker } from '../machine/machines-picker'; import { ShellExecution, Task } from '@theia/plugin'; import { inject, injectable } from 'inversify'; import { CheWorkspaceClient } from '../che-workspace-client'; -import { che as cheApi } from '@eclipse-che/api'; -import { getAttribute } from '../utils'; +import { MachinesPicker } from '../machine/machines-picker'; /** Reads the commands from the current Che workspace and provides it as Task Configurations. */ @injectable() @@ -49,7 +47,11 @@ export class CheTaskProvider { resultTarget.workspaceId = await this.cheWorkspaceClient.getWorkspaceId(); } - resultTarget.containerName = await this.getContainerName(target); + if (target && target.component) { + resultTarget.component = target.component; + } else { + resultTarget.component = await this.machinePicker.pick(); + } if (target && target.workingDir) { resultTarget.workingDir = await che.variables.resolve(target.workingDir); @@ -71,50 +73,4 @@ export class CheTaskProvider { execution: execution, }; } - - private async getContainerName(target?: Target): Promise { - if (!target) { - return this.machinePicker.pick(); - } - - const containers = await this.cheWorkspaceClient.getMachines(); - - const containerName = target.containerName; - if (containerName && containers.hasOwnProperty(containerName)) { - return containerName; - } - - return (await this.getContainerNameByComponent(target.component, containers)) || this.machinePicker.pick(); - } - - private async getContainerNameByComponent( - targetComponent: string | undefined, - containers: { [attrName: string]: cheApi.workspace.Machine } - ): Promise { - if (!targetComponent) { - return undefined; - } - - const names = []; - for (const containerName in containers) { - if (!containers.hasOwnProperty(containerName)) { - continue; - } - - const container = containers[containerName]; - const component = getAttribute(COMPONENT_ATTRIBUTE, container.attributes); - if (component && component === targetComponent) { - names.push(containerName); - } - } - - if (names.length === 1) { - return names[0]; - } - - if (names.length > 1) { - return this.machinePicker.pick(names); - } - return undefined; - } } diff --git a/plugins/task-plugin/src/variable/server-variable-resolver.ts b/plugins/task-plugin/src/variable/server-variable-resolver.ts index f27de57e61..e4b80a47cb 100644 --- a/plugins/task-plugin/src/variable/server-variable-resolver.ts +++ b/plugins/task-plugin/src/variable/server-variable-resolver.ts @@ -1,5 +1,5 @@ /********************************************************************** - * Copyright (c) 2019-2020 Red Hat, Inc. + * Copyright (c) 2019-2021 Red Hat, Inc. * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 @@ -25,34 +25,42 @@ export class ServerVariableResolver { protected readonly cheWorkspaceClient!: CheWorkspaceClient; async registerVariables(): Promise { - const machines = await this.cheWorkspaceClient.getMachines(); - for (const machineName in machines) { - if (!machines.hasOwnProperty(machineName)) { - continue; - } - - const servers = machines[machineName].servers!; - - for (const serverName in servers) { - if (!servers.hasOwnProperty(serverName)) { - continue; - } - - const url = servers[serverName].url; - if (url) { - const variableSubscription = await che.variables.registerVariable(this.createVariable(serverName, url)); - startPoint.getSubscriptions().push(variableSubscription); + const componentStatuses = await this.cheWorkspaceClient.getComponentStatuses(); + await Promise.all( + componentStatuses.map(async componentStatus => { + if (componentStatus.endpoints) { + for (const endpointName in componentStatus.endpoints) { + if (!componentStatus.endpoints.hasOwnProperty(endpointName)) { + continue; + } + const url = componentStatus.endpoints[endpointName].url; + if (url) { + const variables = this.createVariables(endpointName, url); + const variableSubscriptions = await Promise.all( + variables.map(variable => che.variables.registerVariable(variable)) + ); + variableSubscriptions.forEach(subscription => startPoint.getSubscriptions().push(subscription)); + } + } } - } - } + }) + ); } - private createVariable(serverName: string, url: string): che.Variable { - return { - name: `server.${serverName}`, - description: url, - resolve: async () => url, - isResolved: true, - }; + private createVariables(serverName: string, url: string): che.Variable[] { + return [ + { + name: `server.${serverName}`, + description: url, + resolve: async () => url, + isResolved: true, + }, + { + name: `endpoint.${serverName}`, + description: url, + resolve: async () => url, + isResolved: true, + }, + ]; } }