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..9126224e0df44 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 = { reevaluateOnRerun: task.runOptions.reevaluateOnRerun };
+
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..b990a737b52e4 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 taskRunOptions: 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.taskRunOptions;
+ }
+
+ set runOptions(value: theia.RunOptions) {
+ if (value === null || value === undefined) {
+ value = Object.create(null);
+ }
+ this.taskRunOptions = 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..0a97486aabd03 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?.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;