Showing the changes to apps/server/src/sourceControl/GitLabSourceControlProvider.ts (1 of 24 files). Show all
Unified · Split
| @@ -0,0 +1,106 @@ | |||
| 1 | import { Effect, Layer, Option } from "effect"; | ||
| 2 | import { SourceControlProviderError, type ChangeRequest } from "@t3tools/contracts"; | ||
| 3 | |||
| 4 | import { GitLabCli, type GitLabCliError, type GitLabMergeRequestSummary } from "./GitLabCli.ts"; | ||
| 5 | import { SourceControlProvider, type SourceControlRefSelector } from "./SourceControlProvider.ts"; | ||
| 6 | |||
| 7 | function providerError(operation: string, cause: GitLabCliError): SourceControlProviderError { | ||
| 8 | return new SourceControlProviderError({ | ||
| 9 | provider: "gitlab", | ||
| 10 | operation, | ||
| 11 | detail: cause.detail, | ||
| 12 | cause, | ||
| 13 | }); | ||
| 14 | } | ||
| 15 | |||
| 16 | function toChangeRequest(summary: GitLabMergeRequestSummary): ChangeRequest { | ||
| 17 | return { | ||
| 18 | provider: "gitlab", | ||
| 19 | number: summary.number, | ||
| 20 | title: summary.title, | ||
| 21 | url: summary.url, | ||
| 22 | baseRefName: summary.baseRefName, | ||
| 23 | headRefName: summary.headRefName, | ||
| 24 | state: summary.state ?? "open", | ||
| 25 | updatedAt: summary.updatedAt ?? Option.none(), | ||
| 26 | ...(summary.isCrossRepository !== undefined | ||
| 27 | ? { isCrossRepository: summary.isCrossRepository } | ||
| 28 | : {}), | ||
| 29 | ...(summary.headRepositoryNameWithOwner !== undefined | ||
| 30 | ? { headRepositoryNameWithOwner: summary.headRepositoryNameWithOwner } | ||
| 31 | : {}), | ||
| 32 | ...(summary.headRepositoryOwnerLogin !== undefined | ||
| 33 | ? { headRepositoryOwnerLogin: summary.headRepositoryOwnerLogin } | ||
| 34 | : {}), | ||
| 35 | }; | ||
| 36 | } | ||
| 37 | |||
| 38 | function sourceFromInput(input: { | ||
| 39 | readonly headSelector: string; | ||
| 40 | readonly source?: SourceControlRefSelector; | ||
| 41 | }): SourceControlRefSelector | undefined { | ||
| 42 | if (input.source) { | ||
| 43 | return input.source; | ||
| 44 | } | ||
| 45 | |||
| 46 | const match = /^([^:/\s]+):(.+)$/u.exec(input.headSelector.trim()); | ||
| 47 | const owner = match?.[1]?.trim(); | ||
| 48 | const refName = match?.[2]?.trim(); | ||
| 49 | return owner && refName ? { owner, refName } : undefined; | ||
| 50 | } | ||
| 51 | |||
| 52 | export const make = Effect.fn("makeGitLabSourceControlProvider")(function* () { | ||
| 53 | const gitlab = yield* GitLabCli; | ||
| 54 | |||
| 55 | return SourceControlProvider.of({ | ||
| 56 | kind: "gitlab", | ||
| 57 | listChangeRequests: (input) => { | ||
| 58 | const source = sourceFromInput(input); | ||
| 59 | return gitlab | ||
| 60 | .listMergeRequests({ | ||
| 61 | cwd: input.cwd, | ||
| 62 | headSelector: input.headSelector, | ||
| 63 | ...(source ? { source } : {}), | ||
| 64 | state: input.state, | ||
| 65 | ...(input.limit !== undefined ? { limit: input.limit } : {}), | ||
| 66 | }) | ||
| 67 | .pipe( | ||
| 68 | Effect.map((items) => items.map(toChangeRequest)), | ||
| 69 | Effect.mapError((error) => providerError("listChangeRequests", error)), | ||
| 70 | ); | ||
| 71 | }, | ||
| 72 | getChangeRequest: (input) => | ||
| 73 | gitlab.getMergeRequest(input).pipe( | ||
| 74 | Effect.map(toChangeRequest), | ||
| 75 | Effect.mapError((error) => providerError("getChangeRequest", error)), | ||
| 76 | ), | ||
| 77 | createChangeRequest: (input) => { | ||
| 78 | const source = sourceFromInput(input); | ||
| 79 | return gitlab | ||
| 80 | .createMergeRequest({ | ||
| 81 | cwd: input.cwd, | ||
| 82 | baseBranch: input.baseRefName, | ||
| 83 | headSelector: input.headSelector, | ||
| 84 | ...(source ? { source } : {}), | ||
| 85 | ...(input.target ? { target: input.target } : {}), | ||
| 86 | title: input.title, | ||
| 87 | bodyFile: input.bodyFile, | ||
| 88 | }) | ||
| 89 | .pipe(Effect.mapError((error) => providerError("createChangeRequest", error))); | ||
| 90 | }, | ||
| 91 | getRepositoryCloneUrls: (input) => | ||
| 92 | gitlab | ||
| 93 | .getRepositoryCloneUrls(input) | ||
| 94 | .pipe(Effect.mapError((error) => providerError("getRepositoryCloneUrls", error))), | ||
| 95 | getDefaultBranch: (input) => | ||
| 96 | gitlab | ||
| 97 | .getDefaultBranch(input) | ||
| 98 | .pipe(Effect.mapError((error) => providerError("getDefaultBranch", error))), | ||
| 99 | checkoutChangeRequest: (input) => | ||
| 100 | gitlab | ||
| 101 | .checkoutMergeRequest(input) | ||
| 102 | .pipe(Effect.mapError((error) => providerError("checkoutChangeRequest", error))), | ||
| 103 | }); | ||
| 104 | }); | ||
| 105 | |||
| 106 | export const layer = Layer.effect(SourceControlProvider, make()); | ||