322 lines · 10.2 KB · TypeScript
RawDownload
import * as NodeServices from "@effect/platform-node/NodeServices";import { assert, it } from "@effect/vitest";import { Effect, FileSystem, Layer } from "effect";import { ChildProcessSpawner } from "effect/unstable/process"; import { GitCommandError, type SourceControlProviderError } from "@t3tools/contracts"; import { ServerConfig } from "../config.ts";import {  GitVcsDriver,  type ExecuteGitResult,  type GitVcsDriverShape,} from "../vcs/GitVcsDriver.ts";import { SourceControlProviderRegistry } from "./SourceControlProviderRegistry.ts";import type { SourceControlProviderShape } from "./SourceControlProvider.ts";import { SourceControlRepositoryService, layer } 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<SourceControlProviderShape> = {},): SourceControlProviderShape {  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(): ExecuteGitResult {  return {    exitCode: ChildProcessSpawner.ExitCode(0),    stdout: "",    stderr: "",    stdoutTruncated: false,    stderrTruncated: false,  };} function makeLayer(input: {  readonly provider?: SourceControlProviderShape;  readonly git?: Partial<GitVcsDriverShape>;}) {  return layer.pipe(    Layer.provide(      Layer.mock(SourceControlProviderRegistry)({        get: () => Effect.succeed(input.provider ?? makeProvider()),      }),    ),    Layer.provide(      Layer.mock(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(), { prefix: "t3-source-control-repos-" })),    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;    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("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;      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("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;    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;    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;    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,              };            }),        },      }),    ),  );});