summaryrefslogtreecommitdiff
path: root/model/pipeline
diff options
context:
space:
mode:
Diffstat (limited to 'model/pipeline')
-rw-r--r--model/pipeline/builder.ts53
-rw-r--r--model/pipeline/impl.ts20
-rw-r--r--model/pipeline/index.ts19
3 files changed, 92 insertions, 0 deletions
diff --git a/model/pipeline/builder.ts b/model/pipeline/builder.ts
new file mode 100644
index 0000000..e95e89c
--- /dev/null
+++ b/model/pipeline/builder.ts
@@ -0,0 +1,53 @@
+import { Pipeline, PipelineStage } from '.';
+import { FetchCodeJob } from '../job';
+import { PipelineImpl } from './impl';
+
+export interface PipelineBuilder {
+ addStage(stage: PipelineStage): PipelineBuilder;
+ build(): Pipeline;
+}
+
+export abstract class BasePipelineBuilder implements PipelineBuilder {
+ protected readonly stages: Array<PipelineStage> = [];
+
+ public addStage(stage: PipelineStage): PipelineBuilder {
+ this.stages.push(stage);
+ return this;
+ }
+
+ public build() {
+ return new PipelineImpl(this.stages);
+ }
+}
+
+export class DefaultGitHookPipelineBuilder extends BasePipelineBuilder {
+ constructor(
+ private readonly remoteUrl = process.env.remote!,
+ rev = process.env.rev!,
+ private readonly ref = process.env.ref!,
+ ) {
+ super();
+
+ this.addStage({
+ parallelJobs: [
+ <FetchCodeJob>{
+ type: 'fetch_code.ts',
+ arguments: {
+ remoteUrl,
+ checkout: rev,
+ path: this.getSourceDestination(),
+ },
+ },
+ ],
+ });
+ }
+
+ public getSourceDestination() {
+ return this.remoteUrl.split('/').at(-1) ?? 'src';
+ }
+
+ public getBranch(): string | undefined {
+ const branchRefPrefix = 'refs/heads/';
+ return this.ref.split(branchRefPrefix).at(1);
+ }
+}
diff --git a/model/pipeline/impl.ts b/model/pipeline/impl.ts
new file mode 100644
index 0000000..2e08d6e
--- /dev/null
+++ b/model/pipeline/impl.ts
@@ -0,0 +1,20 @@
+import { Either, IEither } from '@emprespresso/pengueno';
+import { isPipeline, Pipeline, PipelineStage } from '.';
+
+export class PipelineImpl implements Pipeline {
+ constructor(public readonly serialJobs: Array<PipelineStage>) {}
+
+ public serialize() {
+ return JSON.stringify(this.serialJobs);
+ }
+
+ public static from(s: string): IEither<Error, Pipeline> {
+ return Either.fromFailable<Error, unknown>(() => JSON.parse(s))
+ .flatMap<Pipeline>((eitherPipelineJson) =>
+ isPipeline(eitherPipelineJson)
+ ? Either.right(eitherPipelineJson)
+ : Either.left(new Error('oh noes D: its a bad pipewine :((')),
+ )
+ .mapRight((pipeline) => new PipelineImpl(pipeline.serialJobs));
+ }
+}
diff --git a/model/pipeline/index.ts b/model/pipeline/index.ts
new file mode 100644
index 0000000..adf902b
--- /dev/null
+++ b/model/pipeline/index.ts
@@ -0,0 +1,19 @@
+import { isObject } from '@emprespresso/pengueno';
+import { isJob, Job } from '../job';
+
+export interface PipelineStage {
+ readonly parallelJobs: Array<Job>;
+}
+export const isPipelineStage = (t: unknown): t is PipelineStage =>
+ isObject(t) && 'parallelJobs' in t && Array.isArray(t.parallelJobs) && t.parallelJobs.every((j) => isJob(j));
+
+export const isPipeline = (t: unknown): t is Pipeline =>
+ isObject(t) && 'serialJobs' in t && Array.isArray(t.serialJobs) && t.serialJobs.every((p) => isPipelineStage(p));
+
+export interface Pipeline {
+ readonly serialJobs: Array<PipelineStage>;
+ serialize(): string;
+}
+
+export * from './builder';
+export * from './impl';