Skip to content

Commit ebb0db0

Browse files
Replace shell commands with native fs in repo service
1 parent f03670d commit ebb0db0

2 files changed

Lines changed: 30 additions & 27 deletions

File tree

backend/src/services/repo.ts

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { existsSync, rmSync } from 'node:fs'
12
import { executeCommand } from '../utils/process'
23
import { ensureDirectoryExists } from './file-operations'
34
import * as db from '../db/queries'
@@ -304,9 +305,9 @@ export async function cloneRepo(
304305
}
305306

306307
await ensureDirectoryExists(getReposPath())
307-
const baseRepoExists = await executeCommand(['bash', '-c', `test -d ${baseRepoDirName} && echo exists || echo missing`], path.resolve(getReposPath()))
308+
const baseRepoExists = existsSync(path.join(path.resolve(getReposPath()), baseRepoDirName))
308309

309-
const shouldUseWorktree = useWorktree && branch && baseRepoExists.trim() === 'exists'
310+
const shouldUseWorktree = useWorktree && branch && baseRepoExists
310311

311312
const createRepoInput: CreateRepoInput = {
312313
repoUrl: normalizedRepoUrl,
@@ -340,26 +341,24 @@ export async function cloneRepo(
340341

341342
await createWorktreeSafely(baseRepoPath, worktreePath, branch, env)
342343

343-
const worktreeVerified = await executeCommand(['test', '-d', worktreePath])
344-
.then(() => true)
345-
.catch(() => false)
344+
const worktreeVerified = existsSync(worktreePath)
346345

347346
if (!worktreeVerified) {
348347
throw new Error(`Worktree directory was not created at: ${worktreePath}`)
349348
}
350349

351350
logger.info(`Worktree verified at: ${worktreePath}`)
352351

353-
} else if (branch && baseRepoExists.trim() === 'exists' && useWorktree) {
352+
} else if (branch && baseRepoExists && useWorktree) {
354353
logger.info(`Base repo exists but worktree creation failed, cloning branch separately`)
355354

356-
const worktreeExists = await executeCommand(['bash', '-c', `test -d ${worktreeDirName} && echo exists || echo missing`], path.resolve(getReposPath()))
357-
if (worktreeExists.trim() === 'exists') {
355+
const worktreeExists = existsSync(path.join(path.resolve(getReposPath()), worktreeDirName))
356+
if (worktreeExists) {
358357
logger.info(`Workspace directory exists, removing it: ${worktreeDirName}`)
359358
try {
360-
await executeCommand(['rm', '-rf', worktreeDirName], getReposPath())
361-
const verifyRemoved = await executeCommand(['bash', '-c', `test -d ${worktreeDirName} && echo exists || echo removed`], getReposPath())
362-
if (verifyRemoved.trim() === 'exists') {
359+
rmSync(path.join(path.resolve(getReposPath()), worktreeDirName), { recursive: true, force: true })
360+
const verifyRemoved = !existsSync(path.join(path.resolve(getReposPath()), worktreeDirName))
361+
if (!verifyRemoved) {
363362
throw new Error(`Failed to remove existing directory: ${worktreeDirName}`)
364363
}
365364
} catch (cleanupError: unknown) {
@@ -402,7 +401,7 @@ export async function cloneRepo(
402401
}
403402
}
404403
} else {
405-
if (baseRepoExists.trim() === 'exists') {
404+
if (baseRepoExists) {
406405
logger.info(`Repository directory already exists, verifying it's a valid git repo: ${baseRepoDirName}`)
407406
const isValidRepo = await executeCommand(['git', '-C', path.resolve(getReposPath(), baseRepoDirName), 'rev-parse', '--git-dir'], path.resolve(getReposPath())).then(() => 'valid').catch(() => 'invalid')
408407

@@ -446,26 +445,26 @@ export async function cloneRepo(
446445
return { ...repo, cloneStatus: 'ready' }
447446
} else {
448447
logger.warn(`Invalid repository directory found, removing and recloning: ${baseRepoDirName}`)
449-
await executeCommand(['rm', '-rf', baseRepoDirName], getReposPath())
448+
rmSync(path.join(getReposPath(), baseRepoDirName), { recursive: true, force: true })
450449
}
451450
}
452451

453452
logger.info(`Cloning repo: ${normalizedRepoUrl}${branch ? ` to branch ${branch}` : ''}`)
454453

455-
const worktreeExists = await executeCommand(['bash', '-c', `test -d ${worktreeDirName} && echo exists || echo missing`], getReposPath())
456-
if (worktreeExists.trim() === 'exists') {
454+
const worktreeExists = existsSync(path.join(getReposPath(), worktreeDirName))
455+
if (worktreeExists) {
457456
logger.info(`Workspace directory exists, removing it: ${worktreeDirName}`)
458457
try {
459-
await executeCommand(['rm', '-rf', worktreeDirName], getReposPath())
460-
const verifyRemoved = await executeCommand(['bash', '-c', `test -d ${worktreeDirName} && echo exists || echo removed`], getReposPath())
461-
if (verifyRemoved.trim() === 'exists') {
462-
throw new Error(`Failed to remove existing directory: ${worktreeDirName}`)
458+
rmSync(path.join(getReposPath(), worktreeDirName), { recursive: true, force: true })
459+
const verifyRemoved = !existsSync(path.join(getReposPath(), worktreeDirName))
460+
if (!verifyRemoved) {
461+
throw new Error(`Failed to remove existing directory: ${worktreeDirName}`)
462+
}
463+
} catch (cleanupError: unknown) {
464+
logger.error(`Failed to clean up existing directory: ${worktreeDirName}`, cleanupError)
465+
throw new Error(`Cannot clone: directory ${worktreeDirName} exists and could not be removed`)
463466
}
464-
} catch (cleanupError: unknown) {
465-
logger.error(`Failed to clean up existing directory: ${worktreeDirName}`, cleanupError)
466-
throw new Error(`Cannot clone: directory ${worktreeDirName} exists and could not be removed`)
467467
}
468-
}
469468

470469
try {
471470
const cloneCmd = branch

backend/test/services/repo-auth-env.test.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { GitAuthService } from '../../src/services/git-auth'
44

55
const executeCommand = vi.fn()
66
const ensureDirectoryExists = vi.fn()
7+
const existsSync = vi.fn()
78

89
const getRepoByUrlAndBranch = vi.fn()
910
const createRepo = vi.fn()
@@ -18,6 +19,11 @@ vi.mock('../../src/services/file-operations', () => ({
1819
ensureDirectoryExists,
1920
}))
2021

22+
vi.mock('node:fs', () => ({
23+
existsSync,
24+
rmSync: vi.fn(),
25+
}))
26+
2127
vi.mock('../../src/db/queries', () => ({
2228
getRepoByUrlAndBranch,
2329
createRepo,
@@ -76,15 +82,13 @@ describe('repoService.cloneRepo auth env', () => {
7682
clonedAt: Date.now(),
7783
})
7884

85+
existsSync.mockReturnValue(false)
7986
executeCommand
80-
.mockResolvedValueOnce('missing')
81-
.mockResolvedValueOnce('missing')
8287
.mockResolvedValueOnce('')
8388

8489
await cloneRepo(database, mockGitAuthService, repoUrl)
8590

86-
expect(executeCommand).toHaveBeenNthCalledWith(
87-
3,
91+
expect(executeCommand).toHaveBeenLastCalledWith(
8892
['git', 'clone', 'https://github.com/acme/forge', 'forge'],
8993
expect.objectContaining({ cwd: getReposPath(), env: mockEnv })
9094
)

0 commit comments

Comments
 (0)