Skip to content

Commit 3f56aed

Browse files
test
Signed-off-by: Roman Nikitenko <rnikiten@redhat.com>
1 parent f4f2971 commit 3f56aed

1 file changed

Lines changed: 130 additions & 7 deletions

File tree

code/extensions/che-commands/src/taskProvider.ts

Lines changed: 130 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ interface DevfileTaskDefinition extends vscode.TaskDefinition {
1717
command: string;
1818
workdir?: string;
1919
component?: string;
20+
commandId?: string;
2021
}
2122

2223
export class DevfileTaskProvider implements vscode.TaskProvider {
@@ -35,15 +36,34 @@ export class DevfileTaskProvider implements vscode.TaskProvider {
3536
private async computeTasks(): Promise<vscode.Task[]> {
3637
const devfileCommands = await this.fetchDevfileCommands();
3738

38-
const cheTasks: vscode.Task[] = devfileCommands!
39-
.filter(command => command.exec?.commandLine)
39+
const localCommands = devfileCommands!
4040
.filter(command => {
4141
const importedByAttribute = (command.attributes as any)?.['controller.devfile.io/imported-by'];
4242
return !command.attributes || importedByAttribute === undefined || importedByAttribute === 'parent';
4343
})
44-
.filter(command => !/^init-ssh-agent-command-\d+$/.test(command.id))
45-
.map(command => this.createCheTask(command.exec?.label || command.id, command.exec?.commandLine!, command.exec?.workingDir || '${PROJECT_SOURCE}', command.exec?.component!, command.exec?.env));
46-
return cheTasks;
44+
.filter(command => !/^init-ssh-agent-command-\d+$/.test(command.id));
45+
46+
const execTasks: vscode.Task[] = localCommands
47+
.filter(command => command.exec?.commandLine)
48+
.map(command => this.createCheTask(
49+
command.exec?.label || command.id,
50+
command.exec?.commandLine!,
51+
command.exec?.workingDir || '${PROJECT_SOURCE}',
52+
command.exec?.component!,
53+
command.exec?.env,
54+
command.id
55+
));
56+
57+
const compositeTasks: vscode.Task[] = localCommands
58+
.filter(command => (command as any).composite?.commands?.length)
59+
.map(command => this.createCompositeTask(
60+
(command as any).composite?.label || command.id,
61+
(command as any).composite?.commands || [],
62+
Boolean((command as any).composite?.parallel),
63+
command.id
64+
));
65+
66+
return [...execTasks, ...compositeTasks];
4767
}
4868

4969
private async fetchDevfileCommands(): Promise<V1alpha2DevWorkspaceSpecTemplateCommands[]> {
@@ -56,7 +76,14 @@ export class DevfileTaskProvider implements vscode.TaskProvider {
5676
return [];
5777
}
5878

59-
private createCheTask(name: string, command: string, workdir: string, component: string, env?: Array<V1alpha2DevWorkspaceSpecTemplateCommandsItemsExecEnv>): vscode.Task {
79+
private createCheTask(
80+
name: string,
81+
command: string,
82+
workdir: string,
83+
component: string,
84+
env?: Array<V1alpha2DevWorkspaceSpecTemplateCommandsItemsExecEnv>,
85+
commandId?: string
86+
): vscode.Task {
6087
function expandEnvVariables(line: string): string {
6188
const regex = /\${[a-zA-Z_][a-zA-Z0-9_]*}/g;
6289
const envArray = line.match(regex);
@@ -75,7 +102,8 @@ export class DevfileTaskProvider implements vscode.TaskProvider {
75102
type: 'devfile',
76103
command,
77104
workdir,
78-
component
105+
component,
106+
commandId
79107
};
80108

81109
const execution = new vscode.CustomExecution(async (): Promise<vscode.Pseudoterminal> => {
@@ -92,4 +120,99 @@ export class DevfileTaskProvider implements vscode.TaskProvider {
92120
const task = new vscode.Task(kind, vscode.TaskScope.Workspace, name, 'devfile', execution, []);
93121
return task;
94122
}
123+
124+
private createCompositeTask(name: string, commandIds: string[], parallel: boolean, commandId: string): vscode.Task {
125+
const kind: DevfileTaskDefinition = {
126+
type: 'devfile',
127+
command: `composite:${commandId}`,
128+
commandId
129+
};
130+
131+
const writeEmitter = new vscode.EventEmitter<string>();
132+
const closeEmitter = new vscode.EventEmitter<void>();
133+
const activeExecutions: vscode.TaskExecution[] = [];
134+
135+
const execution = new vscode.CustomExecution(async (): Promise<vscode.Pseudoterminal> => {
136+
const pty: vscode.Pseudoterminal = {
137+
onDidWrite: writeEmitter.event,
138+
onDidClose: closeEmitter.event,
139+
open: async () => {
140+
writeEmitter.fire(`Running composite task: ${name}\r\n`);
141+
try {
142+
await this.runComposite(commandIds, parallel, writeEmitter, activeExecutions);
143+
writeEmitter.fire(`Composite task finished: ${name}\r\n`);
144+
} catch (error) {
145+
writeEmitter.fire(`Composite task failed: ${name}\r\n`);
146+
writeEmitter.fire(`${String(error)}\r\n`);
147+
} finally {
148+
closeEmitter.fire();
149+
}
150+
},
151+
close: () => {
152+
for (const execution of activeExecutions) {
153+
execution.terminate();
154+
}
155+
}
156+
};
157+
return pty;
158+
});
159+
160+
return new vscode.Task(kind, vscode.TaskScope.Workspace, name, 'devfile', execution, []);
161+
}
162+
163+
private async runComposite(
164+
commandIds: string[],
165+
parallel: boolean,
166+
writeEmitter: vscode.EventEmitter<string>,
167+
activeExecutions: vscode.TaskExecution[]
168+
): Promise<void> {
169+
const tasks = await vscode.tasks.fetchTasks({ type: 'devfile' });
170+
const taskMap = new Map<string, vscode.Task>();
171+
172+
for (const task of tasks) {
173+
const def = task.definition as DevfileTaskDefinition;
174+
if (def?.commandId) {
175+
taskMap.set(def.commandId, task);
176+
}
177+
taskMap.set(task.name, task);
178+
}
179+
180+
const targetTasks = commandIds
181+
.map(id => taskMap.get(id))
182+
.filter((task): task is vscode.Task => Boolean(task));
183+
184+
const missing = commandIds.filter(id => !taskMap.has(id));
185+
if (missing.length) {
186+
writeEmitter.fire(`Missing tasks: ${missing.join(', ')}\r\n`);
187+
}
188+
if (!targetTasks.length) {
189+
writeEmitter.fire('No tasks to run.\r\n');
190+
return;
191+
}
192+
193+
if (parallel) {
194+
const executions = await Promise.all(targetTasks.map(task => vscode.tasks.executeTask(task)));
195+
activeExecutions.push(...executions);
196+
await Promise.all(executions.map(execution => this.waitForTaskEnd(execution)));
197+
return;
198+
}
199+
200+
for (const task of targetTasks) {
201+
writeEmitter.fire(`Starting ${task.name}\r\n`);
202+
const execution = await vscode.tasks.executeTask(task);
203+
activeExecutions.push(execution);
204+
await this.waitForTaskEnd(execution);
205+
}
206+
}
207+
208+
private waitForTaskEnd(execution: vscode.TaskExecution): Promise<void> {
209+
return new Promise(resolve => {
210+
const disposable = vscode.tasks.onDidEndTask(event => {
211+
if (event.execution === execution) {
212+
disposable.dispose();
213+
resolve();
214+
}
215+
});
216+
});
217+
}
95218
}

0 commit comments

Comments
 (0)