worktree-remove.test.ts 2.1 KB

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