Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions apps/server/integration/OrchestrationEngineHarness.integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import { CheckpointStore } from "../src/checkpointing/Services/CheckpointStore.t
import { GitCoreLive } from "../src/git/Layers/GitCore.ts";
import { GitCore, type GitCoreShape } from "../src/git/Services/GitCore.ts";
import { TextGeneration, type TextGenerationShape } from "../src/git/Services/TextGeneration.ts";
import { VcsCore } from "../src/vcs/Services/VcsCore.ts";
import { VcsCoreFromGitLive } from "../src/vcs/Layers/VcsCore.ts";
import { OrchestrationCommandReceiptRepositoryLive } from "../src/persistence/Layers/OrchestrationCommandReceipts.ts";
import { OrchestrationEventStoreLive } from "../src/persistence/Layers/OrchestrationEventStore.ts";
import { ProjectionCheckpointRepositoryLive } from "../src/persistence/Layers/ProjectionCheckpoints.ts";
Expand Down Expand Up @@ -288,7 +290,9 @@ export const makeOrchestrationIntegrationHarness = (
Layer.provide(AnalyticsService.layerTest),
);

const checkpointStoreLayer = CheckpointStoreLive.pipe(Layer.provide(GitCoreLive));
const checkpointStoreLayer = CheckpointStoreLive.pipe(
Layer.provide(VcsCoreFromGitLive.pipe(Layer.provide(GitCoreLive))),
);
const projectionSnapshotQueryLayer = OrchestrationProjectionSnapshotQueryLive;
const runtimeServicesLayer = Layer.mergeAll(
projectionSnapshotQueryLayer,
Expand All @@ -304,17 +308,20 @@ export const makeOrchestrationIntegrationHarness = (
Layer.provideMerge(runtimeServicesLayer),
Layer.provideMerge(serverSettingsLayer),
);
const gitCoreLayer = Layer.succeed(GitCore, {
const branchRenameLayerValue = {
renameBranch: (input: Parameters<GitCoreShape["renameBranch"]>[0]) =>
Effect.succeed({ branch: input.newBranch }),
} as unknown as GitCoreShape);
} as unknown as GitCoreShape;
const gitCoreLayer = Layer.succeed(GitCore, branchRenameLayerValue);
const vcsCoreLayer = Layer.succeed(VcsCore, branchRenameLayerValue);
const textGenerationLayer = Layer.succeed(TextGeneration, {
generateBranchName: () => Effect.succeed({ branch: "update" }),
generateThreadTitle: () => Effect.succeed({ title: "New thread" }),
} as unknown as TextGenerationShape);
const providerCommandReactorLayer = ProviderCommandReactorLive.pipe(
Layer.provideMerge(runtimeServicesLayer),
Layer.provideMerge(gitCoreLayer),
Layer.provideMerge(vcsCoreLayer),
Layer.provideMerge(textGenerationLayer),
Layer.provideMerge(serverSettingsLayer),
);
Expand All @@ -323,7 +330,7 @@ export const makeOrchestrationIntegrationHarness = (
Layer.provideMerge(
WorkspaceEntriesLive.pipe(
Layer.provide(WorkspacePathsLive),
Layer.provideMerge(gitCoreLayer),
Layer.provideMerge(vcsCoreLayer),
Layer.provide(NodeServices.layer),
),
),
Expand Down
107 changes: 98 additions & 9 deletions apps/server/src/checkpointing/Layers/CheckpointStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import { GitCore } from "../../git/Services/GitCore.ts";
import { GitCommandError } from "@t3tools/contracts";
import { ServerConfig } from "../../config.ts";
import { ThreadId } from "@t3tools/contracts";
import { JjCoreLive } from "../../jj/Layers/JjCore.ts";
import { initJjRepo } from "../../jj/Layers/JjTestUtils.ts";
import { VcsCoreLive } from "../../vcs/Layers/VcsCore.ts";

const ServerConfigLayer = ServerConfig.layerTest(process.cwd(), {
prefix: "t3-checkpoint-store-test-",
Expand All @@ -21,11 +24,26 @@ const GitCoreTestLayer = GitCoreLive.pipe(
Layer.provide(ServerConfigLayer),
Layer.provide(NodeServices.layer),
);
const JjCoreTestLayer = JjCoreLive.pipe(
Layer.provide(ServerConfigLayer),
Layer.provideMerge(GitCoreTestLayer),
Layer.provideMerge(NodeServices.layer),
);
const VcsCoreTestLayer = VcsCoreLive.pipe(
Layer.provideMerge(GitCoreTestLayer),
Layer.provideMerge(JjCoreTestLayer),
);
const CheckpointStoreTestLayer = CheckpointStoreLive.pipe(
Layer.provide(GitCoreTestLayer),
Layer.provideMerge(VcsCoreTestLayer),
Layer.provide(NodeServices.layer),
);
const TestLayer = Layer.mergeAll(NodeServices.layer, GitCoreTestLayer, CheckpointStoreTestLayer);
const TestLayer = Layer.mergeAll(
NodeServices.layer,
GitCoreTestLayer,
JjCoreTestLayer,
VcsCoreTestLayer,
CheckpointStoreTestLayer,
);

function makeTmpDir(
prefix = "checkpoint-store-test-",
Expand All @@ -46,6 +64,15 @@ function writeTextFile(
});
}

function fsReadText(
filePath: string,
): Effect.Effect<string, PlatformError.PlatformError, FileSystem.FileSystem> {
return Effect.gen(function* () {
const fileSystem = yield* FileSystem.FileSystem;
return yield* fileSystem.readFileString(filePath);
});
}

function git(
cwd: string,
args: ReadonlyArray<string>,
Expand Down Expand Up @@ -88,20 +115,54 @@ function buildLargeText(lineCount = 5_000): string {

it.layer(TestLayer)("CheckpointStoreLive", (it) => {
describe("diffCheckpoints", () => {
it.effect("returns full oversized checkpoint diffs without truncation", () =>
it.effect(
"returns full oversized checkpoint diffs without truncation for git repositories",
() =>
Effect.gen(function* () {
const tmp = yield* makeTmpDir();
yield* initRepoWithCommit(tmp);
const checkpointStore = yield* CheckpointStore;
const threadId = ThreadId.makeUnsafe("thread-checkpoint-store");
const fromCheckpointRef = checkpointRefForThreadTurn(threadId, 0);
const toCheckpointRef = checkpointRefForThreadTurn(threadId, 1);

yield* checkpointStore.captureCheckpoint({
cwd: tmp,
checkpointRef: fromCheckpointRef,
});
yield* writeTextFile(path.join(tmp, "README.md"), buildLargeText());
yield* checkpointStore.captureCheckpoint({
cwd: tmp,
checkpointRef: toCheckpointRef,
});

const diff = yield* checkpointStore.diffCheckpoints({
cwd: tmp,
fromCheckpointRef,
toCheckpointRef,
});

expect(diff).toContain("diff --git");
expect(diff).not.toContain("[truncated]");
expect(diff).toContain("+line 04999");
}),
);

it.effect("captures JJ checkpoints as native revisions instead of hidden git refs", () =>
Effect.gen(function* () {
const tmp = yield* makeTmpDir();
yield* initRepoWithCommit(tmp);
const tmp = yield* makeTmpDir("checkpoint-store-jj-test-");
yield* initJjRepo(tmp);
const checkpointStore = yield* CheckpointStore;
const threadId = ThreadId.makeUnsafe("thread-checkpoint-store");
const threadId = ThreadId.makeUnsafe("thread-checkpoint-store-jj");
const fromCheckpointRef = checkpointRefForThreadTurn(threadId, 0);
const toCheckpointRef = checkpointRefForThreadTurn(threadId, 1);
const fileSystem = yield* FileSystem.FileSystem;

yield* checkpointStore.captureCheckpoint({
cwd: tmp,
checkpointRef: fromCheckpointRef,
});
yield* writeTextFile(path.join(tmp, "README.md"), buildLargeText());
yield* writeTextFile(path.join(tmp, "notes.txt"), "native jj checkpoint\n");
yield* checkpointStore.captureCheckpoint({
cwd: tmp,
checkpointRef: toCheckpointRef,
Expand All @@ -114,8 +175,36 @@ it.layer(TestLayer)("CheckpointStoreLive", (it) => {
});

expect(diff).toContain("diff --git");
expect(diff).not.toContain("[truncated]");
expect(diff).toContain("+line 04999");
expect(diff).toContain("+++ b/notes.txt");

const gitCore = yield* GitCore;
const gitRefResult = yield* gitCore.execute({
operation: "CheckpointStore.test.git.verifyMissingRef",
cwd: tmp,
args: ["rev-parse", "--verify", "--quiet", `${toCheckpointRef}^{commit}`],
allowNonZeroExit: true,
timeoutMs: 10_000,
});
expect(gitRefResult.code).not.toBe(0);

yield* fileSystem.remove(path.join(tmp, "notes.txt"));
const restored = yield* checkpointStore.restoreCheckpoint({
cwd: tmp,
checkpointRef: toCheckpointRef,
});
expect(restored).toBe(true);
expect(yield* fsReadText(path.join(tmp, "notes.txt"))).toBe("native jj checkpoint\n");

const restoredToInitial = yield* checkpointStore.restoreCheckpoint({
cwd: tmp,
checkpointRef: fromCheckpointRef,
});
expect(restoredToInitial).toBe(true);
const notesExists = yield* fileSystem.stat(path.join(tmp, "notes.txt")).pipe(
Effect.map(() => true),
Effect.catch(() => Effect.succeed(false)),
);
expect(notesExists).toBe(false);
}),
);
});
Expand Down
Loading
Loading