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