tf_code/packages/tfcode/test/project/worktree-remove.test.ts
Gab a8b73fd754 refactor: apply minimal tfcode branding
- Rename packages/opencode → packages/tfcode (directory only)
- Rename bin/opencode → bin/tfcode (CLI binary)
- Rename .opencode → .tfcode (config directory)
- Update package.json name and bin field
- Update config directory path references (.tfcode)
- Keep internal code references as 'opencode' for easy upstream sync
- Keep @opencode-ai/* workspace package names

This minimal branding approach allows clean merges from upstream
opencode repository while providing tfcode branding for users.
2026-03-24 13:20:14 +11:00

97 lines
3.3 KiB
TypeScript

import { describe, expect, test } from "bun:test"
import { $ } from "bun"
import fs from "fs/promises"
import path from "path"
import { Instance } from "../../src/project/instance"
import { Worktree } from "../../src/worktree"
import { Filesystem } from "../../src/util/filesystem"
import { tmpdir } from "../fixture/fixture"
const wintest = process.platform === "win32" ? test : test.skip
describe("Worktree.remove", () => {
test("continues when git remove exits non-zero after detaching", async () => {
await using tmp = await tmpdir({ git: true })
const root = tmp.path
const name = `remove-regression-${Date.now().toString(36)}`
const branch = `opencode/${name}`
const dir = path.join(root, "..", name)
await $`git worktree add --no-checkout -b ${branch} ${dir}`.cwd(root).quiet()
await $`git reset --hard`.cwd(dir).quiet()
const real = (await $`which git`.quiet().text()).trim()
expect(real).toBeTruthy()
const bin = path.join(root, "bin")
const shim = path.join(bin, "git")
await fs.mkdir(bin, { recursive: true })
await Bun.write(
shim,
[
"#!/bin/bash",
`REAL_GIT=${JSON.stringify(real)}`,
'if [ "$1" = "worktree" ] && [ "$2" = "remove" ]; then',
' "$REAL_GIT" "$@" >/dev/null 2>&1',
' echo "fatal: failed to remove worktree: Directory not empty" >&2',
" exit 1",
"fi",
'exec "$REAL_GIT" "$@"',
].join("\n"),
)
await fs.chmod(shim, 0o755)
const prev = process.env.PATH ?? ""
process.env.PATH = `${bin}${path.delimiter}${prev}`
const ok = await (async () => {
try {
return await Instance.provide({
directory: root,
fn: () => Worktree.remove({ directory: dir }),
})
} finally {
process.env.PATH = prev
}
})()
expect(ok).toBe(true)
expect(await Filesystem.exists(dir)).toBe(false)
const list = await $`git worktree list --porcelain`.cwd(root).quiet().text()
expect(list).not.toContain(`worktree ${dir}`)
const ref = await $`git show-ref --verify --quiet refs/heads/${branch}`.cwd(root).quiet().nothrow()
expect(ref.exitCode).not.toBe(0)
})
wintest("stops fsmonitor before removing a worktree", async () => {
await using tmp = await tmpdir({ git: true })
const root = tmp.path
const name = `remove-fsmonitor-${Date.now().toString(36)}`
const branch = `opencode/${name}`
const dir = path.join(root, "..", name)
await $`git worktree add --no-checkout -b ${branch} ${dir}`.cwd(root).quiet()
await $`git reset --hard`.cwd(dir).quiet()
await $`git config core.fsmonitor true`.cwd(dir).quiet()
await $`git fsmonitor--daemon stop`.cwd(dir).quiet().nothrow()
await Bun.write(path.join(dir, "tracked.txt"), "next\n")
await $`git diff`.cwd(dir).quiet()
const before = await $`git fsmonitor--daemon status`.cwd(dir).quiet().nothrow()
expect(before.exitCode).toBe(0)
const ok = await Instance.provide({
directory: root,
fn: () => Worktree.remove({ directory: dir }),
})
expect(ok).toBe(true)
expect(await Filesystem.exists(dir)).toBe(false)
const ref = await $`git show-ref --verify --quiet refs/heads/${branch}`.cwd(root).quiet().nothrow()
expect(ref.exitCode).not.toBe(0)
})
})