authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-06-20 20:20:04-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-06-20 20:20:04-07:00
log6155f5cf64e9f26d10f3c912985f8ca09f9c3fef
treedee5559c0b4f63e0a2fd1186cf8dc23cf5528f72
parente3970e755b0da65c3fd83a985cede1840164ae0b
signature Signed by PGP key B5690EEEBB952194

[codex] Preserve VCS project config error causes (#3474)

Co-authored-by: codex <codex@users.noreply.github.com>

2 files changed, 28 insertions(+), 22 deletions(-)

apps/server/src/vcs/VcsProjectConfig.test.ts+20-15
...@@ -96,16 +96,19 @@ describe("VcsProjectConfig", () => {...@@ -96,16 +96,19 @@ describe("VcsProjectConfig", () => {
96 const kind = yield* config.resolveKind({ cwd });96 const kind = yield* config.resolveKind({ cwd });
9797
98 assert.equal(kind, "jj");98 assert.equal(kind, "jj");
99 const [message, context] = messages[0] as [string, Record<string, unknown>];
100 const failedCandidate = path.join(cwd, ".t3code", "vcs.json");99 const failedCandidate = path.join(cwd, ".t3code", "vcs.json");
101 assert.equal(message, "Failed to inspect VCS project config at " + failedCandidate + ".");100 const [error] = messages[0] as ReadonlyArray<unknown>;
102 assert.deepInclude(context, {101 assert.instanceOf(error, VcsProjectConfig.VcsProjectConfigError);
102 assert.equal(
103 error.message,
104 "Failed to inspect VCS project config at " + failedCandidate + ".",
105 );
106 assert.deepInclude(error, {
103 operation: "inspect",107 operation: "inspect",
104 cwd,108 cwd,
105 configPath: failedCandidate,109 configPath: failedCandidate,
106 errorTag: "VcsProjectConfigError",110 _tag: "VcsProjectConfigError",
107 });111 });
108 assert.equal("cause" in context, false);
109 }).pipe(Effect.provide(Logger.layer([logger], { mergeWithExisting: false })));112 }).pipe(Effect.provide(Logger.layer([logger], { mergeWithExisting: false })));
110 });113 });
111 });114 });
...@@ -146,18 +149,19 @@ describe("VcsProjectConfig", () => {...@@ -146,18 +149,19 @@ describe("VcsProjectConfig", () => {
146 const kind = yield* config.resolveKind({ cwd: root });149 const kind = yield* config.resolveKind({ cwd: root });
147150
148 assert.equal(kind, "auto");151 assert.equal(kind, "auto");
149 const [message, context] = messages[0] as [string, Record<string, unknown>];152 const [error] = messages[0] as ReadonlyArray<unknown>;
153 assert.instanceOf(error, VcsProjectConfig.VcsProjectConfigError);
150 assert.equal(154 assert.equal(
151 message,155 error.message,
152 "Failed to decode VCS project config at " + path.join(configDir, "vcs.json") + ".",156 "Failed to decode VCS project config at " + path.join(configDir, "vcs.json") + ".",
153 );157 );
154 assert.deepInclude(context, {158 assert.deepInclude(error.cause, { _tag: "SchemaError" });
159 assert.deepInclude(error, {
155 operation: "decode",160 operation: "decode",
156 cwd: root,161 cwd: root,
157 configPath: path.join(configDir, "vcs.json"),162 configPath: path.join(configDir, "vcs.json"),
158 errorTag: "VcsProjectConfigError",163 _tag: "VcsProjectConfigError",
159 });164 });
160 assert.equal("cause" in context, false);
161 }).pipe(Effect.provide(Logger.layer([logger], { mergeWithExisting: false })));165 }).pipe(Effect.provide(Logger.layer([logger], { mergeWithExisting: false })));
162 });166 });
163 });167 });
...@@ -182,15 +186,16 @@ describe("VcsProjectConfig", () => {...@@ -182,15 +186,16 @@ describe("VcsProjectConfig", () => {
182 const kind = yield* config.resolveKind({ cwd: root });186 const kind = yield* config.resolveKind({ cwd: root });
183187
184 assert.equal(kind, "auto");188 assert.equal(kind, "auto");
185 const [message, context] = messages[0] as [string, Record<string, unknown>];189 const [error] = messages[0] as ReadonlyArray<unknown>;
186 assert.equal(message, "Failed to read VCS project config at " + configPath + ".");190 assert.instanceOf(error, VcsProjectConfig.VcsProjectConfigError);
187 assert.deepInclude(context, {191 assert.equal(error.message, "Failed to read VCS project config at " + configPath + ".");
192 assert.deepInclude(error.cause, { _tag: "PlatformError" });
193 assert.deepInclude(error, {
188 operation: "read",194 operation: "read",
189 cwd: root,195 cwd: root,
190 configPath,196 configPath,
191 errorTag: "VcsProjectConfigError",197 _tag: "VcsProjectConfigError",
192 });198 });
193 assert.equal("cause" in context, false);
194 }).pipe(Effect.provide(Logger.layer([logger], { mergeWithExisting: false })));199 }).pipe(Effect.provide(Logger.layer([logger], { mergeWithExisting: false })));
195 });200 });
196 });201 });
apps/server/src/vcs/VcsProjectConfig.ts+8-7
...@@ -55,13 +55,14 @@ function configuredKind(config: ProjectVcsConfigFile): VcsDriverKindType | "auto...@@ -55,13 +55,14 @@ function configuredKind(config: ProjectVcsConfigFile): VcsDriverKindType | "auto
55}55}
5656
57const logVcsProjectConfigError = (error: VcsProjectConfigError) =>57const logVcsProjectConfigError = (error: VcsProjectConfigError) =>
58 Effect.logWarning(error.message, {58 Effect.logWarning(error).pipe(
59 operation: error.operation,59 Effect.annotateLogs({
60 cwd: error.cwd,60 operation: error.operation,
61 configPath: error.configPath,61 cwd: error.cwd,
62 errorTag: error._tag,62 configPath: error.configPath,
63 stack: error.stack,63 errorTag: error._tag,
64 });64 }),
65 );
6566
66export const make = Effect.gen(function* () {67export const make = Effect.gen(function* () {
67 const fileSystem = yield* FileSystem.FileSystem;68 const fileSystem = yield* FileSystem.FileSystem;