1import { assert, it } from "@effect/vitest";
2import * as DateTime from "effect/DateTime";
3import * as Effect from "effect/Effect";
4import * as Layer from "effect/Layer";
5import * as Option from "effect/Option";
6import { ChildProcessSpawner } from "effect/process";
7
8import * as VcsDriver from "./VcsDriver.ts";
9import * as VcsDriverRegistry from "./VcsDriverRegistry.ts";
10import * as VcsProvisioningService from "./VcsProvisioningService.ts";
11
12const TEST_EPOCH = DateTime.makeUnsafe("1970-01-01T00:00:00.000Z");
13
14function makeDriver(calls: string[]): VcsDriver.VcsDriver["Service"] {
15 return {
16 capabilities: {
17 kind: "git",
18 supportsWorktrees: true,
19 supportsBookmarks: false,
20 supportsAtomicSnapshot: false,
21 supportsPushDefaultRemote: true,
22 ignoreClassifier: "native",
23 },
24 execute: () =>
25 Effect.succeed({
26 exitCode: ChildProcessSpawner.ExitCode(0),
27 stdout: "",
28 stderr: "",
29 stdoutTruncated: false,
30 stderrTruncated: false,
31 }),
32 detectRepository: () => Effect.succeed(null),
33 isInsideWorkTree: () => Effect.succeed(false),
34 listWorkspaceFiles: () =>
35 Effect.succeed({
36 paths: [],
37 truncated: false,
38 freshness: {
39 source: "live-local",
40 observedAt: TEST_EPOCH,
41 expiresAt: Option.none(),
42 },
43 }),
44 listRemotes: () =>
45 Effect.succeed({
46 remotes: [],
47 freshness: {
48 source: "live-local",
49 observedAt: TEST_EPOCH,
50 expiresAt: Option.none(),
51 },
52 }),
53 filterIgnoredPaths: (_cwd, relativePaths) => Effect.succeed(relativePaths),
54 initRepository: (input) =>
55 Effect.sync(() => {
56 calls.push(`${input.kind ?? "default"}:${input.cwd}`);
57 }),
58 };
59}
60
61it.effect("routes repository initialization through an explicit VCS driver kind", () => {
62 const calls: string[] = [];
63 const driver = makeDriver(calls);
64 const layerTest = VcsProvisioningService.layer.pipe(
65 Layer.provide(
66 Layer.mock(VcsDriverRegistry.VcsDriverRegistry)({
67 get: (kind) => (kind === "git" ? Effect.succeed(driver) : Effect.die("unexpected kind")),
68 }),
69 ),
70 );
71
72 return Effect.gen(function* () {
73 const provisioning = yield* VcsProvisioningService.VcsProvisioningService;
74 yield* provisioning.initRepository({ cwd: "/repo", kind: "git" });
75
76 assert.deepStrictEqual(calls, ["git:/repo"]);
77 }).pipe(Effect.provide(layerTest));
78});
79
80it.effect("defaults repository initialization to Git until callers choose a VCS kind", () => {
81 const calls: string[] = [];
82 const driver = makeDriver(calls);
83 const layerTest = VcsProvisioningService.layer.pipe(
84 Layer.provide(
85 Layer.mock(VcsDriverRegistry.VcsDriverRegistry)({
86 get: (kind) => (kind === "git" ? Effect.succeed(driver) : Effect.die("unexpected kind")),
87 }),
88 ),
89 );
90
91 return Effect.gen(function* () {
92 const provisioning = yield* VcsProvisioningService.VcsProvisioningService;
93 yield* provisioning.initRepository({ cwd: "/repo" });
94
95 assert.deepStrictEqual(calls, ["default:/repo"]);
96 }).pipe(Effect.provide(layerTest));
97});