110 lines · 3.8 KB · TypeScript
RawDownload
import { Effect, Layer, Option } from "effect";import { SourceControlProviderError, type ChangeRequest } from "@t3tools/contracts"; import { GitLabCli, type GitLabCliError, type GitLabMergeRequestSummary } from "./GitLabCli.ts";import { SourceControlProvider, type SourceControlRefSelector } from "./SourceControlProvider.ts"; function providerError(operation: string, cause: GitLabCliError): SourceControlProviderError {  return new SourceControlProviderError({    provider: "gitlab",    operation,    detail: cause.detail,    cause,  });} function toChangeRequest(summary: GitLabMergeRequestSummary): ChangeRequest {  return {    provider: "gitlab",    number: summary.number,    title: summary.title,    url: summary.url,    baseRefName: summary.baseRefName,    headRefName: summary.headRefName,    state: summary.state ?? "open",    updatedAt: summary.updatedAt ?? Option.none(),    ...(summary.isCrossRepository !== undefined      ? { isCrossRepository: summary.isCrossRepository }      : {}),    ...(summary.headRepositoryNameWithOwner !== undefined      ? { headRepositoryNameWithOwner: summary.headRepositoryNameWithOwner }      : {}),    ...(summary.headRepositoryOwnerLogin !== undefined      ? { headRepositoryOwnerLogin: summary.headRepositoryOwnerLogin }      : {}),  };} function sourceFromInput(input: {  readonly headSelector: string;  readonly source?: SourceControlRefSelector;}): SourceControlRefSelector | undefined {  if (input.source) {    return input.source;  }   const match = /^([^:/\s]+):(.+)$/u.exec(input.headSelector.trim());  const owner = match?.[1]?.trim();  const refName = match?.[2]?.trim();  return owner && refName ? { owner, refName } : undefined;} export const make = Effect.fn("makeGitLabSourceControlProvider")(function* () {  const gitlab = yield* GitLabCli;   return SourceControlProvider.of({    kind: "gitlab",    listChangeRequests: (input) => {      const source = sourceFromInput(input);      return gitlab        .listMergeRequests({          cwd: input.cwd,          headSelector: input.headSelector,          ...(source ? { source } : {}),          state: input.state,          ...(input.limit !== undefined ? { limit: input.limit } : {}),        })        .pipe(          Effect.map((items) => items.map(toChangeRequest)),          Effect.mapError((error) => providerError("listChangeRequests", error)),        );    },    getChangeRequest: (input) =>      gitlab.getMergeRequest(input).pipe(        Effect.map(toChangeRequest),        Effect.mapError((error) => providerError("getChangeRequest", error)),      ),    createChangeRequest: (input) => {      const source = sourceFromInput(input);      return gitlab        .createMergeRequest({          cwd: input.cwd,          baseBranch: input.baseRefName,          headSelector: input.headSelector,          ...(source ? { source } : {}),          ...(input.target ? { target: input.target } : {}),          title: input.title,          bodyFile: input.bodyFile,        })        .pipe(Effect.mapError((error) => providerError("createChangeRequest", error)));    },    getRepositoryCloneUrls: (input) =>      gitlab        .getRepositoryCloneUrls(input)        .pipe(Effect.mapError((error) => providerError("getRepositoryCloneUrls", error))),    createRepository: (input) =>      gitlab        .createRepository(input)        .pipe(Effect.mapError((error) => providerError("createRepository", error))),    getDefaultBranch: (input) =>      gitlab        .getDefaultBranch(input)        .pipe(Effect.mapError((error) => providerError("getDefaultBranch", error))),    checkoutChangeRequest: (input) =>      gitlab        .checkoutMergeRequest(input)        .pipe(Effect.mapError((error) => providerError("checkoutChangeRequest", error))),  });}); export const layer = Layer.effect(SourceControlProvider, make());