fix(core): reuse location git repository
This commit is contained in:
parent
dba5da7c10
commit
d54d26acd6
5 changed files with 18 additions and 5 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import { Context, Effect, Layer } from "effect"
|
||||
import { Info, Ref, response } from "@opencode-ai/schema/location"
|
||||
import { Project } from "./project"
|
||||
import { Git } from "./git"
|
||||
import { LayerNode } from "@opencode-ai/util/effect/layer-node"
|
||||
import { makeLocationNode, tags } from "@opencode-ai/util/effect/app-node"
|
||||
|
||||
|
|
@ -10,6 +11,7 @@ export { Info, Ref, response }
|
|||
|
||||
export interface Interface extends Info {
|
||||
readonly vcs?: Project.Vcs
|
||||
readonly repository?: Git.Repository
|
||||
}
|
||||
|
||||
export class Service extends Context.Service<Service, Interface>()("@opencode/Location") {}
|
||||
|
|
@ -27,6 +29,7 @@ const layer = (ref: Ref) =>
|
|||
workspaceID: ref.workspaceID,
|
||||
project: { id: resolved.id, directory: resolved.directory },
|
||||
vcs: resolved.vcs,
|
||||
repository: resolved.repository,
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ export interface Resolved {
|
|||
readonly id: ID
|
||||
readonly directory: AbsolutePath
|
||||
readonly vcs?: Vcs
|
||||
readonly repository?: Git.Repository
|
||||
}
|
||||
|
||||
// Keep this filesystem-only; permission checks use it and should not execute VCS commands.
|
||||
|
|
@ -217,6 +218,7 @@ const layer = Layer.effect(
|
|||
id: id ?? ID.global,
|
||||
directory: repo.worktree,
|
||||
vcs: { type: "git" as const, store: repo.commonDirectory },
|
||||
repository: repo,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ const layer = Layer.effect(
|
|||
// Cache a scope-owned fiber so caller cancellation stops waiting without poisoning shared initialization.
|
||||
const repositoryFiber = yield* Effect.cached(
|
||||
Effect.gen(function* () {
|
||||
const source = yield* git.repo.discover(location.project.directory)
|
||||
const source = location.repository ?? (yield* git.repo.discover(location.project.directory))
|
||||
if (!source) return yield* new Error({ operation: "capture", message: "Project is not a Git repository" })
|
||||
const worktree = AbsolutePath.make(yield* fs.realPath(source.worktree).pipe(Effect.orDie))
|
||||
const gitDirectory = AbsolutePath.make(
|
||||
|
|
|
|||
|
|
@ -3,12 +3,18 @@ import { Effect, Layer } from "effect"
|
|||
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
||||
import { Location } from "@opencode-ai/core/location"
|
||||
import { Project } from "@opencode-ai/core/project"
|
||||
import { Git } from "@opencode-ai/core/git"
|
||||
import { AbsolutePath } from "@opencode-ai/core/schema"
|
||||
import { WorkspaceV2 } from "@opencode-ai/core/workspace"
|
||||
import { testEffect } from "./lib/effect"
|
||||
|
||||
const workspaceID = WorkspaceV2.ID.make("wrk_test")
|
||||
const ref = { directory: AbsolutePath.make("/repo/packages/app"), workspaceID }
|
||||
const repository = new Git.Repository({
|
||||
worktree: AbsolutePath.make("/repo"),
|
||||
gitDirectory: AbsolutePath.make("/repo/.git"),
|
||||
commonDirectory: AbsolutePath.make("/repo/.git"),
|
||||
})
|
||||
const projectLayer = Layer.succeed(
|
||||
Project.Service,
|
||||
Project.Service.of({
|
||||
|
|
@ -19,6 +25,7 @@ const projectLayer = Layer.succeed(
|
|||
id: Project.ID.make("project"),
|
||||
directory: AbsolutePath.make("/repo"),
|
||||
vcs: { type: "git", store: AbsolutePath.make("/repo/.git") },
|
||||
repository,
|
||||
}),
|
||||
commit: () => Effect.void,
|
||||
}),
|
||||
|
|
@ -38,6 +45,7 @@ describe("Location", () => {
|
|||
type: "git",
|
||||
store: AbsolutePath.make("/repo/.git"),
|
||||
})
|
||||
expect(location.repository).toBe(repository)
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import { tmpdir } from "./fixture/tmpdir"
|
|||
import { testEffect } from "./lib/effect"
|
||||
|
||||
describe("Snapshot", () => {
|
||||
testEffect(Layer.empty).live("keeps lazy repository discovery after the first caller is interrupted", () =>
|
||||
testEffect(Layer.empty).live("reuses the Location repository after the first caller is interrupted", () =>
|
||||
Effect.acquireUseRelease(
|
||||
Effect.promise(() => tmpdir()),
|
||||
(tmp) =>
|
||||
|
|
@ -65,16 +65,16 @@ describe("Snapshot", () => {
|
|||
|
||||
const interrupted = yield* snapshot.capture().pipe(Effect.forkChild)
|
||||
yield* Deferred.await(started)
|
||||
expect(discoveries).toBe(1)
|
||||
expect(discoveries).toBe(0)
|
||||
expect(creations).toBe(1)
|
||||
yield* Fiber.interrupt(interrupted)
|
||||
|
||||
const capture = yield* snapshot.capture().pipe(Effect.forkChild)
|
||||
expect(discoveries).toBe(1)
|
||||
expect(discoveries).toBe(0)
|
||||
expect(creations).toBe(1)
|
||||
yield* Deferred.succeed(release, undefined)
|
||||
expect(yield* Fiber.join(capture)).toBeDefined()
|
||||
expect(discoveries).toBe(1)
|
||||
expect(discoveries).toBe(0)
|
||||
expect(creations).toBe(1)
|
||||
}).pipe(Effect.provide(layer))
|
||||
}),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue