diff --git a/API.md b/API.md index b72452d..97c1333 100644 --- a/API.md +++ b/API.md @@ -3321,6 +3321,7 @@ new TaskBuilder(scope: Construct, id: string) | **Name** | **Description** | | --- | --- | | buildTask | Builds the `Task`. | +| specifyRunAfter | Allows you to specify the names of which task(s), if any, the 'Task' should run after in a pipeline. | | withAnnotation | Adds an annotation to the `Task` `metadata` with the provided key and value. | | withDescription | Sets the `description` of the `Task` being built. | | withLabel | Adds a label to the `Task` with the provided label key and value. | @@ -3340,6 +3341,24 @@ public buildTask(): void Builds the `Task`. +##### `specifyRunAfter` + +```typescript +public specifyRunAfter(taskArray: string[]): TaskBuilder +``` + +Allows you to specify the names of which task(s), if any, the 'Task' should run after in a pipeline. + +An empty array as input indicates the 'Task' yaml +should have no runAfter field. +By default, the value of runAfter is set to the preceeding 'Task' in the pipeline. + +###### `taskArray`Required + +- *Type:* string[] + +--- + ##### `withAnnotation` ```typescript @@ -3490,9 +3509,10 @@ Adds the specified workspace to the `Task`. | **Name** | **Type** | **Description** | | --- | --- | --- | | logicalID | string | *No description.* | -| description | string | Gets the `description` of the `Task`. | | name | string | Gets the name of the `Task` in the context of a pipeline. | +| description | string | Gets the `description` of the `Task`. | | parameters | ParameterBuilder[] | *No description.* | +| runAfter | string[] | Gets the list of task names for the runAfter value of the `Task`. | | workspaces | WorkspaceBuilder[] | Gets the workspaces for the `Task`. | --- @@ -3507,27 +3527,29 @@ public readonly logicalID: string; --- -##### `description`Optional +##### `name`Required ```typescript -public readonly description: string; +public readonly name: string; ``` - *Type:* string -Gets the `description` of the `Task`. +Gets the name of the `Task` in the context of a pipeline. + +If not set, the 'Task' id is used. --- -##### `name`Optional +##### `description`Optional ```typescript -public readonly name: string; +public readonly description: string; ``` - *Type:* string -Gets the name of the `Task` in the context of a pipeline. +Gets the `description` of the `Task`. --- @@ -3541,6 +3563,18 @@ public readonly parameters: ParameterBuilder[]; --- +##### `runAfter`Optional + +```typescript +public readonly runAfter: string[]; +``` + +- *Type:* string[] + +Gets the list of task names for the runAfter value of the `Task`. + +--- + ##### `workspaces`Optional ```typescript diff --git a/src/builders.ts b/src/builders.ts index b8b9121..166e188 100644 --- a/src/builders.ts +++ b/src/builders.ts @@ -664,6 +664,7 @@ export class TaskBuilder { private _labels?: { [key: string]: string; }; + private _runafter?: string[]; /** * Creates a new instance of the `TaskBuilder` using the given `scope` and @@ -717,9 +718,10 @@ export class TaskBuilder { /** * Gets the name of the `Task` in the context of a pipeline. + * If not set, the 'Task' id is used. */ - public get name(): string | undefined { - return this._name; + public get name(): string { + return this._name || this._id; } /** @@ -807,6 +809,25 @@ export class TaskBuilder { return this; } + /** + * Allows you to specify the names of which task(s), if any, the 'Task' should + * run after in a pipeline. An empty array as input indicates the 'Task' yaml + * should have no runAfter field. + * By default, the value of runAfter is set to the preceeding 'Task' in the pipeline. + * @param taskArray + */ + public specifyRunAfter(taskArray: string[]): TaskBuilder { + this._runafter = taskArray; + return this; + } + + /** + * Gets the list of task names for the runAfter value of the `Task`. + */ + public get runAfter(): string[] | undefined { + return this._runafter; + } + /** * Builds the `Task`. */ @@ -1019,7 +1040,7 @@ export class PipelineBuilder { this._tasks?.forEach((t, i) => { - const taskName = t.name || t.logicalID; + const taskName = t.name; if (taskNames.find(it => { return it == taskName; })) { @@ -1044,7 +1065,19 @@ export class PipelineBuilder { }); }); - const pt = createOrderedPipelineTask(t, ((i > 0) ? (this._tasks![i - 1].name || this._tasks![i - 1].logicalID) : ''), taskParams, taskWorkspaces); + const after = []; + if (t.runAfter != undefined) { + t.runAfter.forEach(name => { + if (!this._tasks?.find(it => {return (it.name) == name;})) { + throw new Error(`'${name}' supplied as value for runAfter but no such task found in pipeline.`); + } + after.push(name); + }); + } else if (i > 0) { + after.push(this._tasks![i - 1].name); + } + + const pt = createOrderedPipelineTask(t, after, taskParams, taskWorkspaces); pipelineTasks.push(pt); @@ -1076,20 +1109,20 @@ export class PipelineBuilder { } } -function createOrderedPipelineTask(t: TaskBuilder, after: string, params: TaskParam[], ws: TaskWorkspace[]): PipelineTask { - if (after) { +function createOrderedPipelineTask(t: TaskBuilder, after: string[], params: TaskParam[], ws: TaskWorkspace[]): PipelineTask { + if (after.length) { return { - name: t.name || t.logicalID, + name: t.name, taskRef: { name: t.logicalID, }, - runAfter: [after], + runAfter: after, params: params, workspaces: ws, }; } return { - name: t.name || t.logicalID, + name: t.name, taskRef: { name: t.logicalID, }, diff --git a/test/__snapshots__/pipelinebuilder.test.ts.snap b/test/__snapshots__/pipelinebuilder.test.ts.snap index 8e60bbe..fa3c47d 100644 --- a/test/__snapshots__/pipelinebuilder.test.ts.snap +++ b/test/__snapshots__/pipelinebuilder.test.ts.snap @@ -229,6 +229,87 @@ exports[`PipelineBuilderTest PipelineBuilderWithParameters 1`] = ` ] `; +exports[`PipelineBuilderTest PipelineBuilderWithRunAfter 1`] = ` +[ + { + "apiVersion": "tekton.dev/v1", + "kind": "Task", + "metadata": { + "annotations": undefined, + "labels": undefined, + "name": "print-readme", + }, + "spec": { + "description": undefined, + "params": [], + "results": [], + "steps": [], + "workspaces": [], + }, + }, + { + "apiVersion": "tekton.dev/v1", + "kind": "Task", + "metadata": { + "annotations": undefined, + "labels": undefined, + "name": "git-clone", + }, + "spec": { + "description": undefined, + "params": [], + "results": [], + "steps": [], + "workspaces": [], + }, + }, + { + "apiVersion": "tekton.dev/v1", + "kind": "Pipeline", + "metadata": { + "name": "clone-read", + }, + "spec": { + "description": undefined, + "params": [], + "tasks": [ + { + "name": "cat-readme", + "params": [], + "runAfter": [ + "fetch-again", + ], + "taskRef": { + "name": "print-readme", + }, + "workspaces": [], + }, + { + "name": "fetch-source", + "params": [], + "taskRef": { + "name": "git-clone", + }, + "workspaces": [], + }, + { + "name": "fetch-again", + "params": [], + "runAfter": [ + "fetch-source", + ], + "taskRef": { + "name": "git-clone", + }, + "workspaces": [], + }, + ], + "workspaces": [], + }, + }, +] +`; + exports[`PipelineBuilderTest PipelineBuilderWithSimilarTasks 1`] = ` [ { diff --git a/test/pipelinebuilder.test.ts b/test/pipelinebuilder.test.ts index 55618e3..c969499 100644 --- a/test/pipelinebuilder.test.ts +++ b/test/pipelinebuilder.test.ts @@ -309,6 +309,43 @@ class MyTestChartWithSimilarTasks extends Chart { } } +class MyTestChartWithRunAfter extends Chart { + constructor(scope: Construct, id: string, props?: ChartProps) { + super(scope, id, props); + + const firstTask = new TaskBuilder(this, 'git-clone') + .withName('fetch-source') + .specifyRunAfter([]); + + const secondTask = new TaskBuilder(this, 'git-clone') + .withName('fetch-again'); + + const thirdTask = new TaskBuilder(this, 'print-readme') + .withName('cat-readme') + .specifyRunAfter(['fetch-again']); + + new PipelineBuilder(this, 'clone-read') + .withTask(thirdTask) + .withTask(firstTask) + .withTask(secondTask) + .buildPipeline({ includeDependencies: true }); + } +} + +class MyTestChartWithRunAfterError extends Chart { + constructor(scope: Construct, id: string, props?: ChartProps) { + super(scope, id, props); + + const myTask = new TaskBuilder(this, 'print-readme') + .withName('cat-readme') + .specifyRunAfter(['fetch-source']); + + new PipelineBuilder(this, 'clone-read') + .withTask(myTask) + .buildPipeline({ includeDependencies: true }); + } +} + describe('PipelineBuilderTest', () => { test('PipelineRunBuilder', () => { const app = Testing.app(); @@ -383,4 +420,19 @@ describe('PipelineBuilderTest', () => { const results = Testing.synth(chart); expect(results).toMatchSnapshot(); }); + + test('PipelineBuilderWithRunAfter', () => { + const app = Testing.app(); + const chart = new MyTestChartWithRunAfter(app, 'test-chart'); + const results = Testing.synth(chart); + expect(results).toMatchSnapshot(); + }); + + test('PipelineBuilderWithRunAfterError', () => { + const app = Testing.app(); + const f = () => { + new MyTestChartWithRunAfterError(app, 'test-chart'); + }; + expect(f).toThrowError('\'fetch-source\' supplied as value for runAfter but no such task found in pipeline.'); + }); });