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

Use component for task configuration instead of container name #512

Merged
merged 1 commit into from
Oct 28, 2019
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
2 changes: 1 addition & 1 deletion plugins/task-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The format of a Che task is the following:
"command": "",
"target": {
"workspaceId": "",
"containerName": "",
"component": "",
"workingDir": ""
},
"previewUrl": ""
Expand Down
2 changes: 2 additions & 0 deletions plugins/task-plugin/src/che-task-backend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { ConfigFileTasksExtractor } from './extract/config-file-task-configs-ext
import { VsCodeLaunchConfigsExtractor } from './extract/vscode-launch-configs-extractor';
import { VsCodeTaskConfigsExtractor } from './extract/vscode-task-configs-extractor';
import { PreviewUrlVariableResolver } from './variable/preview-url-variable-resolver';
import { BackwardCompatibilityResolver } from './task/backward-compatibility';

const container = new Container();
container.bind(CheTaskProvider).toSelf().inSingletonScope();
Expand All @@ -54,6 +55,7 @@ container.bind(ConfigFileTasksExtractor).toSelf().inSingletonScope();
container.bind(ConfigFileLaunchConfigsExtractor).toSelf().inSingletonScope();
container.bind(VsCodeLaunchConfigsExtractor).toSelf().inSingletonScope();
container.bind(VsCodeTaskConfigsExtractor).toSelf().inSingletonScope();
container.bind(BackwardCompatibilityResolver).toSelf().inSingletonScope();

