diff --git a/extensions/eclipse-che-theia-plugin-ext/src/browser/che-api-provider.ts b/extensions/eclipse-che-theia-plugin-ext/src/browser/che-api-provider.ts index 06af320191..0c348a1754 100644 --- a/extensions/eclipse-che-theia-plugin-ext/src/browser/che-api-provider.ts +++ b/extensions/eclipse-che-theia-plugin-ext/src/browser/che-api-provider.ts @@ -11,6 +11,7 @@ import { injectable, interfaces } from 'inversify'; import { CheDevfileMainImpl } from './che-devfile-main'; +import { CheEndpointMainImpl } from './che-endpoint-main'; import { CheGithubMainImpl } from './che-github-main'; import { CheK8SMainImpl } from './che-k8s-main'; import { CheLanguagesTestAPIImpl } from './che-languages-test-api'; @@ -34,6 +35,7 @@ export class CheApiProvider implements MainPluginApiProvider { initialize(rpc: RPCProtocol, container: interfaces.Container): void { rpc.set(PLUGIN_RPC_CONTEXT.CHE_WORKSPACE_MAIN, new CheWorkspaceMainImpl(container)); rpc.set(PLUGIN_RPC_CONTEXT.CHE_DEVFILE_MAIN, new CheDevfileMainImpl(container)); + rpc.set(PLUGIN_RPC_CONTEXT.CHE_ENDPOINT_MAIN, new CheEndpointMainImpl(container)); rpc.set(PLUGIN_RPC_CONTEXT.CHE_TELEMETRY_MAIN, new CheTelemetryMainImpl(container, rpc)); rpc.set(PLUGIN_RPC_CONTEXT.CHE_VARIABLES_MAIN, new CheVariablesMainImpl(container, rpc)); rpc.set(PLUGIN_RPC_CONTEXT.CHE_TASK_MAIN, new CheTaskMainImpl(container, rpc)); diff --git a/extensions/eclipse-che-theia-plugin-ext/src/browser/che-endpoint-main.ts b/extensions/eclipse-che-theia-plugin-ext/src/browser/che-endpoint-main.ts new file mode 100644 index 0000000000..80f6857179 --- /dev/null +++ b/extensions/eclipse-che-theia-plugin-ext/src/browser/che-endpoint-main.ts @@ -0,0 +1,33 @@ +/********************************************************************** + * Copyright (c) 2018-2021 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ***********************************************************************/ + +import { ComponentExposedEndpoint, ExposedEndpoint } from '@eclipse-che/theia-remote-api/lib/common/endpoint-service'; + +import { CheEndpointMain } from '../common/che-protocol'; +import { EndpointService } from '@eclipse-che/theia-remote-api/lib/common/endpoint-service'; +import { interfaces } from 'inversify'; + +export class CheEndpointMainImpl implements CheEndpointMain { + private readonly endpointService: EndpointService; + + constructor(container: interfaces.Container) { + this.endpointService = container.get(EndpointService); + } + + async $getEndpoints(): Promise { + return this.endpointService.getEndpoints(); + } + async $getEndpointsByName(...names: string[]): Promise { + return this.endpointService.getEndpointsByName(...names); + } + async $getEndpointsByType(type: string): Promise { + return this.$getEndpointsByType(type); + } +} diff --git a/extensions/eclipse-che-theia-plugin-ext/src/common/che-protocol.ts b/extensions/eclipse-che-theia-plugin-ext/src/common/che-protocol.ts index 285e354dae..065a229676 100644 --- a/extensions/eclipse-che-theia-plugin-ext/src/common/che-protocol.ts +++ b/extensions/eclipse-che-theia-plugin-ext/src/common/che-protocol.ts @@ -51,6 +51,14 @@ export interface CheDevfileMain { $update(updatedDevfile: che.devfile.Devfile): Promise; } +export interface CheEndpoint {} + +export interface CheEndpointMain { + $getEndpoints(): Promise; + $getEndpointsByName(...names: string[]): Promise; + $getEndpointsByType(type: string): Promise; +} + export interface CheSsh {} export interface CheSshMain { @@ -416,6 +424,9 @@ export const PLUGIN_RPC_CONTEXT = { CHE_DEVFILE: createProxyIdentifier('CheDevfile'), CHE_DEVFILE_MAIN: createProxyIdentifier('CheDevfileMain'), + CHE_ENDPOINT: createProxyIdentifier('CheEndpoint'), + CHE_ENDPOINT_MAIN: createProxyIdentifier('CheEndpointMain'), + CHE_TELEMETRY: createProxyIdentifier('CheTelemetry'), CHE_TELEMETRY_MAIN: createProxyIdentifier('CheTelemetryMain'), diff --git a/extensions/eclipse-che-theia-plugin-ext/src/plugin/che-api.ts b/extensions/eclipse-che-theia-plugin-ext/src/plugin/che-api.ts index 683894a996..66d8d7bb7b 100644 --- a/extensions/eclipse-che-theia-plugin-ext/src/plugin/che-api.ts +++ b/extensions/eclipse-che-theia-plugin-ext/src/plugin/che-api.ts @@ -14,6 +14,7 @@ import * as theia from '@theia/plugin'; import { CheTaskImpl, TaskStatus, TaskTerminallKind } from './che-task-impl'; import { CheDevfileImpl } from './che-devfile'; +import { CheEndpointImpl } from './che-endpoint'; import { CheGithubImpl } from './che-github'; import { CheK8SImpl } from './che-k8s'; import { CheOauthImpl } from './che-oauth'; @@ -41,6 +42,7 @@ export interface CheApiFactory { export function createAPIFactory(rpc: RPCProtocol): CheApiFactory { const cheWorkspaceImpl = rpc.set(PLUGIN_RPC_CONTEXT.CHE_WORKSPACE, new CheWorkspaceImpl(rpc)); const cheDevfileImpl = rpc.set(PLUGIN_RPC_CONTEXT.CHE_DEVFILE, new CheDevfileImpl(rpc)); + const cheEndpointImpl = rpc.set(PLUGIN_RPC_CONTEXT.CHE_DEVFILE, new CheEndpointImpl(rpc)); const cheVariablesImpl = rpc.set(PLUGIN_RPC_CONTEXT.CHE_VARIABLES, new CheVariablesImpl(rpc)); const cheTaskImpl = rpc.set(PLUGIN_RPC_CONTEXT.CHE_TASK, new CheTaskImpl(rpc)); const cheSshImpl = rpc.set(PLUGIN_RPC_CONTEXT.CHE_SSH, new CheSshImpl(rpc)); @@ -118,6 +120,18 @@ export function createAPIFactory(rpc: RPCProtocol): CheApiFactory { }, }; + const endpoint: typeof che.endpoint = { + getEndpoints(): Promise { + return cheEndpointImpl.getEndpoints(); + }, + getEndpointsByName(...names: string[]): Promise { + return cheEndpointImpl.getEndpointsByName(...names); + }, + getEndpointsByType(type: string): Promise { + return cheEndpointImpl.getEndpointsByType(type); + }, + }; + const telemetry: typeof che.telemetry = { event(id: string, ownerId: string, properties: [string, string][]): Promise { return cheTelemetryImpl.event(id, ownerId, properties); @@ -424,6 +438,7 @@ export function createAPIFactory(rpc: RPCProtocol): CheApiFactory { return { workspace, devfile, + endpoint, variables, task, ssh, diff --git a/extensions/eclipse-che-theia-plugin-ext/src/plugin/che-endpoint.ts b/extensions/eclipse-che-theia-plugin-ext/src/plugin/che-endpoint.ts new file mode 100644 index 0000000000..9370d197f3 --- /dev/null +++ b/extensions/eclipse-che-theia-plugin-ext/src/plugin/che-endpoint.ts @@ -0,0 +1,33 @@ +/********************************************************************** + * Copyright (c) 2018-2021 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ***********************************************************************/ + +import { CheEndpoint, CheEndpointMain, PLUGIN_RPC_CONTEXT } from '../common/che-protocol'; + +import { RPCProtocol } from '@theia/plugin-ext/lib/common/rpc-protocol'; +import { endpoint } from '@eclipse-che/plugin'; + +export class CheEndpointImpl implements CheEndpoint { + private readonly endpointMain: CheEndpointMain; + + constructor(rpc: RPCProtocol) { + this.endpointMain = rpc.getProxy(PLUGIN_RPC_CONTEXT.CHE_ENDPOINT_MAIN); + } + + async getEndpoints(): Promise { + return this.endpointMain.$getEndpoints(); + } + async getEndpointsByName(...names: string[]): Promise { + return this.endpointMain.$getEndpointsByName(...names); + } + + async getEndpointsByType(type: string): Promise { + return this.endpointMain.$getEndpointsByType(type); + } +} diff --git a/extensions/eclipse-che-theia-plugin/src/che-proposed.d.ts b/extensions/eclipse-che-theia-plugin/src/che-proposed.d.ts index fe2bc1435f..65345177ff 100644 --- a/extensions/eclipse-che-theia-plugin/src/che-proposed.d.ts +++ b/extensions/eclipse-che-theia-plugin/src/che-proposed.d.ts @@ -216,6 +216,25 @@ declare module '@eclipse-che/plugin' { export function createWorkspace(devfilePath: string): Promise; } + export namespace endpoint { + + export interface ExposedEndpoint { + attributes?: { [key: string]: string }; + url?: string; + name: string; + component: string; + } + + export interface ComponentExposedEndpoint { + name: string; + endpoints: ExposedEndpoint[]; + } + + export function getEndpoints(): Promise; + export function getEndpointsByName(...names: string[]): Promise; + export function getEndpointsByType(type: string): Promise; + } + export interface GithubUser { login: string, id: number, diff --git a/plugins/task-plugin/__mocks__/@eclipse-che/plugin.ts b/plugins/task-plugin/__mocks__/@eclipse-che/plugin.ts new file mode 100644 index 0000000000..a462fa9b4b --- /dev/null +++ b/plugins/task-plugin/__mocks__/@eclipse-che/plugin.ts @@ -0,0 +1,22 @@ +/********************************************************************** + * Copyright (c) 2021 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ***********************************************************************/ + +/* eslint-disable @typescript-eslint/no-explicit-any */ +const chePlugin: any = {}; +chePlugin.devfile = { + get: jest.fn(), + getComponentStatuses: jest.fn(), +}; + +chePlugin.endpoint = { + getEndpointsByType: jest.fn(), +}; + +module.exports = chePlugin; diff --git a/plugins/task-plugin/tests/no-op.spec.ts b/plugins/task-plugin/__mocks__/@theia/plugin.ts similarity index 69% rename from plugins/task-plugin/tests/no-op.spec.ts rename to plugins/task-plugin/__mocks__/@theia/plugin.ts index 3ec8409a6b..e476b3c0de 100644 --- a/plugins/task-plugin/tests/no-op.spec.ts +++ b/plugins/task-plugin/__mocks__/@theia/plugin.ts @@ -8,6 +8,10 @@ * SPDX-License-Identifier: EPL-2.0 ***********************************************************************/ -describe('no-op', function () { - it('no-op', function () {}); -}); +/* eslint-disable @typescript-eslint/no-explicit-any */ +const theiaPlugin: any = {}; + +theiaPlugin.window = { + createOutputChannel: jest.fn() +}; +module.exports = theiaPlugin; diff --git a/plugins/task-plugin/src/che-workspace-client.ts b/plugins/task-plugin/src/che-workspace-client.ts index 41d201f8df..39d359105d 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 @@ -9,18 +9,14 @@ ***********************************************************************/ import * as che from '@eclipse-che/plugin'; +import * as theia from '@theia/plugin'; import { che as cheApi } from '@eclipse-che/api'; 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 +26,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 +52,22 @@ export class CheWorkspaceClient { } async getMachineExecServerURL(): Promise { - const machineExecServer = await this.getMachineExecServer(); - if (!machineExecServer) { - throw new Error(`No server with type ${TERMINAL_SERVER_TYPE} found.`); - } - if (!machineExecServer.attributes!.port) { - throw new Error('No machine-exec-server attributes.port found'); - } - return `ws://127.0.0.1:${machineExecServer.attributes!.port}`; + const machineExecEndpoint = await this.getMachineExecEndpoint(); + const outputChannelTaskPlugin = theia.window.createOutputChannel('task-plugin-ref'); + const port = machineExecEndpoint.attributes?.port || machineExecEndpoint.attributes?.targetPort; + outputChannelTaskPlugin.appendLine( + `port is ${port} and machineExecEndpoint is ${JSON.stringify(machineExecEndpoint, undefined, 2)}` + ); + 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 terminalEndpoints = await che.endpoint.getEndpointsByType(TERMINAL_SERVER_TYPE); + const outputChannel = theia.window.createOutputChannel('task-plugin'); + outputChannel.appendLine(`terminalEndpoints are ${JSON.stringify(terminalEndpoints, undefined, 2)}`); + if (terminalEndpoints.length === 1) { + return terminalEndpoints[0]; } - return undefined; + throw new Error(`Unable to find terminal with type ${TERMINAL_SERVER_TYPE}: Found: ${terminalEndpoints}`); } } 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, + }, + ]; } } diff --git a/plugins/task-plugin/tests/che-workspace-client.spec.ts b/plugins/task-plugin/tests/che-workspace-client.spec.ts new file mode 100644 index 0000000000..863a437887 --- /dev/null +++ b/plugins/task-plugin/tests/che-workspace-client.spec.ts @@ -0,0 +1,57 @@ +/********************************************************************** + * Copyright (c) 2021 Red Hat, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ***********************************************************************/ + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import 'reflect-metadata'; + +import * as che from '@eclipse-che/plugin'; +import * as theia from '@theia/plugin'; + +import { CheWorkspaceClient } from '../src/che-workspace-client'; +import { Container } from 'inversify'; + +describe('Test containers service', () => { + const getEndpointsByTypeSpy = jest.spyOn(che.endpoint, 'getEndpointsByType'); + const createOutputChannelSpy = jest.spyOn(theia.window, 'createOutputChannel'); + + let workspaceClient: CheWorkspaceClient; + + beforeEach(() => { + jest.clearAllMocks(); + jest.resetAllMocks(); + const outputChannelMock = { + appendLine: jest.fn(), + }; + createOutputChannelSpy.mockReturnValue(outputChannelMock as any); + const container = new Container(); + container.bind(CheWorkspaceClient).toSelf().inSingletonScope(); + workspaceClient = container.get(CheWorkspaceClient); + }); + + test('Check getMachineExecServerURL', async () => { + const exposedEndpoints: che.endpoint.ExposedEndpoint[] = [ + { + name: 'che-machine-exec', + component: 'machine-exec', + attributes: { + type: 'terminal', + discoverable: 'false', + cookiesAuthEnabled: 'true', + port: '4444', + }, + }, + ]; + getEndpointsByTypeSpy.mockResolvedValue(exposedEndpoints); + const url = await workspaceClient.getMachineExecServerURL(); + expect(url).toBe('ws://127.0.0.1:4444'); + expect(getEndpointsByTypeSpy).toBeCalled(); + }); +});