From c712f753d37f5eaa8c6349c7ec07c409d43bf976 Mon Sep 17 00:00:00 2001 From: Simon Graband Date: Wed, 12 Oct 2022 12:51:26 +0200 Subject: [PATCH 1/2] Add `task#runOptions` to API. Additionally added functionality to support `reevaluateOnRerun`. If this flag is set to false no variables will be resolved again. Therefore lastTask can now be re-triggered without resolving all variables. For this the lastTask object was updated to contain all resolved information. Contributed on behalf of STMicroelectronics Resolves #11132 --- CHANGELOG.md | 9 +++++++ .../plugin-ext/src/common/plugin-api-rpc.ts | 5 ++++ .../plugin-ext/src/main/browser/tasks-main.ts | 3 ++- .../src/plugin/type-converters.spec.ts | 19 ++++++++++++-- .../plugin-ext/src/plugin/type-converters.ts | 5 +++- packages/plugin-ext/src/plugin/types-impl.ts | 12 +++++++++ packages/plugin/src/theia.d.ts | 15 +++++++++++ .../task/src/browser/task-configurations.ts | 2 +- packages/task/src/browser/task-service.ts | 25 ++++++++++++------- packages/task/src/common/task-protocol.ts | 6 +++++ 10 files changed, 87 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1a5984d9ebaf..bc7aa320226de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ - [Previous Changelogs](https://github.com/eclipse-theia/theia/tree/master/doc/changelogs/) +## v1.32.0 + +- [plugin] added `Task#runOptions` field and `RunOptions` interface [#11759](https://github.com/eclipse-theia/theia/pull/11759) - Contributed on behalf of STMicroelectronics +- [tasks] added support for `reevaluateOnRerun` run option [#11759](https://github.com/eclipse-theia/theia/pull/11759) - Contributed on behalf of STMicroelectronics + +[Breaking Changes:](#breaking_changes_1.32.0) + +- [tasks] if the variables of a task should be reevaluated on a rerun (this was the behavior until now) the `reevaluateOnRerun` run option in the task description needs to be set to `true` from now on [#11759](https://github.com/eclipse-theia/theia/pull/11759) - Contributed on behalf of STMicroelectronics + ## v1.31.0 - 10/27/2022 - [debug] added confirmation message for debug exit [#11546](https://github.com/eclipse-theia/theia/pull/11546) diff --git a/packages/plugin-ext/src/common/plugin-api-rpc.ts b/packages/plugin-ext/src/common/plugin-api-rpc.ts index cc04bd3b288c5..aaaf79f10c844 100644 --- a/packages/plugin-ext/src/common/plugin-api-rpc.ts +++ b/packages/plugin-ext/src/common/plugin-api-rpc.ts @@ -1456,10 +1456,15 @@ export interface TaskDto { group?: string; detail?: string; presentation?: TaskPresentationOptionsDTO; + runOptions?: RunOptionsDTO; // eslint-disable-next-line @typescript-eslint/no-explicit-any [key: string]: any; } +export interface RunOptionsDTO { + reevaluateOnRerun?: boolean; +} + export interface TaskPresentationOptionsDTO { reveal?: number; focus?: boolean; diff --git a/packages/plugin-ext/src/main/browser/tasks-main.ts b/packages/plugin-ext/src/main/browser/tasks-main.ts index cf64f49bce811..95310e5bd8c0c 100644 --- a/packages/plugin-ext/src/main/browser/tasks-main.ts +++ b/packages/plugin-ext/src/main/browser/tasks-main.ts @@ -202,7 +202,7 @@ export class TasksMainImpl implements TasksMain, Disposable { } protected toTaskConfiguration(taskDto: TaskDto): TaskConfiguration { - const { group, presentation, scope, source, ...common } = taskDto ?? {}; + const { group, presentation, scope, source, runOptions, ...common } = taskDto ?? {}; const partialConfig: Partial = {}; if (presentation) { partialConfig.presentation = this.convertTaskPresentation(presentation); @@ -213,6 +213,7 @@ export class TasksMainImpl implements TasksMain, Disposable { return { ...common, ...partialConfig, + runOptions, _scope: scope, _source: source, }; diff --git a/packages/plugin-ext/src/plugin/type-converters.spec.ts b/packages/plugin-ext/src/plugin/type-converters.spec.ts index a76b3de3fa7f2..215872b8ea479 100644 --- a/packages/plugin-ext/src/plugin/type-converters.spec.ts +++ b/packages/plugin-ext/src/plugin/type-converters.spec.ts @@ -202,7 +202,10 @@ describe('Type converters:', () => { reveal: 3, focus: true }, - group: groupDto + group: groupDto, + runOptions: { + reevaluateOnRerun: false + } }; const shellTaskDtoWithCommandLine: TaskDto = { @@ -213,7 +216,10 @@ describe('Type converters:', () => { scope: 2, command: commandLine, options: { cwd }, - additionalProperty + additionalProperty, + runOptions: { + reevaluateOnRerun: false + } }; const shellPluginTask: theia.Task = { @@ -235,6 +241,9 @@ describe('Type converters:', () => { options: { cwd } + }, + runOptions: { + reevaluateOnRerun: false } }; @@ -264,6 +273,9 @@ describe('Type converters:', () => { options: { cwd } + }, + runOptions: { + reevaluateOnRerun: false } }; @@ -291,6 +303,9 @@ describe('Type converters:', () => { options: { cwd } + }, + runOptions: { + reevaluateOnRerun: false } }; diff --git a/packages/plugin-ext/src/plugin/type-converters.ts b/packages/plugin-ext/src/plugin/type-converters.ts index d3f1ae6e47607..826c19ae88ef7 100644 --- a/packages/plugin-ext/src/plugin/type-converters.ts +++ b/packages/plugin-ext/src/plugin/type-converters.ts @@ -816,6 +816,8 @@ export function fromTask(task: theia.Task): TaskDto | undefined { taskDto.label = task.name; taskDto.source = task.source; + taskDto.runOptions = task.runOptions; + if ((task as types.Task).hasProblemMatchers) { taskDto.problemMatcher = task.problemMatchers; } @@ -877,10 +879,11 @@ export function toTask(taskDto: TaskDto): theia.Task { throw new Error('Task should be provided for converting'); } - const { type, taskType, label, source, scope, problemMatcher, detail, command, args, options, group, presentation, ...properties } = taskDto; + const { type, taskType, label, source, scope, problemMatcher, detail, command, args, options, group, presentation, runOptions, ...properties } = taskDto; const result = {} as theia.Task; result.name = label; result.source = source; + result.runOptions = runOptions ?? {}; if (detail) { result.detail = detail; } diff --git a/packages/plugin-ext/src/plugin/types-impl.ts b/packages/plugin-ext/src/plugin/types-impl.ts index cf9eea96158cb..038ed709a4941 100644 --- a/packages/plugin-ext/src/plugin/types-impl.ts +++ b/packages/plugin-ext/src/plugin/types-impl.ts @@ -2057,6 +2057,7 @@ export class Task { private taskSource: string; private taskGroup: TaskGroup | undefined; private taskPresentationOptions: theia.TaskPresentationOptions; + private _runOptions: theia.RunOptions; constructor( taskDefinition: theia.TaskDefinition, scope: theia.WorkspaceFolder | theia.TaskScope.Global | theia.TaskScope.Workspace, @@ -2229,6 +2230,17 @@ export class Task { } this.taskPresentationOptions = value; } + + get runOptions(): theia.RunOptions { + return this._runOptions; + } + + set runOptions(value: theia.RunOptions) { + if (value === null || value === undefined) { + value = Object.create(null); + } + this._runOptions = value; + } } @es5ClassCompat diff --git a/packages/plugin/src/theia.d.ts b/packages/plugin/src/theia.d.ts index 1de28bef1e37e..fab66987e8ab0 100644 --- a/packages/plugin/src/theia.d.ts +++ b/packages/plugin/src/theia.d.ts @@ -11532,6 +11532,16 @@ export module '@theia/plugin' { clear?: boolean; } + /** + * Run options for a task. + */ + export interface RunOptions { + /** + * Controls whether task variables are re-evaluated on rerun. + */ + reevaluateOnRerun?: boolean; + } + export class Task { /** @@ -11618,6 +11628,11 @@ export module '@theia/plugin' { * array. */ problemMatchers?: string[]; + + /** + * Run options for the task + */ + runOptions: RunOptions; } /** diff --git a/packages/task/src/browser/task-configurations.ts b/packages/task/src/browser/task-configurations.ts index 8bc5d5d4e2065..f44d4046c412f 100644 --- a/packages/task/src/browser/task-configurations.ts +++ b/packages/task/src/browser/task-configurations.ts @@ -328,7 +328,7 @@ export class TaskConfigurations implements Disposable { console.error('Detected / Contributed tasks should have a task definition.'); return; } - const customization: TaskCustomization = { type: task.type }; + const customization: TaskCustomization = { type: task.type, runOptions: task.runOptions }; definition.properties.all.forEach(p => { if (task[p] !== undefined) { customization[p] = task[p]; diff --git a/packages/task/src/browser/task-service.ts b/packages/task/src/browser/task-service.ts index f03dfe9c74d8d..be96841c2f534 100644 --- a/packages/task/src/browser/task-service.ts +++ b/packages/task/src/browser/task-service.ts @@ -87,13 +87,18 @@ export interface TaskEndedInfo { value: number | boolean | undefined } +export interface LastRunTaskInfo { + resolvedTask?: TaskConfiguration; + option?: RunTaskOption +} + @injectable() export class TaskService implements TaskConfigurationClient { /** * The last executed task. */ - protected lastTask: { source: string, taskLabel: string, scope: TaskConfigurationScope } | undefined = undefined; + protected lastTask: LastRunTaskInfo = {resolvedTask: undefined, option: undefined}; protected cachedRecentTasks: TaskConfiguration[] = []; protected runningTasks = new Map, @@ -470,7 +475,7 @@ export class TaskService implements TaskConfigurationClient { * * @returns the last executed task or `undefined`. */ - getLastTask(): { source: string, taskLabel: string, scope: TaskConfigurationScope } | undefined { + getLastTask(): LastRunTaskInfo { return this.lastTask; } @@ -496,11 +501,14 @@ export class TaskService implements TaskConfigurationClient { * @param token The cache token for the user interaction in progress */ async runLastTask(token: number): Promise { - if (!this.lastTask) { + if (!this.lastTask || !this.lastTask.resolvedTask) { return; } - const { source, taskLabel, scope } = this.lastTask; - return this.run(token, source, taskLabel, scope); + if (!this.lastTask.resolvedTask.runOptions?.reevaluateOnRerun) { + return this.runResolvedTask(this.lastTask.resolvedTask, this.lastTask.option); + } + const { _source, label, _scope } = this.lastTask.resolvedTask; + return this.run(token, _source, label, _scope); } /** @@ -737,7 +745,7 @@ export class TaskService implements TaskConfigurationClient { try { // resolve problemMatchers if (!option && task.problemMatcher) { - const customizationObject: TaskCustomization = { type: task.taskType, problemMatcher: task.problemMatcher }; + const customizationObject: TaskCustomization = { type: task.taskType, problemMatcher: task.problemMatcher, runOptions: task.runOptions }; const resolvedMatchers = await this.resolveProblemMatchers(task, customizationObject); option = { customization: { ...customizationObject, ...{ problemMatcher: resolvedMatchers } } @@ -949,7 +957,7 @@ export class TaskService implements TaskConfigurationClient { } protected async getTaskCustomization(task: TaskConfiguration): Promise { - const customizationObject: TaskCustomization = { type: '', _scope: task._scope }; + const customizationObject: TaskCustomization = { type: '', _scope: task._scope, runOptions: task.runOptions }; const customizationFound = this.taskConfigurations.getCustomizationForTask(task); if (customizationFound) { Object.assign(customizationObject, customizationFound); @@ -982,12 +990,11 @@ export class TaskService implements TaskConfigurationClient { * @param option options to run the resolved task */ protected async runResolvedTask(resolvedTask: TaskConfiguration, option?: RunTaskOption): Promise { - const source = resolvedTask._source; const taskLabel = resolvedTask.label; let taskInfo: TaskInfo | undefined; try { taskInfo = await this.taskServer.run(resolvedTask, this.getContext(), option); - this.lastTask = { source, taskLabel, scope: resolvedTask._scope }; + this.lastTask = {resolvedTask, option }; this.logger.debug(`Task created. Task id: ${taskInfo.taskId}`); /** diff --git a/packages/task/src/common/task-protocol.ts b/packages/task/src/common/task-protocol.ts index de2ce5415e8d7..1fc7894da579f 100644 --- a/packages/task/src/common/task-protocol.ts +++ b/packages/task/src/common/task-protocol.ts @@ -127,6 +127,8 @@ export interface TaskCustomization { /** The order the dependsOn tasks should be executed in. */ dependsOrder?: DependsOrder; + runOptions?: RunOptions; + // eslint-disable-next-line @typescript-eslint/no-explicit-any [name: string]: any; } @@ -228,6 +230,10 @@ export interface RunTaskOption { customization?: TaskCustomizationData; } +export interface RunOptions { + reevaluateOnRerun?: boolean; +} + /** Event sent when a task has concluded its execution */ export interface TaskExitedEvent { readonly taskId: number; From fd36854e1c7f116b87d2ee06a086f22b75e5fbdd Mon Sep 17 00:00:00 2001 From: Simon Graband Date: Mon, 17 Oct 2022 09:06:41 +0200 Subject: [PATCH 2/2] Address review feedback --- packages/plugin-ext/src/plugin/type-converters.ts | 2 +- packages/plugin-ext/src/plugin/types-impl.ts | 6 +++--- packages/task/src/browser/task-service.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/plugin-ext/src/plugin/type-converters.ts b/packages/plugin-ext/src/plugin/type-converters.ts index 826c19ae88ef7..9126224e0df44 100644 --- a/packages/plugin-ext/src/plugin/type-converters.ts +++ b/packages/plugin-ext/src/plugin/type-converters.ts @@ -816,7 +816,7 @@ export function fromTask(task: theia.Task): TaskDto | undefined { taskDto.label = task.name; taskDto.source = task.source; - taskDto.runOptions = task.runOptions; + taskDto.runOptions = { reevaluateOnRerun: task.runOptions.reevaluateOnRerun }; if ((task as types.Task).hasProblemMatchers) { taskDto.problemMatcher = task.problemMatchers; diff --git a/packages/plugin-ext/src/plugin/types-impl.ts b/packages/plugin-ext/src/plugin/types-impl.ts index 038ed709a4941..b990a737b52e4 100644 --- a/packages/plugin-ext/src/plugin/types-impl.ts +++ b/packages/plugin-ext/src/plugin/types-impl.ts @@ -2057,7 +2057,7 @@ export class Task { private taskSource: string; private taskGroup: TaskGroup | undefined; private taskPresentationOptions: theia.TaskPresentationOptions; - private _runOptions: theia.RunOptions; + private taskRunOptions: theia.RunOptions; constructor( taskDefinition: theia.TaskDefinition, scope: theia.WorkspaceFolder | theia.TaskScope.Global | theia.TaskScope.Workspace, @@ -2232,14 +2232,14 @@ export class Task { } get runOptions(): theia.RunOptions { - return this._runOptions; + return this.taskRunOptions; } set runOptions(value: theia.RunOptions) { if (value === null || value === undefined) { value = Object.create(null); } - this._runOptions = value; + this.taskRunOptions = value; } } diff --git a/packages/task/src/browser/task-service.ts b/packages/task/src/browser/task-service.ts index be96841c2f534..0a97486aabd03 100644 --- a/packages/task/src/browser/task-service.ts +++ b/packages/task/src/browser/task-service.ts @@ -501,7 +501,7 @@ export class TaskService implements TaskConfigurationClient { * @param token The cache token for the user interaction in progress */ async runLastTask(token: number): Promise { - if (!this.lastTask || !this.lastTask.resolvedTask) { + if (!this.lastTask?.resolvedTask) { return; } if (!this.lastTask.resolvedTask.runOptions?.reevaluateOnRerun) {