Skip to content
This repository has been archived by the owner on Apr 4, 2023. It is now read-only.

feat(task-plugin): bump to devfile 2.0 API #1024

Merged
merged 2 commits into from
Mar 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions plugins/task-plugin/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ dist/
lib/
node_modules/
*.theia
coverage
22 changes: 22 additions & 0 deletions plugins/task-plugin/__mocks__/@eclipse-che/plugin.ts
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
Expand Up @@ -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;
109 changes: 15 additions & 94 deletions plugins/task-plugin/src/che-workspace-client.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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 {
Expand All @@ -30,69 +25,13 @@ export class CheWorkspaceClient {
return workspace.links;
}

/** Returns array of containers' names for the current workspace. */
async getContainersNames(): Promise<string[]> {
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 getComponentStatuses(): Promise<che.devfile.DevfileComponentStatus[]> {
return che.devfile.getComponentStatuses();
}

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<WorkspaceContainer[]> {
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 getCommands(): Promise<cheApi.workspace.Command[]> {
const workspace: cheApi.workspace.Workspace = await this.getCurrentWorkspace();

const runtime: cheApi.workspace.Runtime | undefined = workspace.runtime;
if (!runtime) {
return [];
}

const commands = runtime.commands;
return commands ? commands : [];
async getCommands(): Promise<che.devfile.DevfileCommand[]> {
const devfile = await che.devfile.get();
return devfile.commands || [];
}

getCurrentWorkspace(): Promise<cheApi.workspace.Workspace> {
Expand All @@ -105,34 +44,16 @@ export class CheWorkspaceClient {
}

async getMachineExecServerURL(): Promise<string> {
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 port = machineExecEndpoint.attributes?.port || machineExecEndpoint.attributes?.targetPort;
return `ws://127.0.0.1:${port}`;
}

protected async getMachineExecServer(): Promise<cheApi.workspace.Server | undefined> {
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<che.endpoint.ExposedEndpoint> {
const terminalEndpoints = await che.endpoint.getEndpointsByType(TERMINAL_SERVER_TYPE);
if (terminalEndpoints.length === 1) {
return terminalEndpoints[0];
}
return undefined;
throw new Error(`Unable to find terminal with type ${TERMINAL_SERVER_TYPE}: Found: ${terminalEndpoints}`);
}
}
9 changes: 5 additions & 4 deletions plugins/task-plugin/src/export/export-configs-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
* SPDX-License-Identifier: EPL-2.0
***********************************************************************/

import * as che from '@eclipse-che/plugin';

import { inject, injectable, multiInject } from 'inversify';

import { CheWorkspaceClient } from '../che-workspace-client';
import { LaunchConfigurationsExporter } from './launch-configs-exporter';
import { che as cheApi } from '@eclipse-che/api';

export const ConfigurationsExporter = Symbol('ConfigurationsExporter');

Expand All @@ -23,7 +24,7 @@ export interface ConfigurationsExporter {
* @param workspaceFolder workspace folder for exporting configs in the config file
* @param commands commands with configurations for export
*/
export(commands: cheApi.workspace.Command[]): Promise<void>;
export(commands: che.devfile.DevfileCommand[]): Promise<void>;
}
/** Contains configurations as array of object and as raw content and is used at getting configurations from config file for example */
export interface Configurations<T> {
Expand All @@ -46,7 +47,7 @@ export class ExportConfigurationsManager {
@inject(LaunchConfigurationsExporter)
protected readonly launchConfigurationsExporter: LaunchConfigurationsExporter;

protected cheCommands: cheApi.workspace.Command[] = [];
protected cheCommands: che.devfile.DevfileCommand[] = [];

async init(): Promise<void> {
this.cheCommands = await this.cheWorkspaceClient.getCommands();
Expand All @@ -63,7 +64,7 @@ export class ExportConfigurationsManager {
await Promise.all(exportPromises);
}

private async doExport(cheCommands: cheApi.workspace.Command[], exporter: ConfigurationsExporter): Promise<void> {
private async doExport(cheCommands: che.devfile.DevfileCommand[], exporter: ConfigurationsExporter): Promise<void> {
return exporter.export(cheCommands);
}
}
8 changes: 4 additions & 4 deletions plugins/task-plugin/src/export/launch-configs-exporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* SPDX-License-Identifier: EPL-2.0
***********************************************************************/

import * as che from '@eclipse-che/plugin';
import * as startPoint from '../task-plugin-backend';
import * as theia from '@theia/plugin';

Expand All @@ -17,7 +18,6 @@ import { inject, injectable } from 'inversify';
import { ConfigFileLaunchConfigsExtractor } from '../extract/config-file-launch-configs-extractor';
import { ConfigurationsExporter } from './export-configs-manager';
import { VsCodeLaunchConfigsExtractor } from '../extract/vscode-launch-configs-extractor';
import { che as cheApi } from '@eclipse-che/api';
import { resolve } from 'path';

const CONFIG_DIR = '.theia';
Expand All @@ -33,7 +33,7 @@ export class LaunchConfigurationsExporter implements ConfigurationsExporter {
@inject(VsCodeLaunchConfigsExtractor)
protected readonly vsCodeLaunchConfigsExtractor: VsCodeLaunchConfigsExtractor;

async init(commands: cheApi.workspace.Command[]): Promise<void> {
async init(commands: che.devfile.DevfileCommand[]): Promise<void> {
theia.workspace.onDidChangeWorkspaceFolders(
event => {
const workspaceFolders: theia.WorkspaceFolder[] | undefined = event.added;
Expand All @@ -46,7 +46,7 @@ export class LaunchConfigurationsExporter implements ConfigurationsExporter {
);
}

async export(commands: cheApi.workspace.Command[], workspaceFolders?: theia.WorkspaceFolder[]): Promise<void> {
async export(commands: che.devfile.DevfileCommand[], workspaceFolders?: theia.WorkspaceFolder[]): Promise<void> {
workspaceFolders = workspaceFolders ? workspaceFolders : theia.workspace.workspaceFolders;
if (!workspaceFolders) {
return;
Expand All @@ -60,7 +60,7 @@ export class LaunchConfigurationsExporter implements ConfigurationsExporter {
await Promise.all(exportConfigsPromises);
}

async doExport(workspaceFolder: theia.WorkspaceFolder, commands: cheApi.workspace.Command[]): Promise<void> {
async doExport(workspaceFolder: theia.WorkspaceFolder, commands: che.devfile.DevfileCommand[]): Promise<void> {
const workspaceFolderPath = workspaceFolder.uri.path;
const launchConfigFilePath = resolve(workspaceFolderPath, CONFIG_DIR, LAUNCH_CONFIG_FILE);
const configFileConfigs = await this.configFileLaunchConfigsExtractor.extract(launchConfigFilePath);
Expand Down
6 changes: 3 additions & 3 deletions plugins/task-plugin/src/export/task-configs-exporter.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -8,6 +8,7 @@
* SPDX-License-Identifier: EPL-2.0
***********************************************************************/

import * as che from '@eclipse-che/plugin';
import * as startPoint from '../task-plugin-backend';

import { inject, injectable } from 'inversify';
Expand All @@ -19,7 +20,6 @@ import { ConfigFileTasksExtractor } from '../extract/config-file-task-configs-ex
import { ConfigurationsExporter } from './export-configs-manager';
import { TaskConfiguration } from '@eclipse-che/plugin';
import { VsCodeTaskConfigsExtractor } from '../extract/vscode-task-configs-extractor';
import { che as cheApi } from '@eclipse-che/api';
import { homedir } from 'os';
import { resolve } from 'path';

Expand Down Expand Up @@ -48,7 +48,7 @@ export class TaskConfigurationsExporter implements ConfigurationsExporter {
@inject(BackwardCompatibilityResolver)
protected readonly backwardCompatibilityResolver: BackwardCompatibilityResolver;

async export(commands: cheApi.workspace.Command[]): Promise<void> {
async export(commands: che.devfile.DevfileCommand[]): Promise<void> {
const configFileTasks = await this.configFileTasksExtractor.extract(THEIA_USER_TASKS_PATH);

const cheTasks = this.cheTaskConfigsExtractor.extract(commands);
Expand Down
13 changes: 5 additions & 8 deletions plugins/task-plugin/src/extract/che-task-configs-extractor.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -8,21 +8,18 @@
* SPDX-License-Identifier: EPL-2.0
***********************************************************************/

import * as che from '@eclipse-che/plugin';

import { TaskConfiguration } from '@eclipse-che/plugin';
import { VSCODE_LAUNCH_TYPE } from './vscode-launch-configs-extractor';
import { VSCODE_TASK_TYPE } from './vscode-task-configs-extractor';
import { che as cheApi } from '@eclipse-che/api';
import { injectable } from 'inversify';
import { toTaskConfiguration } from '../task/converter';

/** Extracts CHE configurations of tasks. */
@injectable()
export class CheTaskConfigsExtractor {
extract(commands: cheApi.workspace.Command[]): TaskConfiguration[] {
extract(commands: che.devfile.DevfileCommand[]): TaskConfiguration[] {
// TODO filter should be changed according to task type after resolving https://github.com/eclipse/che/issues/12710
const filteredCommands = commands.filter(
command => command.type !== VSCODE_TASK_TYPE && command.type !== VSCODE_LAUNCH_TYPE
);
const filteredCommands = commands.filter(command => command.exec);

if (filteredCommands.length === 0) {
return [];
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -8,36 +8,34 @@
* SPDX-License-Identifier: EPL-2.0
***********************************************************************/

import * as che from '@eclipse-che/plugin';
import * as theia from '@theia/plugin';

import { Configurations } from '../export/export-configs-manager';
import { che as cheApi } from '@eclipse-che/api';
import { injectable } from 'inversify';
import { parse } from '../utils';

export const VSCODE_LAUNCH_TYPE = 'vscode-launch';

/** Extracts vscode launch configurations. */
@injectable()
export class VsCodeLaunchConfigsExtractor {
extract(commands: cheApi.workspace.Command[]): Configurations<theia.DebugConfiguration> {
extract(commands: che.devfile.DevfileCommand[]): Configurations<theia.DebugConfiguration> {
const emptyContent: Configurations<theia.DebugConfiguration> = { content: '', configs: [] };

const configCommands = commands.filter(command => command.type === VSCODE_LAUNCH_TYPE);
const configCommands = commands.filter(command => command.vscodeLaunch);
if (configCommands.length === 0) {
return emptyContent;
}

if (configCommands.length > 1) {
console.warn(`Found duplicate entry with configurations for type ${VSCODE_LAUNCH_TYPE}`);
console.warn(`Found duplicate entry with configurations for type vscodeLaunch`);
}

const configCommand = configCommands[0];
if (!configCommand || !configCommand.attributes || !configCommand.attributes.actionReferenceContent) {
if (!configCommand || !configCommand.vscodeLaunch?.inline) {
return emptyContent;
}

const launchConfigsContent = configCommand.attributes.actionReferenceContent;
const launchConfigsContent = configCommand.vscodeLaunch.inline;
const configsJson = parse(launchConfigsContent);
if (!configsJson || !configsJson.configurations) {
return emptyContent;
Expand Down
Loading