From 6f5d96b5233f4123e8fc79c7240936e8e2944514 Mon Sep 17 00:00:00 2001 From: ferhtgoldaraz <2060086+ferhtgoldaraz@users.noreply.github.com> Date: Sun, 8 Nov 2026 11:41:55 +0100 Subject: [PATCH] fix(server): repositories without a remote no longer record failed spans A git repository with no remote is a valid local-only setup, but resolvePrimaryRemoteName failed inside its own traced span when it found none. Status and base-branch callers recover from that and fall back to local branches, so every status refresh still recorded a failed resolvePrimaryRemoteName span, and Settings > Diagnostics filled with failures that were all expected. The lookup span now succeeds with no remote as its answer. Callers that need a remote, such as fetching a pull request head, still fail with the same "No git remote is configured" error in their own span. Co-Authored-By: Claude Opus 5.5 --- apps/server/src/vcs/GitVcsDriverCore.test.ts | 39 ++++++++++++++++++++ apps/server/src/vcs/GitVcsDriverCore.ts | 35 +++++++++++------- 2 files changed, 60 insertions(+), 14 deletions(-) diff --git a/apps/server/src/vcs/GitVcsDriverCore.test.ts b/apps/server/src/vcs/GitVcsDriverCore.test.ts index 728c20c034ee2..6cb55413c31d8 100644 --- a/apps/server/src/vcs/GitVcsDriverCore.test.ts +++ b/apps/server/src/vcs/GitVcsDriverCore.test.ts @@ -23,6 +23,7 @@ import * as Schema from "effect/Schema"; import * as Sink from "effect/Sink"; import * as Stream from "effect/Stream"; import * as TestClock from "effect/testing/TestClock"; +import * as Tracer from "effect/Tracer"; import { ChildProcess, ChildProcessSpawner, CommandLine } from "effect/process"; import { @@ -4001,6 +4002,44 @@ it.layer(layerTest)("GitVcsDriver core integration", (it) => { }), ); + it.effect("records no failed span reading status of a repository without a remote", () => + Effect.gen(function* () { + const cwd = yield* makeTmpDir(); + yield* initRepoWithCommit(cwd); + yield* git(cwd, ["checkout", "-b", "feature"]); + const driver = yield* GitVcsDriver.GitVcsDriver; + const spans: Array = []; + const tracer = Tracer.make({ + span: (options) => { + const span = new Tracer.NativeSpan(options); + spans.push(span); + return span; + }, + }); + const traced = (effect: Effect.Effect) => + Effect.gen(function* () { + spans.length = 0; + const exit = yield* effect.pipe(Effect.withTracer(tracer), Effect.exit); + const failedSpans = spans.flatMap((span) => + span.status._tag === "Ended" && Exit.isFailure(span.status.exit) ? [span.name] : [], + ); + return { exit, failedSpans }; + }); + + const status = yield* traced(driver.statusDetailsRemote(cwd)); + assert.isTrue(Exit.isSuccess(status.exit)); + assert.deepStrictEqual(status.failedSpans, []); + + // A caller that needs a remote still fails, in its own span. + const fetch = yield* traced(driver.fetchRefCommit({ cwd, ref: "refs/pull/1/head" })); + assert.include( + Exit.isFailure(fetch.exit) ? Cause.pretty(fetch.exit.cause) : "", + "No git remote is configured for this repository.", + ); + assert.deepStrictEqual(fetch.failedSpans, ["GitVcsDriver.fetchRefCommit"]); + }), + ); + it.effect("can read cached remote divergence without fetching upstream", () => Effect.gen(function* () { const cwd = yield* makeTmpDir(); diff --git a/apps/server/src/vcs/GitVcsDriverCore.ts b/apps/server/src/vcs/GitVcsDriverCore.ts index 85a7e524b1a63..14baafe3ed951 100644 --- a/apps/server/src/vcs/GitVcsDriverCore.ts +++ b/apps/server/src/vcs/GitVcsDriverCore.ts @@ -1738,25 +1738,32 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* return parsedRemoteRef?.branchName ?? branchName; }); - const resolvePrimaryRemoteName = Effect.fn("resolvePrimaryRemoteName")(function* (cwd: string) { + // Local-only repositories are normal and status polls them, so the span succeeds with null. + // Callers that need a remote fail in their own span. + const findPrimaryRemoteName = Effect.fn("resolvePrimaryRemoteName")(function* (cwd: string) { if (yield* originRemoteExists(cwd)) { return "origin"; } - const remotes = yield* listRemoteNames(cwd); - const [firstRemote] = remotes; - if (firstRemote) { - return firstRemote; - } - return yield* new GitCommandError({ - ...gitCommandContext({ - operation: "GitVcsDriver.resolvePrimaryRemoteName", - cwd, - args: ["remote"], - }), - detail: "No git remote is configured for this repository.", - }); + const [firstRemote] = yield* listRemoteNames(cwd); + return firstRemote ?? null; }); + const resolvePrimaryRemoteName = (cwd: string) => + findPrimaryRemoteName(cwd).pipe( + Effect.filterOrFail( + (remoteName): remoteName is string => remoteName !== null, + () => + new GitCommandError({ + ...gitCommandContext({ + operation: "GitVcsDriver.resolvePrimaryRemoteName", + cwd, + args: ["remote"], + }), + detail: "No git remote is configured for this repository.", + }), + ), + ); + const resolvePushRemoteName = Effect.fn("resolvePushRemoteName")(function* ( cwd: string, refName: string,