worktree-remove.test.ts 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import { describe, expect, test } from "bun:test"
  2. import { $ } from "bun"
  3. import fs from "fs/promises"
  4. import path from "path"
  5. import { Instance } from "../../src/project/instance"
  6. import { Worktree } from "../../src/worktree"
  7. import { tmpdir } from "../fixture/fixture"
  8. describe("Worktree.remove", () => {
  9. test("continues when git remove exits non-zero after detaching", async () => {
  10. await using tmp = await tmpdir({ git: true })
  11. const root = tmp.path
  12. const name = `remove-regression-${Date.now().toString(36)}`
  13. const branch = `opencode/${name}`
  14. const dir = path.join(root, "..", name)
  15. await $`git worktree add --no-checkout -b ${branch} ${dir}`.cwd(root).quiet()
  16. await $`git reset --hard`.cwd(dir).quiet()
  17. const real = (await $`which git`.quiet().text()).trim()
  18. expect(real).toBeTruthy()
  19. const bin = path.join(root, "bin")
  20. const shim = path.join(bin, "git")
  21. await fs.mkdir(bin, { recursive: true })
  22. await Bun.write(
  23. shim,
  24. [
  25. "#!/bin/bash",
  26. `REAL_GIT=${JSON.stringify(real)}`,
  27. 'if [ "$1" = "worktree" ] && [ "$2" = "remove" ]; then',
  28. ' "$REAL_GIT" "$@" >/dev/null 2>&1',
  29. ' echo "fatal: failed to remove worktree: Directory not empty" >&2',
  30. " exit 1",
  31. "fi",
  32. 'exec "$REAL_GIT" "$@"',
  33. ].join("\n"),
  34. )
  35. await fs.chmod(shim, 0o755)
  36. const prev = process.env.PATH ?? ""
  37. process.env.PATH = `${bin}${path.delimiter}${prev}`
  38. const ok = await (async () => {
  39. try {
  40. return await Instance.provide({
  41. directory: root,
  42. fn: () => Worktree.remove({ directory: dir }),
  43. })
  44. } finally {
  45. process.env.PATH = prev
  46. }
  47. })()
  48. expect(ok).toBe(true)
  49. expect(await Bun.file(dir).exists()).toBe(false)
  50. const list = await $`git worktree list --porcelain`.cwd(root).quiet().text()
  51. expect(list).not.toContain(`worktree ${dir}`)
  52. const ref = await $`git show-ref --verify --quiet refs/heads/${branch}`.cwd(root).quiet().nothrow()
  53. expect(ref.exitCode).not.toBe(0)
  54. })
  55. })