History

[codex] structure source-control repository failures (#3336)

Julius Marminge committed 4 months ago

Commit a26f0dc1 parent 6ff6c132 files · +98 −45Browse files

Showing the changes to apps/server/src/sourceControl/SourceControlRepositoryService.test.ts (1 of 2 files). Show all

Unified · Split

apps/server/src/sourceControl/SourceControlRepositoryService.test.ts+83−4
@@ -1,11 +1,13 @@
1+import * as NodePath from "@effect/platform-node/NodePath";
12 import * as NodeServices from "@effect/platform-node/NodeServices";
23 import { assert, it } from "@effect/vitest";
34 import * as Effect from "effect/Effect";
45 import * as FileSystem from "effect/FileSystem";
56 import * as Layer from "effect/Layer";
7+import * as PlatformError from "effect/PlatformError";
68 import { ChildProcessSpawner } from "effect/unstable/process";
79
8−import { GitCommandError, type SourceControlProviderError } from "@t3tools/contracts";
10+import { GitCommandError, SourceControlProviderError } from "@t3tools/contracts";
911
1012 import * as ServerConfig from "../config.ts";
1113 import * as GitVcsDriver from "../vcs/GitVcsDriver.ts";
@@ -54,8 +56,9 @@ function processOutput(): GitVcsDriver.ExecuteGitResult { · 42 unmodified lines
5456 function makeLayer(input: {
5557 readonly provider?: SourceControlProvider.SourceControlProvider["Service"];
5658 readonly git?: Partial<GitVcsDriver.GitVcsDriver["Service"]>;
59+ readonly fileSystem?: FileSystem.FileSystem;
5760 }) {
58− return SourceControlRepositoryService.layer.pipe(
61+ const serviceLayer = SourceControlRepositoryService.layer.pipe(
5962 Layer.provide(
6063 Layer.mock(SourceControlProviderRegistry.SourceControlProviderRegistry)({
6164 get: () => Effect.succeed(input.provider ?? makeProvider()),
@@ -75,9 +78,20 @@ function makeLayer(input: { · 13 unmodified lines
7578 ...input.git,
7679 }),
7780 ),
78− Layer.provide(ServerConfig.layerTest(process.cwd(), { prefix: "t3-source-control-repos-" })),
79− Layer.provideMerge(NodeServices.layer),
81+ Layer.provide(
82+ ServerConfig.layerTest(
83+ process.cwd(),
84+ input.fileSystem ? "/tmp/t3-source-control-repos" : { prefix: "t3-source-control-repos-" },
85+ ),
86+ ),
8087 );
88+
89+ return input.fileSystem
90+ ? serviceLayer.pipe(
91+ Layer.provide(Layer.succeed(FileSystem.FileSystem, input.fileSystem)),
92+ Layer.provideMerge(NodePath.layer),
93+ )
94+ : serviceLayer.pipe(Layer.provideMerge(NodeServices.layer));
8195 }
8296
8397 it.effect("looks up repositories through the requested provider without search", () => {
@@ -103,6 +117,39 @@ it.effect("looks up repositories through the requested provider without search", · 19 unmodified lines
103117 }).pipe(Effect.provide(makeLayer({ provider })));
104118 });
105119
120+it.effect("preserves provider failures without deriving the repository message from them", () => {
121+ const providerCause = new SourceControlProviderError({
122+ provider: "github",
123+ operation: "getRepositoryCloneUrls",
124+ cwd: "/workspace",
125+ repository: "octocat/t3code",
126+ detail: "credential token abc123 was rejected",
127+ });
128+ const provider = makeProvider({
129+ getRepositoryCloneUrls: () => Effect.fail(providerCause),
130+ });
131+
132+ return Effect.gen(function* () {
133+ const service = yield* SourceControlRepositoryService.SourceControlRepositoryService;
134+ const error = yield* Effect.flip(
135+ service.lookupRepository({
136+ provider: "github",
137+ repository: "octocat/t3code",
138+ cwd: "/workspace",
139+ }),
140+ );
141+
142+ assert.strictEqual(error.provider, "github");
143+ assert.strictEqual(error.operation, "lookupRepository");
144+ assert.strictEqual(error.detail, "The source control operation could not be completed.");
145+ assert.strictEqual(
146+ error.message,
147+ "Source control repository operation lookupRepository failed for github: The source control operation could not be completed.",
148+ );
149+ assert.strictEqual(error.cause, providerCause);
150+ }).pipe(Effect.provide(makeLayer({ provider })));
151+});
152+
106153 it.effect("clones a looked-up repository into the requested destination", () =>
107154 Effect.gen(function* () {
108155 const fs = yield* FileSystem.FileSystem;
@@ -148,6 +195,38 @@ it.effect("clones a looked-up repository into the requested destination", () => · 39 unmodified lines
148195 }).pipe(Effect.provide(NodeServices.layer)),
149196 );
150197
198+it.effect("preserves destination probe failures instead of treating them as missing paths", () => {
199+ const fileSystemCause = PlatformError.systemError({
200+ _tag: "PermissionDenied",
201+ module: "FileSystem",
202+ method: "exists",
203+ pathOrDescriptor: "/restricted/t3code",
204+ });
205+
206+ return Effect.gen(function* () {
207+ const service = yield* SourceControlRepositoryService.SourceControlRepositoryService;
208+ const error = yield* Effect.flip(
209+ service.cloneRepository({
210+ remoteUrl: CLONE_URLS.sshUrl,
211+ destinationPath: "/restricted/t3code",
212+ }),
213+ );
214+
215+ assert.strictEqual(error.provider, "unknown");
216+ assert.strictEqual(error.operation, "cloneRepository");
217+ assert.strictEqual(error.cause, fileSystemCause);
218+ }).pipe(
219+ Effect.provide(
220+ makeLayer({
221+ fileSystem: FileSystem.makeNoop({
222+ exists: () => Effect.fail(fileSystemCause),
223+ makeDirectory: () => Effect.void,
224+ }),
225+ }),
226+ ),
227+ );
228+});
229+
151230 it.effect("publishes by creating the repository, adding a remote, and pushing upstream", () => {
152231 const createCalls: Array<{ cwd: string; repository: string; visibility: string }> = [];
153232 const remoteCalls: Array<{ cwd: string; preferredName: string; url: string }> = [];