1+ // @effect -diagnostics nodeBuiltinImport:off
12import * as Context from "effect/Context" ;
23import * as Effect from "effect/Effect" ;
34import * as Layer from "effect/Layer" ;
5+ import * as Option from "effect/Option" ;
6+ import * as NodeFS from "node:fs" ;
47
58import {
69 GitManagerError ,
@@ -31,6 +34,15 @@ import {
3134import * as GitManager from "./GitManager.ts" ;
3235import * as GitVcsDriver from "../vcs/GitVcsDriver.ts" ;
3336import * as VcsDriverRegistry from "../vcs/VcsDriverRegistry.ts" ;
37+ import { RollbackSagaRepository } from "../persistence/Services/RollbackSagas.ts" ;
38+
39+ function canonicalWorkspacePath ( cwd : string ) : string {
40+ try {
41+ return NodeFS . realpathSync ( cwd ) ;
42+ } catch {
43+ return cwd ;
44+ }
45+ }
3446
3547export class GitWorkflowService extends Context . Service <
3648 GitWorkflowService ,
@@ -141,6 +153,44 @@ export const make = Effect.gen(function* () {
141153 const registry = yield * VcsDriverRegistry . VcsDriverRegistry ;
142154 const git = yield * GitVcsDriver . GitVcsDriver ;
143155 const gitManager = yield * GitManager . GitManager ;
156+ const rollbackRepository = yield * Effect . serviceOption ( RollbackSagaRepository ) ;
157+
158+ const workspaceIsRollbackFenced = Effect . fn ( "GitWorkflowService.workspaceIsRollbackFenced" ) (
159+ function * ( cwd : string ) {
160+ if ( Option . isNone ( rollbackRepository ) ) return false ;
161+ const canonical = canonicalWorkspacePath ( cwd ) ;
162+ const active = yield * rollbackRepository . value
163+ . listNonterminalForFence ( )
164+ . pipe ( Effect . orElseSucceed ( ( ) => null ) ) ;
165+ if ( active === null ) return true ;
166+ return active . some ( ( record ) => record . state . workspaceCwd === canonical ) ;
167+ } ,
168+ ) ;
169+ const ensureMutationCommand = Effect . fn ( "GitWorkflowService.ensureMutationCommand" ) ( function * (
170+ operation : string ,
171+ cwd : string ,
172+ ) {
173+ if ( yield * workspaceIsRollbackFenced ( cwd ) ) {
174+ return yield * new GitCommandError ( {
175+ operation,
176+ command : "rollback-fence" ,
177+ cwd,
178+ detail : "The workspace is fenced by an active rollback operation." ,
179+ } ) ;
180+ }
181+ } ) ;
182+ const ensureMutationWorkflow = Effect . fn ( "GitWorkflowService.ensureMutationWorkflow" ) ( function * (
183+ operation : string ,
184+ cwd : string ,
185+ ) {
186+ if ( yield * workspaceIsRollbackFenced ( cwd ) ) {
187+ return yield * new GitManagerError ( {
188+ operation,
189+ cwd,
190+ detail : "The workspace is fenced by an active rollback operation." ,
191+ } ) ;
192+ }
193+ } ) ;
144194
145195 const ensureGit = Effect . fn ( "GitWorkflowService.ensureGit" ) ( function * (
146196 operation : string ,
@@ -281,29 +331,33 @@ export const make = Effect.gen(function* () {
281331 invalidateRemoteStatus : gitManager . invalidateRemoteStatus ,
282332 invalidateStatus : gitManager . invalidateStatus ,
283333 pullCurrentBranch : ( cwd ) =>
284- ensureGitCommand ( "GitWorkflowService.pullCurrentBranch" , cwd ) . pipe (
334+ ensureMutationCommand ( "GitWorkflowService.pullCurrentBranch" , cwd ) . pipe (
335+ Effect . andThen ( ensureGitCommand ( "GitWorkflowService.pullCurrentBranch" , cwd ) ) ,
285336 Effect . andThen ( git . pullCurrentBranch ( cwd ) ) ,
286337 ) ,
287338 runStackedAction : ( input , options ) =>
288- ensureGit ( "GitWorkflowService.runStackedAction" , input . cwd ) . pipe (
339+ ensureMutationWorkflow ( "GitWorkflowService.runStackedAction" , input . cwd ) . pipe (
340+ Effect . andThen ( ensureGit ( "GitWorkflowService.runStackedAction" , input . cwd ) ) ,
289341 Effect . andThen ( gitManager . runStackedAction ( input , options ) ) ,
290342 ) ,
291343 resolvePullRequest : routeGitManager (
292344 "GitWorkflowService.resolvePullRequest" ,
293345 gitManager . resolvePullRequest ,
294346 ) ,
295- preparePullRequestThread : routeGitManager (
296- "GitWorkflowService.preparePullRequestThread" ,
297- gitManager . preparePullRequestThread ,
298- ) ,
347+ preparePullRequestThread : ( input ) =>
348+ ensureMutationWorkflow ( "GitWorkflowService.preparePullRequestThread" , input . cwd ) . pipe (
349+ Effect . andThen ( ensureGit ( "GitWorkflowService.preparePullRequestThread" , input . cwd ) ) ,
350+ Effect . andThen ( gitManager . preparePullRequestThread ( input ) ) ,
351+ ) ,
299352 listRefs : ( input ) =>
300353 detectGitRepositoryForCommand ( "GitWorkflowService.listRefs" , input . cwd ) . pipe (
301354 Effect . flatMap ( ( isGitRepository ) =>
302355 isGitRepository ? git . listRefs ( input ) : Effect . succeed ( nonRepositoryListRefs ( ) ) ,
303356 ) ,
304357 ) ,
305358 createWorktree : ( input ) =>
306- ensureGitCommand ( "GitWorkflowService.createWorktree" , input . cwd ) . pipe (
359+ ensureMutationCommand ( "GitWorkflowService.createWorktree" , input . cwd ) . pipe (
360+ Effect . andThen ( ensureGitCommand ( "GitWorkflowService.createWorktree" , input . cwd ) ) ,
307361 Effect . andThen ( git . createWorktree ( input ) ) ,
308362 ) ,
309363 fetchRemote : ( input ) =>
@@ -319,23 +373,27 @@ export const make = Effect.gen(function* () {
319373 Effect . andThen ( git . resolveRemoteTrackingCommit ( input ) ) ,
320374 ) ,
321375 removeWorktree : ( input ) =>
322- ensureGitCommand ( "GitWorkflowService.removeWorktree" , input . cwd ) . pipe (
376+ ensureMutationCommand ( "GitWorkflowService.removeWorktree" , input . cwd ) . pipe (
377+ Effect . andThen ( ensureGitCommand ( "GitWorkflowService.removeWorktree" , input . cwd ) ) ,
323378 Effect . andThen ( git . removeWorktree ( input ) ) ,
324379 ) ,
325380 pruneWorktrees : ( input ) =>
326381 ensureGitCommand ( "GitWorkflowService.pruneWorktrees" , input . cwd ) . pipe (
327382 Effect . andThen ( git . pruneWorktrees ( input ) ) ,
328383 ) ,
329384 createRef : ( input ) =>
330- ensureGitCommand ( "GitWorkflowService.createRef" , input . cwd ) . pipe (
385+ ensureMutationCommand ( "GitWorkflowService.createRef" , input . cwd ) . pipe (
386+ Effect . andThen ( ensureGitCommand ( "GitWorkflowService.createRef" , input . cwd ) ) ,
331387 Effect . andThen ( git . createRef ( input ) ) ,
332388 ) ,
333389 switchRef : ( input ) =>
334- ensureGitCommand ( "GitWorkflowService.switchRef" , input . cwd ) . pipe (
390+ ensureMutationCommand ( "GitWorkflowService.switchRef" , input . cwd ) . pipe (
391+ Effect . andThen ( ensureGitCommand ( "GitWorkflowService.switchRef" , input . cwd ) ) ,
335392 Effect . andThen ( Effect . scoped ( git . switchRef ( input ) ) ) ,
336393 ) ,
337394 renameBranch : ( input ) =>
338- ensureGit ( "GitWorkflowService.renameBranch" , input . cwd ) . pipe (
395+ ensureMutationWorkflow ( "GitWorkflowService.renameBranch" , input . cwd ) . pipe (
396+ Effect . andThen ( ensureGit ( "GitWorkflowService.renameBranch" , input . cwd ) ) ,
339397 Effect . andThen ( git . renameBranch ( input ) ) ,
340398 ) ,
341399 } ) ;
0 commit comments