git.test.ts 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import { describe, expect } from "bun:test"
  2. import fs from "fs/promises"
  3. import path from "path"
  4. import { Effect } from "effect"
  5. import { Git } from "@opencode-ai/core/git"
  6. import { branch, commit, gitRemote } from "./fixture/git"
  7. import { tmpdir } from "./fixture/tmpdir"
  8. import { testEffect } from "./lib/effect"
  9. const it = testEffect(Git.defaultLayer)
  10. describe("Git", () => {
  11. it.live("clones a remote and reads checkout metadata", () =>
  12. withRemote((fixture) =>
  13. Effect.gen(function* () {
  14. const git = yield* Git.Service
  15. const target = path.join(fixture.root, "checkout")
  16. const result = yield* git.clone({ remote: fixture.remote, target })
  17. expect(result.exitCode).toBe(0)
  18. expect(yield* git.origin(target)).toBe(fixture.remote)
  19. expect(yield* git.head(target)).toBeString()
  20. expect(yield* git.branch(target)).toBe("main")
  21. expect(yield* git.remoteHead(target)).toBe("origin/main")
  22. expect(yield* read(path.join(target, "README.md"))).toBe("one\n")
  23. }),
  24. ),
  25. )
  26. it.live("fetches, checks out, and resets remote changes", () =>
  27. withRemote((fixture) =>
  28. Effect.gen(function* () {
  29. const git = yield* Git.Service
  30. const target = path.join(fixture.root, "checkout")
  31. yield* git.clone({ remote: fixture.remote, target })
  32. yield* Effect.promise(() => commit(fixture.source, "two\n", "second"))
  33. expect((yield* git.fetch(target)).exitCode).toBe(0)
  34. expect((yield* git.reset(target, "origin/main")).exitCode).toBe(0)
  35. expect(yield* read(path.join(target, "README.md"))).toBe("two\n")
  36. yield* Effect.promise(() => branch(fixture.source, "feature/docs", "feature\n"))
  37. expect((yield* git.fetchBranch(target, "feature/docs")).exitCode).toBe(0)
  38. expect((yield* git.checkout(target, "feature/docs")).exitCode).toBe(0)
  39. expect((yield* git.reset(target, "origin/feature/docs")).exitCode).toBe(0)
  40. expect(yield* git.branch(target)).toBe("feature/docs")
  41. expect(yield* read(path.join(target, "README.md"))).toBe("feature\n")
  42. }),
  43. ),
  44. )
  45. })
  46. function withRemote<A, E, R>(body: (fixture: Awaited<ReturnType<typeof gitRemote>>) => Effect.Effect<A, E, R>) {
  47. return Effect.acquireUseRelease(
  48. Effect.promise(async () => {
  49. const root = await tmpdir()
  50. return { root, fixture: await gitRemote(root.path) }
  51. }),
  52. (input) => body(input.fixture),
  53. (input) => Effect.promise(() => input.root[Symbol.asyncDispose]()),
  54. )
  55. }
  56. function read(file: string) {
  57. return Effect.promise(() => fs.readFile(file, "utf8")).pipe(Effect.map((content) => content.replace(/\r\n/g, "\n")))
  58. }