-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support Compound Tasks #6680
Support Compound Tasks #6680
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ShimonBenYair
thank you for your contribution!
I'm testing your changes and I can see two notifications when a task is terminated
Could you check this behavior?
packages/variable-resolver/src/browser/variable-resolver-service.ts
Outdated
Show resolved
Hide resolved
packages/variable-resolver/src/browser/variable-resolver-service.ts
Outdated
Show resolved
Hide resolved
const signal = await this.taskService.getTerminateSignal(taskInfo.taskId); | ||
if (signal !== undefined) { | ||
return this.doPostTaskAction(`Task '${taskName}' terminated by signal ${signal}.`); | ||
return Promise.race([this.taskService.getBackgroundTaskEndMatch(taskInfo.taskId), this.taskService.getExitCode(taskInfo.taskId)]).then(async result => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it looks tricky to decide what is a result depending on the type.
Can we use Promis.all
instead to have separate variables?
Also async/await
is more preferable than using promise chaining.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it looks tricky to decide what is a result depending on the type.
fixed.done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use
Promis.all
instead to have separate variables?Also
async/await
is more preferable than using promise chaining.
I must use here promise.race since i need to handle the case of depending on background tasks, and background tasks can send a feedback that the task was "ended" before the task was "exited".
@elaihau please review the task extension |
} | ||
} | ||
|
||
// tslint:disable-next-line: no-any |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
parameter and return types should not use any
, only if it json, please review the rest PR to have explicit types
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be a json object.
was fixed by renaming the variable and a documentation was added to the method
@@ -42,6 +43,9 @@ export class TaskWatcher { | |||
}, | |||
onDidProcessTaskOutput(event: TaskOutputProcessedEvent): void { | |||
outputProcessedEmitter.fire(event); | |||
}, | |||
onBackgroundTaskActive(event: BackgroundTaskEndEvent): void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What active means? Usually it means something what is focused in Theia.
coding guidelines for event naming: https://github.com/eclipse-theia/theia/wiki/Coding-Guidelines#event_names
Alternatively we usually fine with naming like on[Noun]PastTenseVerb
, i.e. onTaskCreated
or onCreated
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the comment.
was fixed and was change to 'onBackgroundTaskEnded'.
The server fires 'BackgroundTaskEndedEvent' when a background task matches its 'beginsPattern' and 'endsPattern' properties in order to notify the client (that the backround task is active).
e.g. if we have a main task that in its "dependsOn" array there is a task that for example runs tomcat ( so it is running in the background and doesn't seems to have exit code ) , then the root task will never start ...
So the solution is to have a problem matcher with a background property and when it matches the 'beginsPattern' and 'endsPattern' properties , we know that the task is active and we can move forward to the main task.
That's why i have added the 'onBackgroundTaskEnded'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you are going to already be updating the PR, I think another improvement would be to update the commit message. I think we can add a description of what the PR does and what it resolves.
Also if you add 'Fixes #5517', then the corresponding issue will automatically be closed when merged.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like the schemas for compound tasks are not supported at the moment (due to mandatory type
and command
properties).
An example is defined in the VS Code docs: (https://code.visualstudio.com/docs/editor/tasks#_compound-tasks)
{
"version": "2.0.0",
"tasks": [
{
"label": "Client Build",
"command": "gulp",
"args": ["build"],
"options": {
"cwd": "${workspaceRoot}/client"
}
},
{
"label": "Server Build",
"command": "gulp",
"args": ["build"],
"options": {
"cwd": "${workspaceRoot}/server"
}
},
{
"label": "Build",
"dependsOn": ["Client Build", "Server Build"]
}
]
}
@vince-fugnitto |
I'm not sure, maybe others can chime in @eclipse-theia/task-extension. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed that your custom task1
task fails silently when @theia/vscode-builtin-npm
is not included. I think that in this case and in other cases (where errors are thrown), a message should at least be displayed to end users and not fail silently.
Error:
task ERROR The information provied in the "dependsOn" is not enough for matching the correct task !
It would be nice if @elaihau or @RomanNikitenko can check new control flow, data structures, changes to APIs and so on. |
@elaihau WDYT? |
After a bit of investigating, the way forward would be to:
|
@vince-fugnitto |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will do more testing on the functionality later today.
Given that "task 2" depends on "task 1", one thing I found after testing was, vs code proceeded with "task 2" after "task 1" was terminated by "CTRL+C". This is different from what this pull request does. With this PR, "task 2" is not started if "task 1" is terminated by the user. I prefer the implementation in this PR. What do you think? @marcdumais-work @akosyakov @vince-fugnitto |
same question, do i need to change also here : https://github.com/eclipse-theia/theia/blob/master/packages/debug/src/node/vscode/vscode-debug-adapter-contribution.ts#L171 ? what is this file responsible for ? |
https://github.com/eclipse-theia/theia/blob/master/packages/plugin-ext/src/hosted/node/scanners/scanner-theia.ts#L495 https://github.com/eclipse-theia/theia/blob/master/packages/debug/src/node/vscode/vscode-debug-adapter-contribution.ts#L171 Yes, we have to change those files. |
I think it is better as well. If a task is dependent on another successfully completing, I do not expect the subsequent task to execute if the first has been terminated. However, we should get the opinion of others. I'm not sure that this will break behaviour from plugins contributing such tasks. |
I have fixed everything we talked about. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a few comments, mainly regarding typos and naming.
const code = await this.taskService.getExitCode(taskInfo.taskId); | ||
if (code === 0) { | ||
const getExitCodePromise: Promise<TaskEndedInfo> = this.taskService.getExitCode(taskInfo.taskId).then(result => | ||
({ taskEndedtype: TasksEndedTypes.TaskExited, value: result })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[minor] please rename to taskEndedType
following the guidelines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, done
const getExitCodePromise: Promise<TaskEndedInfo> = this.taskService.getExitCode(taskInfo.taskId).then(result => | ||
({ taskEndedtype: TasksEndedTypes.TaskExited, value: result })); | ||
const isBackgroundTaskEndedPromise: Promise<TaskEndedInfo> = this.taskService.isBackgroundTaskEnded(taskInfo.taskId).then(result => | ||
({ taskEndedtype: TasksEndedTypes.BackgroundTaskEnded, value: result })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[minor] please rename to taskEndedType
following the guidelines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, done
const isBackgroundTaskEndedPromise: Promise<TaskEndedInfo> = this.taskService.isBackgroundTaskEnded(taskInfo.taskId).then(result => | ||
({ taskEndedtype: TasksEndedTypes.BackgroundTaskEnded, value: result })); | ||
|
||
// After start running the task, we wait for the task proccess to exit and if it is a background task, we also wait for a feedback |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[minor] typo - proccess
should be process
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, done
// that a background task is active, as soon as one of the promises fulfills, we can continue and analyze the results. | ||
const taskEndedInfo: TaskEndedInfo = await Promise.race([getExitCodePromise, isBackgroundTaskEndedPromise]); | ||
|
||
if (taskEndedInfo.taskEndedtype === TasksEndedTypes.BackgroundTaskEnded && taskEndedInfo.value) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[minor] please rename to taskEndedType
following the guidelines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, done
return true; | ||
} else if (code !== undefined) { | ||
return this.doPostTaskAction(`Task '${taskName}' terminated with exit code ${code}.`); | ||
} else if (taskEndedInfo.taskEndedtype === TasksEndedTypes.TaskExited && taskEndedInfo.value !== undefined) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[minor] please rename to taskEndedType
following the guidelines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, done
} | ||
|
||
export interface TaskEndedInfo { | ||
taskEndedtype: TasksEndedTypes, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rename taskEndedtype
to taskEndedType
following the guidelines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, done
const isBackgroundTaskEndedPromise: Promise<TaskEndedInfo> = this.isBackgroundTaskEnded(taskInfo.taskId).then(result => | ||
({ taskEndedtype: TasksEndedTypes.BackgroundTaskEnded, value: result })); | ||
|
||
// After start running the task, we wait for the task proccess to exit and if it is a background task, we also wait for a feedback |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[minor] typo - proccess
should be process
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, done
const notEnoughDataError = 'The information provided in the "dependsOn" is not enough for matching the correct task !'; | ||
let currentTaskChildConfiguration: TaskConfiguration; | ||
if (typeof (taskIdentifier) !== 'string') { | ||
// TaskIdentier object does not support tasks of type 'shell' (The same behavior as in VS Code). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[minor] typo - TaskIdentier
should be TaskIndentifier
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, done
if (typeof (taskIdentifier) !== 'string') { | ||
// TaskIdentier object does not support tasks of type 'shell' (The same behavior as in VS Code). | ||
// So if we want the 'dependsOn' property to include tasks of type 'shell', | ||
// then we must mention their labels (in then'dependsOn' property) and not to create a task identifier object for them. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[minor] typo - should be the 'dependsOn'
property
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, done
dependsOn?: string | TaskIdentifier | Array<string | TaskIdentifier>; | ||
|
||
/** The order the dependsOn tasks should be executed in. */ | ||
dependsOrder?: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we use the enum
instead (ex: parallel
| sequence
) ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, done
Also, could you please create a github issue as per @vince-fugnitto suggested here, and let us know if you are going to work on it? Thank you ! |
@ShimonBenYair there is a difference when executing the task in VS Code and in Theia. VS Code
Theia: (only one terminal is ever spawned and its output displayed)
|
as you can see in the "How to test" section in step 6 , two terminals are opened, the first for the "runsample" (the task that task1 is depends on ) and the second terminal for the main task (task1). |
I'm asking since only one terminal is ever opened. Please see the gif from the lastest changes: |
Thanks a lot for finding this bug. |
I have created a github issue for it : #6757 I plan to work on it on January (I will notify in the issue when i start working on it) |
No problem :) it works a lot better now! |
I have fixed everything we talked about. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me.
@ShimonBenYair Would it be OK for you to hold this pull request until Dec 20, 2019 (GMT) ?
There will be a build on Dec 19. If your plan is not targeting the Dec 19 release, I guess it would be nice to have this feature merged after the release so that more contributors have opportunities to try it.
What do you think?
const backgroundTaskStatus = this.backgroundTaskStatusMap.get(event.taskId)!; | ||
if (!backgroundTaskStatus.isActive) { | ||
// Get the 'activeOnStart' value of the problem matcher 'background' property | ||
const activeOnStart = collector.problemMatchers[0]!.watching!.activeOnStart; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we certain that none of these properties will be undefined
when isBackground
is true?
Also, why do we only care about the first index?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, done.Now it behaves exactly like VS Code.
} | ||
} | ||
|
||
getTaskConfigurationByTaskIdentifier(taskDefinition: TaskDefinition | undefined, taskIdentifier: TaskIdentifier, tasks: TaskConfiguration[]): TaskConfiguration { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It isn't clear to me what this method actually does (implementation) and I think it'd be worthwhile to properly document it. What are we trying to ultimately achieve? Also, the naming of the method is misleading since we must provide many parameters not only TaskIdentifier
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, done
node: TaskNode; | ||
} | ||
|
||
export enum TasksEndedTypes { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason we name it TasksEndedTypes
and not TaskEndedTypes
similarly to other interfaces?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, done
if (typeof (taskIdentifier) !== 'string') { | ||
// TaskIdentifier object does not support tasks of type 'shell' (The same behavior as in VS Code). | ||
// So if we want the 'dependsOn' property to include tasks of type 'shell', | ||
// then we must mention their labels (in the'dependsOn' property) and not to create a task identifier object for them. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo - I don't think the typo has been addressed yet: (in the'dependsOn' property)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, done
Only official committers of the project are able to commit, explicitly approve, etc. |
and also Fixes #6534 Signed-off-by: Shimon Ben Yair <shimon.ben.yair@sap.com>
After consulting with my team we will appreciate if it will be part of Theia 14. |
I think that I will not implement it (due to change in the working priorities) |
Signed-off-by: Shimon Ben Yair shimon.ben.yair@sap.com
What it does
With changes in this pull request, Theia offers users to create compound tasks ( to create tasks that depends on other tasks).
The user can run the tasks ( that his tasks depends on) in sequence or in parallel.And after those tasks will end , the main task will start.
In addition the user can create a task that depends on a background task.
How to test
"dependsOn": [
"subTask2",
"subTask3"
],
"dependsOrder": "sequence"
and run "task1" ==> it should first run "subTask2" and then "subTask3" and when they are finished, "task1" will start.
"dependsOn": [
"subTask2",
"subTask3"
],
"dependsOrder": "parallel"
and run "task1" ==> it should run in parallel "subTask2" and "subTask3" and when they are finished,
"task1" will start.
"dependsOn": [
"testBackgroundTask"
],
"dependsOrder": "sequence"
and run "task1" ==> it should run first the "testBackgroundTask" task and when the ends pattern matches ( it will not wait until the whole task is finished and exited) "task1" will start.
"dependsOn": [
{"type":"npm", "script":"runsample"}
],
"dependsOrder": "sequence"
(Please notify that in the package.json file , there is a script named "runsample").
and run "task1" ==> it should run the script "runsample" before "task1" will start.
Review checklist