263 lines · 8.1 KB · TypeScript
RawDownload
import { assert, it } from "@effect/vitest";import * as NodeServices from "@effect/platform-node/NodeServices";import * as DateTime from "effect/DateTime";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer";import * as Option from "effect/Option";import { ChildProcessSpawner } from "effect/unstable/process";import { VcsRepositoryDetectionError } from "@t3tools/contracts"; import * as ServerConfig from "../config.ts";import type * as VcsDriver from "../vcs/VcsDriver.ts";import * as VcsDriverRegistry from "../vcs/VcsDriverRegistry.ts";import * as VcsProcess from "../vcs/VcsProcess.ts";import * as AzureDevOpsCli from "./AzureDevOpsCli.ts";import * as BitbucketApi from "./BitbucketApi.ts";import * as GitHubCli from "./GitHubCli.ts";import * as GitLabCli from "./GitLabCli.ts";import * as SourceControlProviderRegistry from "./SourceControlProviderRegistry.ts"; const TEST_EPOCH = DateTime.makeUnsafe("1970-01-01T00:00:00.000Z"); const processOutput = (  stdout: string,  options?: {    readonly stderr?: string;    readonly exitCode?: ChildProcessSpawner.ExitCode;  },): VcsProcess.VcsProcessOutput => ({  exitCode: options?.exitCode ?? ChildProcessSpawner.ExitCode(0),  stdout,  stderr: options?.stderr ?? "",  stdoutTruncated: false,  stderrTruncated: false,}); function makeRegistry(input: {  readonly remotes: ReadonlyArray<{    readonly name: string;    readonly url: string;  }>;  readonly process?: Partial<VcsProcess.VcsProcess["Service"]>;  readonly resolve?: VcsDriverRegistry.VcsDriverRegistry["Service"]["resolve"];}) {  const driver = {    listRemotes: () =>      Effect.succeed({        remotes: input.remotes.map((remote) => ({          ...remote,          pushUrl: Option.none(),          isPrimary: remote.name === "origin",        })),        freshness: {          source: "live-local" as const,          observedAt: TEST_EPOCH,          expiresAt: Option.none(),        },      }),  } satisfies Partial<VcsDriver.VcsDriver["Service"]>;   const registryLayer = Layer.mock(VcsDriverRegistry.VcsDriverRegistry)({    get: () => Effect.succeed(driver as unknown as VcsDriver.VcsDriver["Service"]),    resolve:      input.resolve ??      (() =>        Effect.succeed({          kind: "git",          repository: {            kind: "git",            rootPath: "/repo",            metadataPath: null,            freshness: {              source: "live-local" as const,              observedAt: TEST_EPOCH,              expiresAt: Option.none(),            },          },          driver: driver as unknown as VcsDriver.VcsDriver["Service"],        })),  });   const processLayer = Layer.mock(VcsProcess.VcsProcess)({    run: () => Effect.succeed(processOutput("")),    ...input.process,  });   return SourceControlProviderRegistry.make.pipe(    Effect.provide(      Layer.mergeAll(        registryLayer,        processLayer,        Layer.mock(AzureDevOpsCli.AzureDevOpsCli)({}),        Layer.mock(BitbucketApi.BitbucketApi)({}),        Layer.mock(GitHubCli.GitHubCli)({}),        Layer.mock(GitLabCli.GitLabCli)({}),        ServerConfig.layerTest(process.cwd(), {          prefix: "t3-source-control-registry-test-",        }).pipe(Layer.provide(NodeServices.layer)),      ),    ),  );} it.effect("routes GitHub remotes to the GitHub provider", () =>  Effect.gen(function* () {    const registry = yield* makeRegistry({      remotes: [{ name: "origin", url: "git@github.com:pingdotgg/t3code.git" }],    });     const provider = yield* registry.resolve({ cwd: "/repo" });     assert.strictEqual(provider.kind, "github");  }),); it.effect("routes directly by provider kind for remote-first workflows", () =>  Effect.gen(function* () {    const registry = yield* makeRegistry({      remotes: [],    });     const provider = yield* registry.get("github");     assert.strictEqual(provider.kind, "github");  }),); it.effect("includes the request cwd when an unregistered provider is used", () =>  Effect.gen(function* () {    const registry = yield* makeRegistry({ remotes: [] });    const provider = yield* registry.get("unknown");     const error = yield* provider      .getChangeRequest({ cwd: "/repo", reference: "#42" })      .pipe(Effect.flip);     assert.strictEqual(error.provider, "unknown");    assert.strictEqual(error.operation, "getChangeRequest");    assert.strictEqual(error.cwd, "/repo");    assert.strictEqual(error.reference, "#42");  }),); it.effect("retains VCS detection failures with structured cwd context", () =>  Effect.gen(function* () {    const cause = new VcsRepositoryDetectionError({      operation: "resolve",      cwd: "/repo",      detail: "raw VCS detection failure",      cause: new Error("raw nested failure"),    });    const registry = yield* makeRegistry({      remotes: [],      resolve: () => Effect.fail(cause),    });     const error = yield* registry.resolve({ cwd: "/repo" }).pipe(Effect.flip);     assert.strictEqual(error.provider, "unknown");    assert.strictEqual(error.operation, "detectProvider");    assert.strictEqual(error.cwd, "/repo");    assert.strictEqual(error.detail, "Failed to detect source control provider.");    assert.strictEqual(error.cause, cause);    assert.equal(error.message.includes(cause.message), false);  }),); it.effect("routes GitLab remotes to the GitLab provider", () =>  Effect.gen(function* () {    const registry = yield* makeRegistry({      remotes: [{ name: "origin", url: "git@gitlab.com:group/project.git" }],    });     const provider = yield* registry.resolve({ cwd: "/repo" });     assert.strictEqual(provider.kind, "gitlab");  }),); it.effect("routes authenticated self-hosted GitLab remotes without relying on host naming", () =>  Effect.gen(function* () {    const registry = yield* makeRegistry({      remotes: [{ name: "origin", url: "https://self-hosted.example.test/group/project.git" }],      process: {        run: () =>          Effect.succeed(            processOutput(              `gitlab.com  x gitlab.com: API call failed: 401 Unauthorized  ! No token foundself-hosted.example.test  ✓ Logged in to self-hosted.example.test as gitlab-user  ✓ Token found: ******`,              { exitCode: ChildProcessSpawner.ExitCode(1) },            ),          ),      },    });     const provider = yield* registry.resolve({ cwd: "/repo" });     assert.strictEqual(provider.kind, "gitlab");  }),); it.effect("routes authenticated self-hosted GitLab remotes on non-standard ports", () =>  Effect.gen(function* () {    const registry = yield* makeRegistry({      remotes: [{ name: "origin", url: "https://self-hosted.example.test:8443/group/project.git" }],      process: {        run: () =>          Effect.succeed(            processOutput(              `self-hosted.example.test:8443  ✓ Logged in to self-hosted.example.test:8443 as gitlab-user  ✓ Token found: ******`,            ),          ),      },    });     const provider = yield* registry.resolve({ cwd: "/repo" });     assert.strictEqual(provider.kind, "gitlab");  }),); it.effect("routes Bitbucket remotes to the Bitbucket provider", () =>  Effect.gen(function* () {    const registry = yield* makeRegistry({      remotes: [{ name: "origin", url: "git@bitbucket.org:pingdotgg/t3code.git" }],    });     const provider = yield* registry.resolve({ cwd: "/repo" });     assert.strictEqual(provider.kind, "bitbucket");  }),); it.effect("routes Azure DevOps remotes to the Azure DevOps provider", () =>  Effect.gen(function* () {    const registry = yield* makeRegistry({      remotes: [{ name: "origin", url: "https://dev.azure.com/acme/project/_git/repo" }],    });     const provider = yield* registry.resolve({ cwd: "/repo" });     assert.strictEqual(provider.kind, "azure-devops");  }),); it.effect("falls back to a non-origin remote when origin is not configured", () =>  Effect.gen(function* () {    const registry = yield* makeRegistry({      remotes: [{ name: "upstream", url: "https://dev.azure.com/acme/project/_git/repo" }],    });     const provider = yield* registry.resolve({ cwd: "/repo" });     assert.strictEqual(provider.kind, "azure-devops");  }),);