Showing the changes to apps/server/src/sourceControl/GitLabSourceControlProvider.ts (1 of 59 files). Show all
Unified · Split
| @@ -1,10 +1,14 @@ | ||
| 1 | 1 | import { Effect, Layer, Option } from "effect"; |
| 2 | 2 | import { SourceControlProviderError, type ChangeRequest } from "@t3tools/contracts"; |
| 3 | 3 | |
| 4 | −import { GitLabCli, type GitLabCliError, type GitLabMergeRequestSummary } from "./GitLabCli.ts"; | |
| 5 | −import { SourceControlProvider, type SourceControlRefSelector } from "./SourceControlProvider.ts"; | |
| 4 | +import * as GitLabCli from "./GitLabCli.ts"; | |
| 5 | +import * as SourceControlProvider from "./SourceControlProvider.ts"; | |
| 6 | +import * as SourceControlProviderDiscovery from "./SourceControlProviderDiscovery.ts"; | |
| 6 | 7 | |
| 7 | −function providerError(operation: string, cause: GitLabCliError): SourceControlProviderError { | |
| 8 | +function providerError( | |
| 9 | + operation: string, | |
| 10 | + cause: GitLabCli.GitLabCliError, | |
| 11 | +): SourceControlProviderError { | |
| 8 | 12 | return new SourceControlProviderError({ |
| 9 | 13 | provider: "gitlab", |
| 10 | 14 | operation, |
| @@ -13,7 +17,7 @@ function providerError(operation: string, cause: GitLabCliError): SourceControlP · 2 unmodified lines | ||
| 13 | 17 | }); |
| 14 | 18 | } |
| 15 | 19 | |
| 16 | −function toChangeRequest(summary: GitLabMergeRequestSummary): ChangeRequest { | |
| 20 | +function toChangeRequest(summary: GitLabCli.GitLabMergeRequestSummary): ChangeRequest { | |
| 17 | 21 | return { |
| 18 | 22 | provider: "gitlab", |
| 19 | 23 | number: summary.number, |
| @@ -35,27 +39,57 @@ function toChangeRequest(summary: GitLabMergeRequestSummary): ChangeRequest { · 15 unmodified lines | ||
| 35 | 39 | }; |
| 36 | 40 | } |
| 37 | 41 | |
| 38 | −function sourceFromInput(input: { | |
| 39 | − readonly headSelector: string; | |
| 40 | − readonly source?: SourceControlRefSelector; | |
| 41 | −}): SourceControlRefSelector | undefined { | |
| 42 | − if (input.source) { | |
| 43 | − return input.source; | |
| 42 | +function parseGitLabAuth(input: SourceControlProviderDiscovery.SourceControlAuthProbeInput) { | |
| 43 | + const output = SourceControlProviderDiscovery.combinedAuthOutput(input); | |
| 44 | + const account = SourceControlProviderDiscovery.matchFirst(output, [ | |
| 45 | + /Logged in to .* as\s+([^\s(]+)/iu, | |
| 46 | + /Logged in to .* account\s+([^\s(]+)/iu, | |
| 47 | + /account:\s*([^\s(]+)/iu, | |
| 48 | + ]); | |
| 49 | + const host = SourceControlProviderDiscovery.parseCliHost(output); | |
| 50 | + | |
| 51 | + if (input.exitCode !== 0) { | |
| 52 | + return SourceControlProviderDiscovery.providerAuth({ | |
| 53 | + status: "unauthenticated", | |
| 54 | + host, | |
| 55 | + detail: | |
| 56 | + SourceControlProviderDiscovery.firstSafeAuthLine(output) ?? | |
| 57 | + "Run `glab auth login` to authenticate GitLab CLI.", | |
| 58 | + }); | |
| 59 | + } | |
| 60 | + | |
| 61 | + if (account) { | |
| 62 | + return SourceControlProviderDiscovery.providerAuth({ status: "authenticated", account, host }); | |
| 44 | 63 | } |
| 45 | 64 | |
| 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; | |
| 65 | + return SourceControlProviderDiscovery.providerAuth({ | |
| 66 | + status: "unknown", | |
| 67 | + host, | |
| 68 | + detail: | |
| 69 | + SourceControlProviderDiscovery.firstSafeAuthLine(output) ?? | |
| 70 | + "GitLab CLI auth status could not be parsed.", | |
| 71 | + }); | |
| 50 | 72 | } |
| 51 | 73 | |
| 74 | +export const discovery = { | |
| 75 | + type: "cli", | |
| 76 | + kind: "gitlab", | |
| 77 | + label: "GitLab", | |
| 78 | + executable: "glab", | |
| 79 | + versionArgs: ["--version"], | |
| 80 | + authArgs: ["auth", "status"], | |
| 81 | + parseAuth: parseGitLabAuth, | |
| 82 | + installHint: | |
| 83 | + "Install the GitLab command-line tool (`glab`) from https://gitlab.com/gitlab-org/cli or your package manager (for example `brew install glab`).", | |
| 84 | +} satisfies SourceControlProviderDiscovery.SourceControlCliDiscoverySpec; | |
| 85 | + | |
| 52 | 86 | export const make = Effect.fn("makeGitLabSourceControlProvider")(function* () { |
| 53 | − const gitlab = yield* GitLabCli; | |
| 87 | + const gitlab = yield* GitLabCli.GitLabCli; | |
| 54 | 88 | |
| 55 | − return SourceControlProvider.of({ | |
| 89 | + return SourceControlProvider.SourceControlProvider.of({ | |
| 56 | 90 | kind: "gitlab", |
| 57 | 91 | listChangeRequests: (input) => { |
| 58 | − const source = sourceFromInput(input); | |
| 92 | + const source = SourceControlProvider.sourceControlRefFromInput(input); | |
| 59 | 93 | return gitlab |
| 60 | 94 | .listMergeRequests({ |
| 61 | 95 | cwd: input.cwd, |
| @@ -75,7 +109,7 @@ export const make = Effect.fn("makeGitLabSourceControlProvider")(function* () { · 13 unmodified lines | ||
| 75 | 109 | Effect.mapError((error) => providerError("getChangeRequest", error)), |
| 76 | 110 | ), |
| 77 | 111 | createChangeRequest: (input) => { |
| 78 | − const source = sourceFromInput(input); | |
| 112 | + const source = SourceControlProvider.sourceControlRefFromInput(input); | |
| 79 | 113 | return gitlab |
| 80 | 114 | .createMergeRequest({ |
| 81 | 115 | cwd: input.cwd, |
| @@ -107,4 +141,4 @@ export const make = Effect.fn("makeGitLabSourceControlProvider")(function* () { · 25 unmodified lines | ||
| 107 | 141 | }); |
| 108 | 142 | }); |
| 109 | 143 | |
| 110 | −export const layer = Layer.effect(SourceControlProvider, make()); | |
| 144 | +export const layer = Layer.effect(SourceControlProvider.SourceControlProvider, make()); | |