Showing the changes to apps/server/src/sourceControl/BitbucketSourceControlProvider.ts (1 of 59 files). Show all
Unified · Split
| @@ -0,0 +1,126 @@ | |||
| 1 | import { Effect, Layer, Option } from "effect"; | ||
| 2 | import { SourceControlProviderError, type ChangeRequest } from "@t3tools/contracts"; | ||
| 3 | |||
| 4 | import * as BitbucketApi from "./BitbucketApi.ts"; | ||
| 5 | import * as BitbucketPullRequests from "./bitbucketPullRequests.ts"; | ||
| 6 | import * as SourceControlProvider from "./SourceControlProvider.ts"; | ||
| 7 | import type * as SourceControlProviderDiscovery from "./SourceControlProviderDiscovery.ts"; | ||
| 8 | |||
| 9 | function providerError( | ||
| 10 | operation: string, | ||
| 11 | cause: BitbucketApi.BitbucketApiError, | ||
| 12 | ): SourceControlProviderError { | ||
| 13 | return new SourceControlProviderError({ | ||
| 14 | provider: "bitbucket", | ||
| 15 | operation, | ||
| 16 | detail: cause.detail, | ||
| 17 | cause, | ||
| 18 | }); | ||
| 19 | } | ||
| 20 | |||
| 21 | function toChangeRequest( | ||
| 22 | summary: BitbucketPullRequests.NormalizedBitbucketPullRequestRecord, | ||
| 23 | ): ChangeRequest { | ||
| 24 | return { | ||
| 25 | provider: "bitbucket", | ||
| 26 | number: summary.number, | ||
| 27 | title: summary.title, | ||
| 28 | url: summary.url, | ||
| 29 | baseRefName: summary.baseRefName, | ||
| 30 | headRefName: summary.headRefName, | ||
| 31 | state: summary.state, | ||
| 32 | updatedAt: summary.updatedAt ?? Option.none(), | ||
| 33 | ...(summary.isCrossRepository !== undefined | ||
| 34 | ? { isCrossRepository: summary.isCrossRepository } | ||
| 35 | : {}), | ||
| 36 | ...(summary.headRepositoryNameWithOwner !== undefined | ||
| 37 | ? { headRepositoryNameWithOwner: summary.headRepositoryNameWithOwner } | ||
| 38 | : {}), | ||
| 39 | ...(summary.headRepositoryOwnerLogin !== undefined | ||
| 40 | ? { headRepositoryOwnerLogin: summary.headRepositoryOwnerLogin } | ||
| 41 | : {}), | ||
| 42 | }; | ||
| 43 | } | ||
| 44 | |||
| 45 | export const make = Effect.fn("makeBitbucketSourceControlProvider")(function* () { | ||
| 46 | const bitbucket = yield* BitbucketApi.BitbucketApi; | ||
| 47 | |||
| 48 | return SourceControlProvider.SourceControlProvider.of({ | ||
| 49 | kind: "bitbucket", | ||
| 50 | listChangeRequests: (input) => { | ||
| 51 | const source = SourceControlProvider.sourceControlRefFromInput(input); | ||
| 52 | return bitbucket | ||
| 53 | .listPullRequests({ | ||
| 54 | cwd: input.cwd, | ||
| 55 | ...(input.context ? { context: input.context } : {}), | ||
| 56 | headSelector: input.headSelector, | ||
| 57 | ...(source ? { source } : {}), | ||
| 58 | state: input.state, | ||
| 59 | ...(input.limit !== undefined ? { limit: input.limit } : {}), | ||
| 60 | }) | ||
| 61 | .pipe( | ||
| 62 | Effect.map((items) => items.map(toChangeRequest)), | ||
| 63 | Effect.mapError((error) => providerError("listChangeRequests", error)), | ||
| 64 | ); | ||
| 65 | }, | ||
| 66 | getChangeRequest: (input) => | ||
| 67 | bitbucket.getPullRequest(input).pipe( | ||
| 68 | Effect.map(toChangeRequest), | ||
| 69 | Effect.mapError((error) => providerError("getChangeRequest", error)), | ||
| 70 | ), | ||
| 71 | createChangeRequest: (input) => { | ||
| 72 | const source = SourceControlProvider.sourceControlRefFromInput(input); | ||
| 73 | return bitbucket | ||
| 74 | .createPullRequest({ | ||
| 75 | cwd: input.cwd, | ||
| 76 | ...(input.context ? { context: input.context } : {}), | ||
| 77 | baseBranch: input.baseRefName, | ||
| 78 | headSelector: input.headSelector, | ||
| 79 | ...(source ? { source } : {}), | ||
| 80 | ...(input.target ? { target: input.target } : {}), | ||
| 81 | title: input.title, | ||
| 82 | bodyFile: input.bodyFile, | ||
| 83 | }) | ||
| 84 | .pipe(Effect.mapError((error) => providerError("createChangeRequest", error))); | ||
| 85 | }, | ||
| 86 | getRepositoryCloneUrls: (input) => | ||
| 87 | bitbucket | ||
| 88 | .getRepositoryCloneUrls(input) | ||
| 89 | .pipe(Effect.mapError((error) => providerError("getRepositoryCloneUrls", error))), | ||
| 90 | createRepository: (input) => | ||
| 91 | bitbucket | ||
| 92 | .createRepository(input) | ||
| 93 | .pipe(Effect.mapError((error) => providerError("createRepository", error))), | ||
| 94 | getDefaultBranch: (input) => | ||
| 95 | bitbucket | ||
| 96 | .getDefaultBranch({ | ||
| 97 | cwd: input.cwd, | ||
| 98 | ...(input.context ? { context: input.context } : {}), | ||
| 99 | }) | ||
| 100 | .pipe(Effect.mapError((error) => providerError("getDefaultBranch", error))), | ||
| 101 | checkoutChangeRequest: (input) => | ||
| 102 | bitbucket | ||
| 103 | .checkoutPullRequest({ | ||
| 104 | cwd: input.cwd, | ||
| 105 | ...(input.context ? { context: input.context } : {}), | ||
| 106 | reference: input.reference, | ||
| 107 | ...(input.force !== undefined ? { force: input.force } : {}), | ||
| 108 | }) | ||
| 109 | .pipe(Effect.mapError((error) => providerError("checkoutChangeRequest", error))), | ||
| 110 | }); | ||
| 111 | }); | ||
| 112 | |||
| 113 | export const layer = Layer.effect(SourceControlProvider.SourceControlProvider, make()); | ||
| 114 | |||
| 115 | export const makeDiscovery = Effect.fn("makeBitbucketSourceControlProviderDiscovery")(function* () { | ||
| 116 | const bitbucket = yield* BitbucketApi.BitbucketApi; | ||
| 117 | |||
| 118 | return { | ||
| 119 | type: "api", | ||
| 120 | kind: "bitbucket", | ||
| 121 | label: "Bitbucket", | ||
| 122 | installHint: | ||
| 123 | "Set T3CODE_BITBUCKET_EMAIL and T3CODE_BITBUCKET_API_TOKEN on the server (use a Bitbucket API token with pull request and repository scopes).", | ||
| 124 | probeAuth: bitbucket.probeAuth, | ||
| 125 | } satisfies SourceControlProviderDiscovery.SourceControlApiDiscoverySpec; | ||
| 126 | }); | ||