From 654450df07c22bd1930c014f8b3d6904df8248e9 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Mon, 25 Nov 2019 17:55:12 +0100 Subject: [PATCH] [FEATURE] AbstractBuilder: Allow adding custom tasks for types that have no standard tasks Types like "module" do not define any standard tasks. Hence custom tasks can't reference anything in their "beforeTask" and "afterTask" configuration. With this change, the first custom task that a project of such type defines can omit the before- or afterTask configuration and will be automatically added as the first tasks. Resolves https://github.com/SAP/ui5-builder/issues/368 --- lib/types/AbstractBuilder.js | 29 +++++++++++------- test/lib/types/AbstractBuilder.js | 50 +++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/lib/types/AbstractBuilder.js b/lib/types/AbstractBuilder.js index b7536c003..6361b1135 100644 --- a/lib/types/AbstractBuilder.js +++ b/lib/types/AbstractBuilder.js @@ -72,7 +72,8 @@ class AbstractBuilder { throw new Error(`Custom task definition ${taskDef.name} of project ${project.metadata.name} ` + `defines both "beforeTask" and "afterTask" parameters. Only one must be defined.`); } - if (!taskDef.beforeTask && !taskDef.afterTask) { + if (this.taskExecutionOrder.length && !taskDef.beforeTask && !taskDef.afterTask) { + // Iff there are tasks configured, beforeTask or afterTask must be given throw new Error(`Custom task definition ${taskDef.name} of project ${project.metadata.name} ` + `defines neither a "beforeTask" nor an "afterTask" parameter. One must be defined.`); } @@ -115,17 +116,23 @@ class AbstractBuilder { this.tasks[newTaskName] = execTask; - const refTaskName = taskDef.beforeTask || taskDef.afterTask; - let refTaskIdx = this.taskExecutionOrder.indexOf(refTaskName); - if (refTaskIdx === -1) { - throw new Error(`Could not find task ${refTaskName}, referenced by custom task ${newTaskName}, ` + - `to be scheduled for project ${project.metadata.name}`); - } - if (taskDef.afterTask) { - // Insert after index of referenced task - refTaskIdx++; + if (this.taskExecutionOrder.length) { + // There is at least one task configured. Use before- and afterTask to add the custom task + const refTaskName = taskDef.beforeTask || taskDef.afterTask; + let refTaskIdx = this.taskExecutionOrder.indexOf(refTaskName); + if (refTaskIdx === -1) { + throw new Error(`Could not find task ${refTaskName}, referenced by custom task ${newTaskName}, ` + + `to be scheduled for project ${project.metadata.name}`); + } + if (taskDef.afterTask) { + // Insert after index of referenced task + refTaskIdx++; + } + this.taskExecutionOrder.splice(refTaskIdx, 0, newTaskName); + } else { + // There is no task configured so far. Just add the custom task + this.taskExecutionOrder.push(newTaskName); } - this.taskExecutionOrder.splice(refTaskIdx, 0, newTaskName); } } diff --git a/test/lib/types/AbstractBuilder.js b/test/lib/types/AbstractBuilder.js index 971a78b9a..c656ca89c 100644 --- a/test/lib/types/AbstractBuilder.js +++ b/test/lib/types/AbstractBuilder.js @@ -77,6 +77,16 @@ class CustomBuilder extends AbstractBuilder { } } +class EmptyBuilder extends AbstractBuilder { + constructor({project, resourceCollections}) { + super({parentLogger, project, resourceCollections}); + } + + addStandardTasks({resourceCollections, project}) { + // None - like the ModuleBuilder + } +} + test("Instantiation with standard tasks only", (t) => { const project = clone(applicationBTree); @@ -178,6 +188,46 @@ test.serial("Instantiation with custom task", (t) => { "Order of tasks is correct"); }); +test.serial("Instantiation of empty builder with custom tasks", (t) => { + const customTask = function() {}; + sinon.stub(taskRepository, "getTask").returns(customTask); + + const project = clone(applicationBTree); + project.builder = { + customTasks: [{ + name: "myTask" + }, { + name: "myTask2", + beforeTask: "myTask" + }] + }; + const customBuilder = new EmptyBuilder({project}); + t.truthy(customBuilder.tasks["myTask"], "Custom task has been added to task array"); + t.truthy(customBuilder.tasks["myTask2"], "Custom task 2 has been added to task array"); + t.deepEqual(customBuilder.taskExecutionOrder, + ["myTask2", "myTask"], + "Order of tasks is correct"); +}); + +test.serial("Instantiation of empty builder with 2nd custom tasks defining neither beforeTask nor afterTask", (t) => { + const customTask = function() {}; + sinon.stub(taskRepository, "getTask").returns(customTask); + + const project = clone(applicationBTree); + project.builder = { + customTasks: [{ + name: "myTask" + }, { + name: "myTask2" // should define before- or afterTask + }] + }; + const error = t.throws(() => { + new EmptyBuilder({project}); + }, Error); + t.deepEqual(error.message, `Custom task definition myTask2 of project application.b defines ` + + `neither a "beforeTask" nor an "afterTask" parameter. One must be defined.`, "Correct exception thrown"); +}); + test.serial("Instantiation with custom task defined three times", (t) => { const customTask = function() {}; sinon.stub(taskRepository, "getTask").returns(customTask);