399 lines · 13.2 KB · TypeScript
RawDownload
import * as NodePath from "@effect/platform-node/NodePath";import * as NodeServices from "@effect/platform-node/NodeServices";import { assert, it } from "@effect/vitest";import * as Effect from "effect/Effect";import * as FileSystem from "effect/FileSystem";import * as Layer from "effect/Layer";import * as PlatformError from "effect/PlatformError";import { ChildProcessSpawner } from "effect/unstable/process"; import { GitCommandError, SourceControlProviderError } from "@t3tools/contracts"; import * as ServerConfig from "../config.ts";import * as GitVcsDriver from "../vcs/GitVcsDriver.ts";import type * as SourceControlProvider from "./SourceControlProvider.ts";import * as SourceControlProviderRegistry from "./SourceControlProviderRegistry.ts";import * as SourceControlRepositoryService from "./SourceControlRepositoryService.ts"; const CLONE_URLS = {  nameWithOwner: "octocat/t3code",  url: "https://github.com/octocat/t3code",  sshUrl: "git@github.com:octocat/t3code.git",}; function makeProvider(  overrides: Partial<SourceControlProvider.SourceControlProvider["Service"]> = {},): SourceControlProvider.SourceControlProvider["Service"] {  const unsupported = (operation: string) =>    Effect.die(`unexpected provider operation ${operation}`) as Effect.Effect<      never,      SourceControlProviderError    >;   return {    kind: "github",    listChangeRequests: () => unsupported("listChangeRequests"),    getChangeRequest: () => unsupported("getChangeRequest"),    createChangeRequest: () => unsupported("createChangeRequest"),    getRepositoryCloneUrls: () => Effect.succeed(CLONE_URLS),    createRepository: () => Effect.succeed(CLONE_URLS),    getDefaultBranch: () => Effect.succeed(null),    checkoutChangeRequest: () => unsupported("checkoutChangeRequest"),    ...overrides,  };} function processOutput(): GitVcsDriver.ExecuteGitResult {  return {    exitCode: ChildProcessSpawner.ExitCode(0),    stdout: "",    stderr: "",    stdoutTruncated: false,    stderrTruncated: false,  };} function makeLayer(input: {  readonly provider?: SourceControlProvider.SourceControlProvider["Service"];  readonly git?: Partial<GitVcsDriver.GitVcsDriver["Service"]>;  readonly fileSystem?: FileSystem.FileSystem;}) {  const serviceLayer = SourceControlRepositoryService.layer.pipe(    Layer.provide(      Layer.mock(SourceControlProviderRegistry.SourceControlProviderRegistry)({        get: () => Effect.succeed(input.provider ?? makeProvider()),      }),    ),    Layer.provide(      Layer.mock(GitVcsDriver.GitVcsDriver)({        execute: () => Effect.succeed(processOutput()),        ensureRemote: () => Effect.succeed("origin"),        pushCurrentBranch: () =>          Effect.succeed({            status: "pushed" as const,            branch: "feature/remote-v1",            upstreamBranch: "origin/feature/remote-v1",            setUpstream: true,          }),        ...input.git,      }),    ),    Layer.provide(      ServerConfig.layerTest(        process.cwd(),        input.fileSystem ? "/tmp/t3-source-control-repos" : { prefix: "t3-source-control-repos-" },      ),    ),  );   return input.fileSystem    ? serviceLayer.pipe(        Layer.provide(Layer.succeed(FileSystem.FileSystem, input.fileSystem)),        Layer.provideMerge(NodePath.layer),      )    : serviceLayer.pipe(Layer.provideMerge(NodeServices.layer));} it.effect("looks up repositories through the requested provider without search", () => {  const calls: Array<{ cwd: string; repository: string }> = [];  const provider = makeProvider({    getRepositoryCloneUrls: (input) =>      Effect.sync(() => {        calls.push({ cwd: input.cwd, repository: input.repository });        return CLONE_URLS;      }),  });   return Effect.gen(function* () {    const service = yield* SourceControlRepositoryService.SourceControlRepositoryService;    const result = yield* service.lookupRepository({      provider: "github",      repository: "octocat/t3code",      cwd: "/workspace",    });     assert.deepStrictEqual(result, { provider: "github", ...CLONE_URLS });    assert.deepStrictEqual(calls, [{ cwd: "/workspace", repository: "octocat/t3code" }]);  }).pipe(Effect.provide(makeLayer({ provider })));}); it.effect("preserves provider failures without deriving the repository message from them", () => {  const providerCause = new SourceControlProviderError({    provider: "github",    operation: "getRepositoryCloneUrls",    cwd: "/workspace",    repository: "octocat/t3code",    detail: "credential token abc123 was rejected",  });  const provider = makeProvider({    getRepositoryCloneUrls: () => Effect.fail(providerCause),  });   return Effect.gen(function* () {    const service = yield* SourceControlRepositoryService.SourceControlRepositoryService;    const error = yield* Effect.flip(      service.lookupRepository({        provider: "github",        repository: "octocat/t3code",        cwd: "/workspace",      }),    );     assert.strictEqual(error.provider, "github");    assert.strictEqual(error.operation, "lookupRepository");    assert.strictEqual(error.detail, "The source control operation could not be completed.");    assert.strictEqual(      error.message,      "Source control repository operation lookupRepository failed for github: The source control operation could not be completed.",    );    assert.strictEqual(error.cause, providerCause);  }).pipe(Effect.provide(makeLayer({ provider })));}); it.effect("clones a looked-up repository into the requested destination", () =>  Effect.gen(function* () {    const fs = yield* FileSystem.FileSystem;    const parent = yield* fs.makeTempDirectoryScoped({      prefix: "t3-source-control-clone-parent-",    });    const destinationPath = `${parent}/t3code`;    const cloneCalls: Array<{ cwd: string; args: ReadonlyArray<string> }> = [];     yield* Effect.gen(function* () {      const service = yield* SourceControlRepositoryService.SourceControlRepositoryService;      const result = yield* service.cloneRepository({        provider: "github",        repository: "octocat/t3code",        destinationPath,        protocol: "https",      });       assert.deepStrictEqual(result, {        cwd: destinationPath,        remoteUrl: CLONE_URLS.url,        repository: { provider: "github", ...CLONE_URLS },      });      assert.deepStrictEqual(cloneCalls, [        {          cwd: parent,          args: ["clone", CLONE_URLS.url, "t3code"],        },      ]);    }).pipe(      Effect.provide(        makeLayer({          git: {            execute: (input) =>              Effect.sync(() => {                cloneCalls.push({ cwd: input.cwd, args: input.args });                return processOutput();              }),          },        }),      ),    );  }).pipe(Effect.provide(NodeServices.layer)),); it.effect("preserves destination probe failures instead of treating them as missing paths", () => {  const fileSystemCause = PlatformError.systemError({    _tag: "PermissionDenied",    module: "FileSystem",    method: "exists",    pathOrDescriptor: "/restricted/t3code",  });   return Effect.gen(function* () {    const service = yield* SourceControlRepositoryService.SourceControlRepositoryService;    const error = yield* Effect.flip(      service.cloneRepository({        remoteUrl: CLONE_URLS.sshUrl,        destinationPath: "/restricted/t3code",      }),    );     assert.strictEqual(error.provider, "unknown");    assert.strictEqual(error.operation, "cloneRepository");    assert.strictEqual(error.cause, fileSystemCause);  }).pipe(    Effect.provide(      makeLayer({        fileSystem: FileSystem.makeNoop({          exists: () => Effect.fail(fileSystemCause),          makeDirectory: () => Effect.void,        }),      }),    ),  );}); it.effect("publishes by creating the repository, adding a remote, and pushing upstream", () => {  const createCalls: Array<{ cwd: string; repository: string; visibility: string }> = [];  const remoteCalls: Array<{ cwd: string; preferredName: string; url: string }> = [];  const pushCalls: Array<{ cwd: string; remoteName: string | null | undefined }> = [];  const provider = makeProvider({    createRepository: (input) =>      Effect.sync(() => {        createCalls.push({          cwd: input.cwd,          repository: input.repository,          visibility: input.visibility,        });        return CLONE_URLS;      }),  });   return Effect.gen(function* () {    const service = yield* SourceControlRepositoryService.SourceControlRepositoryService;    const result = yield* service.publishRepository({      cwd: "/workspace",      provider: "github",      repository: "octocat/t3code",      visibility: "private",      remoteName: "origin",      protocol: "ssh",    });     assert.deepStrictEqual(result, {      repository: { provider: "github", ...CLONE_URLS },      remoteName: "origin",      remoteUrl: CLONE_URLS.sshUrl,      branch: "feature/remote-v1",      upstreamBranch: "origin/feature/remote-v1",      status: "pushed",    });    assert.deepStrictEqual(createCalls, [      { cwd: "/workspace", repository: "octocat/t3code", visibility: "private" },    ]);    assert.deepStrictEqual(remoteCalls, [      { cwd: "/workspace", preferredName: "origin", url: CLONE_URLS.sshUrl },    ]);    assert.deepStrictEqual(pushCalls, [{ cwd: "/workspace", remoteName: "origin" }]);  }).pipe(    Effect.provide(      makeLayer({        provider,        git: {          ensureRemote: (input) =>            Effect.sync(() => {              remoteCalls.push(input);              return "origin";            }),          pushCurrentBranch: (cwd, _fallbackBranch, options) =>            Effect.sync(() => {              pushCalls.push({ cwd, remoteName: options?.remoteName });              return {                status: "pushed" as const,                branch: "feature/remote-v1",                upstreamBranch: "origin/feature/remote-v1",                setUpstream: true,              };            }),        },      }),    ),  );}); it.effect("publishes to the remote name returned by ensureRemote", () => {  const pushCalls: Array<{ cwd: string; remoteName: string | null | undefined }> = [];   return Effect.gen(function* () {    const service = yield* SourceControlRepositoryService.SourceControlRepositoryService;    const result = yield* service.publishRepository({      cwd: "/workspace",      provider: "github",      repository: "octocat/t3code",      visibility: "private",      remoteName: "origin",      protocol: "ssh",    });     assert.equal(result.remoteName, "origin-1");    assert.deepStrictEqual(pushCalls, [{ cwd: "/workspace", remoteName: "origin-1" }]);  }).pipe(    Effect.provide(      makeLayer({        git: {          ensureRemote: () => Effect.succeed("origin-1"),          pushCurrentBranch: (cwd, _fallbackBranch, options) =>            Effect.sync(() => {              pushCalls.push({ cwd, remoteName: options?.remoteName });              return {                status: "pushed" as const,                branch: "feature/remote-v1",                upstreamBranch: `${options?.remoteName ?? "missing"}/feature/remote-v1`,                setUpstream: true,              };            }),        },      }),    ),  );}); it.effect("publish succeeds with status remote_added when the local repo has no commits", () => {  let pushCalls = 0;  return Effect.gen(function* () {    const service = yield* SourceControlRepositoryService.SourceControlRepositoryService;    const result = yield* service.publishRepository({      cwd: "/workspace",      provider: "github",      repository: "octocat/t3code",      visibility: "private",      remoteName: "origin",      protocol: "ssh",    });     assert.deepStrictEqual(result, {      repository: { provider: "github", ...CLONE_URLS },      remoteName: "origin",      remoteUrl: CLONE_URLS.sshUrl,      branch: "main",      status: "remote_added",    });    assert.strictEqual(pushCalls, 0);  }).pipe(    Effect.provide(      makeLayer({        git: {          execute: (input) =>            input.args[0] === "rev-parse"              ? Effect.fail(                  new GitCommandError({                    operation: input.operation,                    command: "git rev-parse --verify HEAD",                    cwd: input.cwd,                    detail: "fatal: Needed a single revision",                  }),                )              : Effect.succeed(processOutput()),          statusDetails: () =>            Effect.succeed({              isRepo: true,              hasOriginRemote: true,              isDefaultBranch: true,              branch: "main",              upstreamRef: null,              hasWorkingTreeChanges: false,              workingTree: { files: [], insertions: 0, deletions: 0 },              hasUpstream: false,              aheadCount: 0,              behindCount: 0,              aheadOfDefaultCount: 0,            }),          pushCurrentBranch: () =>            Effect.sync(() => {              pushCalls += 1;              return {                status: "pushed" as const,                branch: "main",                upstreamBranch: "origin/main",                setUpstream: true,              };            }),        },      }),    ),  );});