Skip to content
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

Adding initial objects and builders #1

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
730 changes: 615 additions & 115 deletions API.md

Large diffs are not rendered by default.

86 changes: 86 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,92 @@ using [cdk8s](https://cdk8s.io/docs/latest/).
const pipeline = new Pipeline(this, 'my-pipeline');
```

## Pipeline objects and builders

Tekton [Pipelines](https://tekton.dev/docs/pipelines/),
[Tasks](https://tekton.dev/docs/pipelines/tasks/),
[Workspaces](https://tekton.dev/docs/pipelines/tasks/#specifying-workspaces),
[Parameters](https://tekton.dev/docs/pipelines/tasks/#specifying-parameters),
and other resources refer to one another within a pipeline. For example, a
Task may have a `params` that a value that is `$(params.foo)`, meaning it uses
the `param` named `foo` at the pipeline level within the task.

It is a goal of the _builders_ within this library to simplify that
cross-referencing during the process of defining a Pipeline and its `tasks`,
`workspaces`, and `params`.

Therefore, within this library there are objects that strictly define the
structure of the construct itself and can be `synth()`'ed to create the
Kubernetes resources. You are free to use the constructs and define all the
cross-references yourself. For example, here is a `Pipeline` that defines all
resources to create a Pipeline that closely matches the
[example here](https://tekton.dev/docs/how-to-guides/kaniko-build-push/):

```typescript
new Pipeline(this, 'test-pipeline', {
metadata: {
name: 'clone-build-push',
},
spec: {
description: 'This pipeline closes a repository, builds a Docker image, etc.',
params: [
{
name: 'repo-url',
type: 'string',
},
],
workspaces: [
{
name: 'shared-data',
},
],
tasks: [
{
name: 'fetch-source',
taskRef: {
name: 'git-clone',
},
workspaces: [
{
name: 'output',
workspace: 'shared-data',
},
],
params: [
{
name: 'url',
value: '$(params.repo-url)',
},
],
},
],
},
});
```

Alternatively, using the _builders_ (e.g., `PipelineBuilder`) for the resources
provides a fluid syntax that you can use to add the resources with cross-references
made for you automatically. Here is the same construct, but defined using the
`PipelineBuilder`.

```typescript
new PipelineBuilder(this, 'my-pipeline')
.withName('clone-build-push')
.withDescription('This pipeline closes a repository, builds a Docker image, etc.')
.withTask(new PipelineTaskBuilder()
.withName('fetch-source')
.withTaskReference('git-clone')
.withWorkspace('output', 'shared-data', 'The files cloned by the task')
.withStringParam('url', 'repo-url', '$(params.repo-url)'))
.buildPipeline();
```

The `build` method on the builders will validate the parameters and, if the
object is valid, will create the construct, making sure to add `workspace`
and `param` resources to the Task as well as the

Any resources that the `task` requires that needs to be defined at the `pipeline`

## Related projects

This is the core project with the basic Pipeline constructs. There are other
Expand Down
300 changes: 300 additions & 0 deletions src/builders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
/**
* This file has builders in it for the various pipeline constructs.
*/


import { Construct } from 'constructs';
import { Pipeline, PipelineParam, PipelineTask, PipelineTaskDef, PipelineWorkspace } from './pipelines';
import { TaskParam, TaskRef, TaskWorkspace } from './tasks';

/**
* The workspace record (WorkspaceRec) is used by the PipelineTaskBuilder
* internally to hold information about the parameters.
*/
export interface WorkspaceRec {
readonly name?: string;
readonly refName?: string;
readonly description?: string;
}

/**
* The parameter record (ParamRec) is used by the PipelineTaskBuilder builder
* internally to hold values for the parameter reference.
*/
export interface ParamRec {
readonly name?: string;
readonly defaultValue?: string;
readonly refName?: string;
readonly type?: string;
readonly value?: string;
}

/**
* The PipelineTaskBuilder creates a PipelineTaskDef, which is used to
* intelligently add a task and its properties to a Pipeline.
*/
export class PipelineTaskBuilder {
private _name?: string;
private _taskRefName?: string;
private _workspaces?: WorkspaceRec[];
private _parameters?: ParamRec[];
private _after?: string[];

/**
* Creates a new instance of the PipelineTaskBuilder
*/
public constructor() {
}

/**
* Provides the name for the pipeline task and will be
* rendered as the `name` property.
* @param name
*/
public withName(name: string): PipelineTaskBuilder {
this._name = name;
return this;
}

/**
* Returns the name of the task being built by the task builder.
*/
public get name(): string {
return this._name!;
}

/**
* Returns the parameter records for the task builder.
*/
public get parameters(): ParamRec[] {
return this._parameters!;
}

/**
* Returns the workspace records for the task builder.
*/
public get workspaces(): WorkspaceRec[] {
return this._workspaces!;
}

/**
* Returns the task reference name for the task builder.
*/
public get taskReference(): string {
return this._taskRefName!;
}

/**
* Allows you to specify that this task should be completed after another
* task. Can be called multiple times to add multiple tasks.
* @param otherTaskB
*/
public doAfter(otherTaskB: PipelineTaskBuilder): PipelineTaskBuilder {
if (!this._after) {
this._after = new Array<string>();
}
this._after.push(otherTaskB.name);
return this;
}

/**
* Creates and adds a [task reference](https://tekton.dev/docs/pipelines/tasks/#configuring-a-task) to the
* task, using the value supplied as the name of the reference. It returns
* a reference to the builder.
* @param ref The name of the task that is referenced.
*/
public withTaskReference(ref: string): PipelineTaskBuilder {
this._taskRefName = ref;
return this;
}


/**
* Adds workspace information to the pipeline task and returns a
* reference to the builder.
* @param name The name of the workspace on the pipeline task.
* @param refName The `workspace` value, which will be the name of the workspace
* at the Pipeline level.
* @param description The description of the Pipeline workspace.
*/
public withWorkspace(name: string, refName: string, description: string): PipelineTaskBuilder {
if (!this._workspaces) {
this._workspaces = new Array<WorkspaceRec>();
}
this._workspaces.push({
name: name,
refName: refName,
description: description,
});
return this;
}

/**
* Adds a parameter of type string to both the task and the pipeline itself.
* @param name The name of the param on the task.
* @param refName The name of the param at the pipeline level.
* @param value The value of the parameter on the task.
* @param defaultValue The default value for the param at the pipeline level
*/
public withStringParam(name: string, refName: string, value: string, defaultValue: string = ''): PipelineTaskBuilder {
if (!this._parameters) {
this._parameters = new Array<ParamRec>();
}
this._parameters!.push({
name: name,
value: value,
refName: refName,
type: 'string',
defaultValue: defaultValue,
});
return this;
}

/**
* Builds the Pipeline
*/

public buildPipelineTask(): PipelineTaskDef {
// TODO: An important part of build here is to assert that the
// object has been correctly made and throw very meaningful errors.
const pt = {
name: this.name,
taskRef: new TaskRef(this._taskRefName!),
params: [
{
name: 'url',
value: '$(params.repo-url)',
},
],
refParams: [
{
name: 'repo-url',
default: '',
type: 'string',
},
],
refWorkspaces: [
{
name: 'output',
workspace: 'shared-files',
description: 'The files that are cloned by the task',
},
],
};
return pt;
}

}

export class PipelineBuilder {
private readonly _scope?: Construct;
private readonly _id?: string;
private _name?: string;
private _description?: string;
private _tasks?: PipelineTaskBuilder[];

public constructor(scope: Construct, id: string) {
this._scope = scope;
this._id = id;
}

/**
* Provides the name for the pipeline task and will be
* rendered as the `name` property.
* @param name
*/
public withName(name: string): PipelineBuilder {
this._name = name;
return this;
}

/**
* Gets the name of the pipeline
*/
public get name(): string {
return this._name!;
}

/**
* Provides the name for the pipeline task and will be
* rendered as the `name` property.
* @param description
*/
public withDescription(description: string): PipelineBuilder {
this._description = description;
return this;
}

// Adds the task to the pipeline.
public withTask(taskB: PipelineTaskBuilder): PipelineBuilder {
// Add the task to the list of tasks...
if (!this._tasks) {
this._tasks = new Array<PipelineTaskBuilder>();
}
this._tasks.push(taskB);
return this;
}

/**
* Builds the actual [Pipeline]() from the settings configured using the
* fluid syntax.
*/
public buildPipeline(): void {
// TODO: validate the object
const pipelineParams: PipelineParam[] = new Array<PipelineParam>();
const pipelineWorkspaces: PipelineWorkspace[] = new Array<PipelineWorkspace>();
const pipelineTasks: PipelineTask[] = new Array<PipelineTask>();

this._tasks?.forEach(t => {

const taskParams: TaskParam[] = new Array<TaskParam>();
const taskWorkspaces: TaskWorkspace[] = new Array<TaskWorkspace>();

t.parameters?.forEach(p => {
pipelineParams.push({
name: p.refName,
type: p.type,
});

taskParams.push({
name: p.name,
value: p.value,
});
});

t.workspaces.forEach((w) => {
pipelineWorkspaces.push({
name: w.refName,
description: w.description,
});

taskWorkspaces.push({
name: w.name,
workspace: w.refName,
});
});

pipelineTasks.push({
name: t.name,
taskRef: {
name: t.taskReference,
},
params: taskParams,
workspaces: taskWorkspaces,
});
});

new Pipeline(this._scope!, this._id!, {
metadata:
{
name: this.name,
},
spec: {
description: this._description,
params: pipelineParams,
workspaces: pipelineWorkspaces,
tasks: pipelineTasks,
},
});
}
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './pipelines';
export * from './tasks';
export * from './common';
export * from './builders';
Loading
Loading