History

Use structural Git status semantics

Julius Marminge committed 4 months ago

Commit c4945aa1 parent cebbe6f2 files · +34 −31Browse files

Unified · Split

2 files
  1. apps/server/src/git/GitManager.test.ts +32 −5
  2. apps/server/src/git/GitManager.ts +2 −26
apps/server/src/git/GitManager.test.ts+32−5
@@ -638,6 +638,7 @@ function makeManager(input?: { · 637 unmodified lines
638638 ghScenario?: FakeGhScenario;
639639 textGeneration?: Partial<FakeGitTextGeneration>;
640640 setupScriptRunner?: ProjectSetupScriptRunner.ProjectSetupScriptRunner["Service"];
641+ vcsDriverLayer?: Layer.Layer<GitVcsDriver.GitVcsDriver>;
641642 }) {
642643 const { service: gitHubCli, ghCalls } = createGitHubCliWithFakeGh(input?.ghScenario);
643644 const textGeneration = createTextGeneration(input?.textGeneration);
@@ -647,11 +648,13 @@ function makeManager(input?: { · 3 unmodified lines
647648
648649 const serverSettingsLayer = ServerSettings.ServerSettingsService.layerTest();
649650
650− const vcsDriverLayer = GitVcsDriver.layer.pipe(
651− Layer.provideMerge(VcsProcess.layer),
652− Layer.provideMerge(NodeServices.layer),
653− Layer.provideMerge(serverConfigLayer),
654− );
651+ const vcsDriverLayer =
652+ input?.vcsDriverLayer ??
653+ GitVcsDriver.layer.pipe(
654+ Layer.provideMerge(VcsProcess.layer),
655+ Layer.provideMerge(NodeServices.layer),
656+ Layer.provideMerge(serverConfigLayer),
657+ );
655658 const sourceControlRegistryLayer = Layer.effect(
656659 SourceControlProviderRegistry.SourceControlProviderRegistry,
657660 GitHubSourceControlProvider.make.pipe(
@@ -934,6 +937,30 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { · 276 unmodified lines
934937 }),
935938 );
936939
940+ it.effect("does not classify Git command failures from message text", () =>
941+ Effect.gen(function* () {
942+ const cwd = "/workspace";
943+ const cause = new Error("spawn failed");
944+ const commandError = new GitCommandError({
945+ operation: "GitVcsDriver.statusDetails.status",
946+ command: "git",
947+ cwd,
948+ detail: "not a git repository",
949+ cause,
950+ });
951+ const { manager } = yield* makeManager({
952+ vcsDriverLayer: Layer.mock(GitVcsDriver.GitVcsDriver)({
953+ statusDetailsLocal: () => Effect.fail(commandError),
954+ }),
955+ });
956+
957+ const error = yield* manager.localStatus({ cwd }).pipe(Effect.flip);
958+
959+ expect(error).toBe(commandError);
960+ expect(error.cause).toBe(cause);
961+ }),
962+ );
963+
937964 it.effect("status briefly caches repeated lookups for the same cwd", () =>
938965 Effect.gen(function* () {
939966 const repoDir = yield* makeTempDir("t3code-git-manager-");
apps/server/src/git/GitManager.ts+2−26
@@ -15,7 +15,6 @@ import * as Ref from "effect/Ref"; · 14 unmodified lines
1515 import {
1616 GitActionProgressEvent,
1717 GitActionProgressPhase,
18− GitCommandError,
1918 GitPreparePullRequestThreadInput,
2019 GitPreparePullRequestThreadResult,
2120 GitPullRequestRefInput,
@@ -99,10 +98,6 @@ type StripProgressContext<T> = T extends any ? Omit<T, "actionId" | "cwd" | "act · 77 unmodified lines
9998 type GitActionProgressPayload = StripProgressContext<GitActionProgressEvent>;
10099 type GitActionProgressEmitter = (event: GitActionProgressPayload) => Effect.Effect<void, never>;
101100
102−function isNotGitRepositoryError(error: GitCommandError): boolean {
103− return error.message.toLowerCase().includes("not a git repository");
104−}
105−
106101 interface OpenPrInfo {
107102 number: number;
108103 title: string;
@@ -727,25 +722,8 @@ export const make = Effect.gen(function* () { · 618 unmodified lines
727722 const canonicalizeExistingPath = (value: string) =>
728723 fileSystem.realPath(value).pipe(Effect.orElseSucceed(() => value));
729724 const normalizeStatusCacheKey = canonicalizeExistingPath;
730− const nonRepositoryStatusDetails = {
731− isRepo: false,
732− hasOriginRemote: false,
733− isDefaultBranch: false,
734− branch: null,
735− upstreamRef: null,
736− hasWorkingTreeChanges: false,
737− workingTree: { files: [], insertions: 0, deletions: 0 },
738− hasUpstream: false,
739− aheadCount: 0,
740− behindCount: 0,
741− aheadOfDefaultCount: 0,
742− } satisfies GitVcsDriver.GitStatusDetails;
743725 const readLocalStatus = Effect.fn("readLocalStatus")(function* (cwd: string) {
744− const details = yield* gitCore
745− .statusDetailsLocal(cwd)
746− .pipe(
747− Effect.catchIf(isNotGitRepositoryError, () => Effect.succeed(nonRepositoryStatusDetails)),
748− );
726+ const details = yield* gitCore.statusDetailsLocal(cwd);
749727 const hostingProvider = details.isRepo
750728 ? yield* resolveHostingProvider(cwd, details.branch)
751729 : null;
@@ -772,9 +750,7 @@ export const make = Effect.gen(function* () { · 20 unmodified lines
772750 cwd: string,
773751 options?: GitVcsDriver.GitRemoteStatusOptions,
774752 ) {
775− const details = yield* gitCore
776− .statusDetailsRemote(cwd, options)
777− .pipe(Effect.catchIf(isNotGitRepositoryError, () => Effect.succeed(null)));
753+ const details = yield* gitCore.statusDetailsRemote(cwd, options);
778754 if (details === null || !details.isRepo) {
779755 return null;
780756 }