container.bind(PreviewUrlsWidget).toSelf().inTransientScope();
container.bind(PreviewUrlsWidgetFactory).toDynamicValue(ctx => ({
Expand Down
17 changes: 17 additions & 0 deletions plugins/task-plugin/src/che-workspace-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,23 @@ 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 getMachines(): Promise<{ [attrName: string]: cheApi.workspace.Machine }> {
const workspace = await this.getCurrentWorkspace();
const runtime = workspace.runtime;
Expand Down
2 changes: 1 addition & 1 deletion plugins/task-plugin/src/export/export-configs-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface ConfigurationsExporter {
* @param workspaceFolder workspace folder for exporting configs in the config file
* @param commands commands with configurations for export
*/
export(workspaceFolder: theia.WorkspaceFolder, commands: cheApi.workspace.Command[]): void;
export(workspaceFolder: theia.WorkspaceFolder, commands: cheApi.workspace.Command[]): 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 Down
2 changes: 1 addition & 1 deletion plugins/task-plugin/src/export/launch-configs-exporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class LaunchConfigurationsExporter implements ConfigurationsExporter {
@inject(VsCodeLaunchConfigsExtractor)
protected readonly vsCodeLaunchConfigsExtractor: VsCodeLaunchConfigsExtractor;

export(workspaceFolder: theia.WorkspaceFolder, commands: cheApi.workspace.Command[]): void {
async export(workspaceFolder: theia.WorkspaceFolder, commands: cheApi.workspace.Command[]): Promise<void> {
const launchConfigFileUri = this.getConfigFileUri(workspaceFolder.uri.path);
const configFileConfigs = this.configFileLaunchConfigsExtractor.extract(launchConfigFileUri);
const vsCodeConfigs = this.vsCodeLaunchConfigsExtractor.extract(commands);
Expand Down
9 changes: 7 additions & 2 deletions plugins/task-plugin/src/export/task-configs-exporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { CheTaskConfigsExtractor } from '../extract/che-task-configs-extractor';
import { VsCodeTaskConfigsExtractor } from '../extract/vscode-task-configs-extractor';
import { ConfigurationsExporter } from './export-configs-manager';
import { ConfigFileTasksExtractor } from '../extract/config-file-task-configs-extractor';
import { BackwardCompatibilityResolver } from '../task/backward-compatibility';

const CONFIG_DIR = '.theia';
const TASK_CONFIG_FILE = 'tasks.json';
Expand All @@ -39,17 +40,21 @@ export class TaskConfigurationsExporter implements ConfigurationsExporter {
@inject(VsCodeTaskConfigsExtractor)
protected readonly vsCodeTaskConfigsExtractor: VsCodeTaskConfigsExtractor;

export(workspaceFolder: theia.WorkspaceFolder, commands: cheApi.workspace.Command[]): void {
@inject(BackwardCompatibilityResolver)
protected readonly backwardCompatibilityResolver: BackwardCompatibilityResolver;

async export(workspaceFolder: theia.WorkspaceFolder, commands: cheApi.workspace.Command[]): Promise<void> {
const tasksConfigFileUri = this.getConfigFileUri(workspaceFolder.uri.path);
const configFileTasks = this.configFileTasksExtractor.extract(tasksConfigFileUri);

const cheTasks = this.cheTaskConfigsExtractor.extract(commands);
const vsCodeTasks = this.vsCodeTaskConfigsExtractor.extract(commands);
const devfileConfigs = this.merge(cheTasks, vsCodeTasks.configs, this.getOutputChannelConflictLogger());
const configFileConfigs = await this.backwardCompatibilityResolver.resolveComponent(configFileTasks.configs);

const configFileContent = configFileTasks.content;
if (configFileContent) {
this.saveConfigs(tasksConfigFileUri, configFileContent, this.merge(configFileTasks.configs, devfileConfigs, this.getConsoleConflictLogger()));
this.saveConfigs(tasksConfigFileUri, configFileContent, this.merge(configFileConfigs, devfileConfigs, this.getConsoleConflictLogger()));
return;
}

Expand Down
41 changes: 13 additions & 28 deletions plugins/task-plugin/src/machine/machines-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import { injectable, inject } from 'inversify';
import * as theia from '@theia/plugin';
import { CheWorkspaceClient } from '../che-workspace-client';

const MACHINES_PLACE_HOLDER = 'Pick a machine to run the task';
const CONTAINERS_PLACE_HOLDER = 'Pick a container to run the task';
export const COMPONENT_ATTRIBUTE: string = 'component';

@injectable()
export class MachinesPicker {
Expand All @@ -21,42 +22,26 @@ export class MachinesPicker {
protected readonly cheWorkspaceClient!: CheWorkspaceClient;

/**
* Returns a machine name if there's just one machine in the current workspace.
* Shows a quick open widget allows to pick a machine if there are several ones.
* Returns a container name if there's just one container in the current workspace.
* Shows a quick open widget and allows to pick a container if there are several ones.
* @param containerNames containers for displaying in quick open widget,
* all containers of the current workspace will be displayed if the optional parameter is absent
*/
async pick(): Promise<string> {
const machines = await this.getMachines();
if (machines.length === 1) {
return Promise.resolve(machines[0]);
async pick(containerNames?: string[]): Promise<string> {
if (!containerNames) {
containerNames = await this.cheWorkspaceClient.getContainersNames();
}

const items: string[] = [];
for (const machineName of machines) {
items.push(machineName);
if (containerNames.length === 1) {
return Promise.resolve(containerNames[0]);
}

return this.showMachineQuickPick(items);
}

protected async getMachines(): Promise<string[]> {
const machineNames: string[] = [];
const machines = await this.cheWorkspaceClient.getMachines();
if (!machines) {
return machineNames;
}

for (const machineName in machines) {
if (machines.hasOwnProperty(machineName)) {
machineNames.push(machineName);
}
}
return machineNames;
return this.showMachineQuickPick(containerNames);
}

private showMachineQuickPick(items: string[]): Promise<string> {
return new Promise<string>(resolve => {

const options = { placeHolder: MACHINES_PLACE_HOLDER } as theia.QuickPickOptions;
const options = { placeHolder: CONTAINERS_PLACE_HOLDER } as theia.QuickPickOptions;
options.onDidSelectItem = (item => {
const machineName = typeof item === 'string' ? item : item.label;
resolve(machineName);
Expand Down
90 changes: 90 additions & 0 deletions plugins/task-plugin/src/task/backward-compatibility.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*********************************************************************
* Copyright (c) 2019 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 { injectable, inject } from 'inversify';
import * as che from '@eclipse-che/plugin';
import { CHE_TASK_TYPE } from './task-protocol';
import { CheWorkspaceClient } from '../che-workspace-client';
import { getAttribute } from '../utils';
import { COMPONENT_ATTRIBUTE } from '../machine/machines-picker';

/** Contains logic to provide backward compatibility. */
@injectable()
export class BackwardCompatibilityResolver {

@inject(CheWorkspaceClient)
protected readonly cheWorkspaceClient!: CheWorkspaceClient;

/**
* Provides backward compatibility for `containerName` field of task configuration.
* `containerName` was used to indicate which container should be used for running task configuration
* `component` is used instead of `containerName` for this goal.
*
* So, the following configuration:
* {
* "type": "che",
* "label": "theia:build",
* "command": "yarn",
* "target": {
* "workingDir": "/projects/theia",
* "containerName": "che-dev"
* }
* }
*
* should be replaced by:
*
* {
* "type": "che",
* "label": "theia:build",
* "command": "yarn",
* "target": {
* "workingDir": "/projects/theia",
* "component": "che-dev"
* }
* }
*
* Note: `containerName` is replaced by empty `component` field if the corresponding component is not found.
* List of containers is displayed at running task for this case and user has opportunity to select a container for running.
*
* @param configs task configurations for resolving
*/
async resolveComponent(configs: che.TaskConfiguration[]): Promise<che.TaskConfiguration[]> {
if (configs.length === 0) {
return configs;
}

const containers = await this.cheWorkspaceClient.getMachines();
for (const config of configs) {
if (config.type !== CHE_TASK_TYPE) {
continue;
}

const target = config.target;
if (!target || !target.containerName) {
continue;
}

const containerName = target.containerName;
target.containerName = undefined;
target.component = '';

if (!containers.hasOwnProperty(containerName)) {
continue;
}

const container = containers[containerName];
const component = getAttribute(COMPONENT_ATTRIBUTE, container.attributes);
if (component) {
target.component = component;
}
}
return configs;
}
}
53 changes: 47 additions & 6 deletions plugins/task-plugin/src/task/che-task-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@

import { injectable, inject } from 'inversify';
import * as che from '@eclipse-che/plugin';
import { che as cheApi } from '@eclipse-che/api';
import { Task, ShellExecution } from '@theia/plugin';
import { CHE_TASK_TYPE, CheTaskDefinition, Target } from './task-protocol';
import { MachinesPicker } from '../machine/machines-picker';
import { MachinesPicker, COMPONENT_ATTRIBUTE } from '../machine/machines-picker';
import { CheWorkspaceClient } from '../che-workspace-client';
import { getAttribute } from '../utils';

/** Reads the commands from the current Che workspace and provides it as Task Configurations. */
@injectable()
Expand Down Expand Up @@ -45,11 +47,7 @@ export class CheTaskProvider {
resultTarget.workspaceId = await this.cheWorkspaceClient.getWorkspaceId();
}

if (target && target.containerName) {
resultTarget.containerName = target.containerName;
} else {
resultTarget.containerName = await this.machinePicker.pick();
}
resultTarget.containerName = await this.getContainerName(target);

if (target && target.workingDir) {
resultTarget.workingDir = await che.variables.resolve(target.workingDir);
Expand All @@ -71,4 +69,47 @@ export class CheTaskProvider {
execution: execution
};
}

private async getContainerName(target?: Target): Promise<string> {
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<string | undefined> {
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;
}
}
15 changes: 8 additions & 7 deletions plugins/task-plugin/src/task/converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
import { che as cheApi } from '@eclipse-che/api';
import { Task } from '@theia/plugin';
import { TaskConfiguration } from '@eclipse-che/plugin';
import { CHE_TASK_TYPE, MACHINE_NAME_ATTRIBUTE, PREVIEW_URL_ATTRIBUTE, WORKING_DIR_ATTRIBUTE } from './task-protocol';
import { CHE_TASK_TYPE, PREVIEW_URL_ATTRIBUTE, WORKING_DIR_ATTRIBUTE, COMPONENT_ALIAS_ATTRIBUTE } from './task-protocol';
import { getAttribute } from '../utils';

/** Converts the Che command to Theia Task Configuration */
export function toTaskConfiguration(command: cheApi.workspace.Command): TaskConfiguration {
Expand All @@ -21,10 +22,10 @@ export function toTaskConfiguration(command: cheApi.workspace.Command): TaskConf
command: command.commandLine,
_scope: undefined, // not to put into tasks.json
target: {
workingDir: getCommandAttribute(command, WORKING_DIR_ATTRIBUTE),
containerName: getCommandAttribute(command, MACHINE_NAME_ATTRIBUTE)
workingDir: getAttribute(WORKING_DIR_ATTRIBUTE, command.attributes),
component: getAttribute(COMPONENT_ALIAS_ATTRIBUTE, command.attributes)
},
previewUrl: getCommandAttribute(command, PREVIEW_URL_ATTRIBUTE)
previewUrl: getAttribute(PREVIEW_URL_ATTRIBUTE, command.attributes)
};

return taskConfig;
Expand All @@ -37,10 +38,10 @@ export function toTask(command: cheApi.workspace.Command): Task {
type: CHE_TASK_TYPE,
command: command.commandLine,
target: {
workingDir: getCommandAttribute(command, WORKING_DIR_ATTRIBUTE),
containerName: getCommandAttribute(command, MACHINE_NAME_ATTRIBUTE)
workingDir: getAttribute(WORKING_DIR_ATTRIBUTE, command.attributes),
component: getAttribute(COMPONENT_ALIAS_ATTRIBUTE, command.attributes)
},
previewUrl: getCommandAttribute(command, PREVIEW_URL_ATTRIBUTE)
previewUrl: getAttribute(PREVIEW_URL_ATTRIBUTE, command.attributes)
},
name: `${command.name}`,
source: CHE_TASK_TYPE,
Expand Down
2 changes: 2 additions & 0 deletions plugins/task-plugin/src/task/task-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const CHE_TASK_TYPE: string = 'che';
export const MACHINE_NAME_ATTRIBUTE: string = 'machineName';
export const PREVIEW_URL_ATTRIBUTE: string = 'previewUrl';
export const WORKING_DIR_ATTRIBUTE: string = 'workingDir';
export const COMPONENT_ALIAS_ATTRIBUTE: string = 'componentAlias';

export interface CheTaskDefinition extends TaskDefinition {
readonly target?: Target,
Expand All @@ -24,4 +25,5 @@ export interface Target {
workspaceId?: string,
containerName?: string,
workingDir?: string
component?: string,
}
Loading