History

Add JJ VCS driver support

- Detect and route jj repositories alongside git - Thread VCS kind through status and UI labels - Add jj driver contract coverage and shared freshness helper

Julius Marminge committed 6 months ago

Commit c31beca1 parent 128b43230 files · +838 −44Browse files

Showing the changes to apps/server/src/git/GitWorkflowService.ts (1 of 30 files). Show all

Unified · Split

apps/server/src/git/GitWorkflowService.ts+67−3
@@ -3,6 +3,7 @@ import { Context, Effect, Layer } from "effect"; · 2 unmodified lines
3import {3import {
4 GitManagerError,4 GitManagerError,
5 GitCommandError,5 GitCommandError,
6 type VcsDriverKind,
6 type VcsSwitchRefInput,7 type VcsSwitchRefInput,
7 type VcsSwitchRefResult,8 type VcsSwitchRefResult,
8 type VcsCreateRefInput,9 type VcsCreateRefInput,
@@ -29,6 +30,7 @@ import { · 20 unmodified lines
29import { GitManager, type GitRunStackedActionOptions } from "./GitManager.ts";30import { GitManager, type GitRunStackedActionOptions } from "./GitManager.ts";
30import { GitVcsDriver } from "../vcs/GitVcsDriver.ts";31import { GitVcsDriver } from "../vcs/GitVcsDriver.ts";
31import { VcsDriverRegistry } from "../vcs/VcsDriverRegistry.ts";32import { VcsDriverRegistry } from "../vcs/VcsDriverRegistry.ts";
33import { mergeGitStatusParts } from "@t3tools/shared/git";
32 34
33export interface GitWorkflowServiceShape {35export interface GitWorkflowServiceShape {
34 readonly status: (36 readonly status: (
@@ -92,6 +94,18 @@ const unsupportedGitCommand = (operation: string, cwd: string, detail: string) = · 57 unmodified lines
92 detail,94 detail,
93 });95 });
94 96
97const emptyWorkingTree = { files: [], insertions: 0, deletions: 0 } as const;
98
99const nonGitLocalStatus = (kind: VcsDriverKind, isRepo: boolean): VcsStatusLocalResult => ({
100 kind,
101 isRepo,
102 hasPrimaryRemote: false,
103 isDefaultRef: false,
104 refName: null,
105 hasWorkingTreeChanges: false,
106 workingTree: emptyWorkingTree,
107});
108
95export const make = Effect.fn("makeGitWorkflowService")(function* () {109export const make = Effect.fn("makeGitWorkflowService")(function* () {
96 const registry = yield* VcsDriverRegistry;110 const registry = yield* VcsDriverRegistry;
97 const git = yield* GitVcsDriver;111 const git = yield* GitVcsDriver;
@@ -153,10 +167,60 @@ export const make = Effect.fn("makeGitWorkflowService")(function* () { · 55 unmodified lines
153 (input: Input) =>167 (input: Input) =>
154 ensureGit(operation, input.cwd).pipe(Effect.andThen(run(input)));168 ensureGit(operation, input.cwd).pipe(Effect.andThen(run(input)));
155 169
170 const localStatus: GitWorkflowServiceShape["localStatus"] = Effect.fn(
171 "GitWorkflowService.localStatus",
172 )(function* (input) {
173 const handle = yield* registry
174 .detect({ cwd: input.cwd })
175 .pipe(
176 Effect.mapError((error) =>
177 unsupportedGitWorkflow(
178 "GitWorkflowService.localStatus",
179 input.cwd,
180 error instanceof Error ? error.message : String(error),
181 ),
182 ),
183 );
184 if (!handle) {
185 return nonGitLocalStatus("unknown", false);
186 }
187 if (handle.kind === "git") {
188 return yield* gitManager.localStatus(input);
189 }
190 return nonGitLocalStatus(handle.kind, true);
191 });
192
193 const remoteStatus: GitWorkflowServiceShape["remoteStatus"] = Effect.fn(
194 "GitWorkflowService.remoteStatus",
195 )(function* (input) {
196 const handle = yield* registry
197 .detect({ cwd: input.cwd })
198 .pipe(
199 Effect.mapError((error) =>
200 unsupportedGitWorkflow(
201 "GitWorkflowService.remoteStatus",
202 input.cwd,
203 error instanceof Error ? error.message : String(error),
204 ),
205 ),
206 );
207 if (handle?.kind === "git") {
208 return yield* gitManager.remoteStatus(input);
209 }
210 return null;
211 });
212
213 const status: GitWorkflowServiceShape["status"] = Effect.fn("GitWorkflowService.status")(
214 function* (input) {
215 const [local, remote] = yield* Effect.all([localStatus(input), remoteStatus(input)]);
216 return mergeGitStatusParts(local, remote);
217 },
218 );
219
156 return GitWorkflowService.of({220 return GitWorkflowService.of({
157 status: routeGitManager("GitWorkflowService.status", gitManager.status),221 status,
158 localStatus: routeGitManager("GitWorkflowService.localStatus", gitManager.localStatus),222 localStatus,
159 remoteStatus: routeGitManager("GitWorkflowService.remoteStatus", gitManager.remoteStatus),223 remoteStatus,
160 invalidateLocalStatus: gitManager.invalidateLocalStatus,224 invalidateLocalStatus: gitManager.invalidateLocalStatus,
161 invalidateRemoteStatus: gitManager.invalidateRemoteStatus,225 invalidateRemoteStatus: gitManager.invalidateRemoteStatus,
162 invalidateStatus: gitManager.invalidateStatus,226 invalidateStatus: gitManager.invalidateStatus,