fixture.ts 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. import { $ } from "bun"
  2. import * as fs from "fs/promises"
  3. import os from "os"
  4. import path from "path"
  5. import type { Config } from "../../src/config/config"
  6. // Strip null bytes from paths (defensive fix for CI environment issues)
  7. function sanitizePath(p: string): string {
  8. return p.replace(/\0/g, "")
  9. }
  10. type TmpDirOptions<T> = {
  11. git?: boolean
  12. config?: Partial<Config.Info>
  13. init?: (dir: string) => Promise<T>
  14. dispose?: (dir: string) => Promise<T>
  15. }
  16. export async function tmpdir<T>(options?: TmpDirOptions<T>) {
  17. const dirpath = sanitizePath(path.join(os.tmpdir(), "opencode-test-" + Math.random().toString(36).slice(2)))
  18. await fs.mkdir(dirpath, { recursive: true })
  19. if (options?.git) {
  20. await $`git init`.cwd(dirpath).quiet()
  21. await $`git commit --allow-empty -m "root commit ${dirpath}"`.cwd(dirpath).quiet()
  22. }
  23. if (options?.config) {
  24. await Bun.write(
  25. path.join(dirpath, "opencode.json"),
  26. JSON.stringify({
  27. $schema: "https://opencode.ai/config.json",
  28. ...options.config,
  29. }),
  30. )
  31. }
  32. const extra = await options?.init?.(dirpath)
  33. const realpath = sanitizePath(await fs.realpath(dirpath))
  34. const result = {
  35. [Symbol.asyncDispose]: async () => {
  36. await options?.dispose?.(dirpath)
  37. // await fs.rm(dirpath, { recursive: true, force: true })
  38. },
  39. path: realpath,
  40. extra: extra as T,
  41. }
  42. return result
  43. }