summaryrefslogtreecommitdiff
path: root/model/pipeline.ts
blob: b0db1b7394b753113ae073af38319e2a1045409b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import { Either, type IEither, isObject } from "@emprespresso/pengueno";
import { type FetchCodeJob, isJob, type Job } from "@emprespresso/ci-model";

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 interface Pipeline {
  readonly serialJobs: Array<PipelineStage>;
  serialize(): string;
}
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 PipelineBuilder {
  addStage(stage: PipelineStage): PipelineBuilder;
  build(): Pipeline;
}

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));
  }
}

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 = Deno.env.get("remote")!,
    rev = Deno.env.get("rev")!,
    private readonly ref = Deno.env.get("ref")!,
  ) {
    super();

    this.addStage({
      parallelJobs: [
        <FetchCodeJob> {
          type: "fetch_code",
          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);
  }
}