|
|
@@ -18,13 +18,15 @@ import { it } from "./lib/effect"
|
|
|
|
|
|
describe("ProjectReference", () => {
|
|
|
it.live("uses the broad experimental flag unless references are explicitly configured", () =>
|
|
|
- withEnv({ OPENCODE_EXPERIMENTAL: "true", OPENCODE_EXPERIMENTAL_REFERENCES: undefined },
|
|
|
+ withEnv(
|
|
|
+ { OPENCODE_EXPERIMENTAL: "true", OPENCODE_EXPERIMENTAL_REFERENCES: undefined },
|
|
|
Effect.sync(() => {
|
|
|
expect(Flag.OPENCODE_EXPERIMENTAL_REFERENCES).toBe(true)
|
|
|
}),
|
|
|
).pipe(
|
|
|
Effect.flatMap(() =>
|
|
|
- withEnv({ OPENCODE_EXPERIMENTAL: "true", OPENCODE_EXPERIMENTAL_REFERENCES: "false" },
|
|
|
+ withEnv(
|
|
|
+ { OPENCODE_EXPERIMENTAL: "true", OPENCODE_EXPERIMENTAL_REFERENCES: "false" },
|
|
|
Effect.sync(() => {
|
|
|
expect(Flag.OPENCODE_EXPERIMENTAL_REFERENCES).toBe(false)
|
|
|
}),
|
|
|
@@ -85,84 +87,100 @@ describe("ProjectReference", () => {
|
|
|
)
|
|
|
|
|
|
it.live("merges config aliases and exposes mention and managed-path operations", () =>
|
|
|
- withoutReferences(withTmp((tmp) => {
|
|
|
- const calls: RepositoryCache.EnsureInput[] = []
|
|
|
- const project = path.join(tmp.path, "project")
|
|
|
- const nested = path.join(project, "packages", "app")
|
|
|
- const docs = path.join(project, "docs")
|
|
|
- const repos = path.join(tmp.path, "repos")
|
|
|
- return Effect.gen(function* () {
|
|
|
- yield* Effect.promise(async () => {
|
|
|
- await fs.mkdir(nested, { recursive: true })
|
|
|
- await fs.mkdir(docs)
|
|
|
- await fs.writeFile(path.join(docs, "README.md"), "docs")
|
|
|
- })
|
|
|
+ withoutReferences(
|
|
|
+ withTmp((tmp) => {
|
|
|
+ const calls: RepositoryCache.EnsureInput[] = []
|
|
|
+ const project = path.join(tmp.path, "project")
|
|
|
+ const nested = path.join(project, "packages", "app")
|
|
|
+ const docs = path.join(project, "docs")
|
|
|
+ const repos = path.join(tmp.path, "repos")
|
|
|
+ return Effect.gen(function* () {
|
|
|
+ yield* Effect.promise(async () => {
|
|
|
+ await fs.mkdir(nested, { recursive: true })
|
|
|
+ await fs.mkdir(docs)
|
|
|
+ await fs.writeFile(path.join(docs, "README.md"), "docs")
|
|
|
+ })
|
|
|
|
|
|
- yield* withReferences(
|
|
|
- Effect.gen(function* () {
|
|
|
- const references = yield* ProjectReference.Service
|
|
|
- const git = path.join(repos, "github.com", "owner", "repo")
|
|
|
+ yield* withReferences(
|
|
|
+ Effect.gen(function* () {
|
|
|
+ const references = yield* ProjectReference.Service
|
|
|
+ const git = path.join(repos, "github.com", "owner", "repo")
|
|
|
|
|
|
- expect(yield* references.list()).toMatchObject([
|
|
|
- { name: "docs", kind: "local", path: docs },
|
|
|
- { name: "sdk", kind: "git", path: git },
|
|
|
- ])
|
|
|
- expect(yield* references.resolveMention("docs/README.md")).toMatchObject({
|
|
|
- name: "docs",
|
|
|
- kind: "reference",
|
|
|
- target: "README.md",
|
|
|
- path: path.join(docs, "README.md"),
|
|
|
- })
|
|
|
- expect(yield* references.resolveMention("docs/missing.md")).toMatchObject({ name: "docs", kind: "missing" })
|
|
|
- expect(yield* references.resolveMention("docs/../outside.md")).toMatchObject({ name: "docs", kind: "invalid" })
|
|
|
- expect(yield* references.resolveMention("unknown")).toBeUndefined()
|
|
|
- expect(yield* references.resolveMention("sdk")).toMatchObject({ name: "sdk", kind: "reference", path: git })
|
|
|
- expect(yield* references.containsManagedPath(path.join(git, "README.md"))).toBe(true)
|
|
|
- expect(yield* references.containsManagedPath(path.join(docs, "README.md"))).toBe(false)
|
|
|
- yield* references.ensurePath()
|
|
|
- expect(calls).toHaveLength(1)
|
|
|
- }).pipe(
|
|
|
- Effect.provide(
|
|
|
- testLayer({
|
|
|
- directory: nested,
|
|
|
- project,
|
|
|
- repos,
|
|
|
- documents: [
|
|
|
- document({ docs: { path: "./old-docs" }, sdk: "owner/old" }),
|
|
|
- document({ docs: { path: "./docs" }, sdk: { repository: "owner/repo", branch: "main" } }),
|
|
|
- ],
|
|
|
- ensure: (input) => Effect.sync(() => result(repos, calls, input)),
|
|
|
- }),
|
|
|
+ expect(yield* references.list()).toMatchObject([
|
|
|
+ { name: "docs", kind: "local", path: docs },
|
|
|
+ { name: "sdk", kind: "git", path: git },
|
|
|
+ ])
|
|
|
+ expect(yield* references.resolveMention("docs/README.md")).toMatchObject({
|
|
|
+ name: "docs",
|
|
|
+ kind: "reference",
|
|
|
+ target: "README.md",
|
|
|
+ path: path.join(docs, "README.md"),
|
|
|
+ })
|
|
|
+ expect(yield* references.resolveMention("docs/missing.md")).toMatchObject({
|
|
|
+ name: "docs",
|
|
|
+ kind: "missing",
|
|
|
+ })
|
|
|
+ expect(yield* references.resolveMention("docs/../outside.md")).toMatchObject({
|
|
|
+ name: "docs",
|
|
|
+ kind: "invalid",
|
|
|
+ })
|
|
|
+ expect(yield* references.resolveMention("unknown")).toBeUndefined()
|
|
|
+ expect(yield* references.resolveMention("sdk")).toMatchObject({
|
|
|
+ name: "sdk",
|
|
|
+ kind: "reference",
|
|
|
+ path: git,
|
|
|
+ })
|
|
|
+ expect(yield* references.containsManagedPath(path.join(git, "README.md"))).toBe(true)
|
|
|
+ expect(yield* references.containsManagedPath(path.join(docs, "README.md"))).toBe(false)
|
|
|
+ yield* references.ensurePath()
|
|
|
+ expect(calls).toHaveLength(1)
|
|
|
+ }).pipe(
|
|
|
+ Effect.provide(
|
|
|
+ testLayer({
|
|
|
+ directory: nested,
|
|
|
+ project,
|
|
|
+ repos,
|
|
|
+ documents: [
|
|
|
+ document({ docs: { path: "./old-docs" }, sdk: "owner/old" }),
|
|
|
+ document({ docs: { path: "./docs" }, sdk: { repository: "owner/repo", branch: "main" } }),
|
|
|
+ ],
|
|
|
+ ensure: (input) => Effect.sync(() => result(repos, calls, input)),
|
|
|
+ }),
|
|
|
+ ),
|
|
|
),
|
|
|
- ),
|
|
|
- )
|
|
|
- })
|
|
|
- })),
|
|
|
+ )
|
|
|
+ })
|
|
|
+ }),
|
|
|
+ ),
|
|
|
)
|
|
|
|
|
|
it.live("is inert while the runtime flag is disabled", () =>
|
|
|
- withoutReferences(withTmp((tmp) => {
|
|
|
- const calls: RepositoryCache.EnsureInput[] = []
|
|
|
- return Effect.gen(function* () {
|
|
|
- const references = yield* ProjectReference.Service
|
|
|
- expect(yield* references.list()).toEqual([])
|
|
|
- expect(yield* references.get("sdk")).toBeUndefined()
|
|
|
- expect(yield* references.resolveMention("sdk")).toBeUndefined()
|
|
|
- expect(yield* references.containsManagedPath(path.join(tmp.path, "repos", "github.com", "owner", "repo"))).toBe(false)
|
|
|
- yield* references.ensurePath()
|
|
|
- expect(calls).toEqual([])
|
|
|
- }).pipe(
|
|
|
- Effect.provide(
|
|
|
- testLayer({
|
|
|
- directory: tmp.path,
|
|
|
- project: tmp.path,
|
|
|
- repos: path.join(tmp.path, "repos"),
|
|
|
- documents: [document({ sdk: "owner/repo" })],
|
|
|
- ensure: (input) => Effect.sync(() => result(path.join(tmp.path, "repos"), calls, input)),
|
|
|
- }),
|
|
|
- ),
|
|
|
- )
|
|
|
- })),
|
|
|
+ withoutReferences(
|
|
|
+ withTmp((tmp) => {
|
|
|
+ const calls: RepositoryCache.EnsureInput[] = []
|
|
|
+ return Effect.gen(function* () {
|
|
|
+ const references = yield* ProjectReference.Service
|
|
|
+ expect(yield* references.list()).toEqual([])
|
|
|
+ expect(yield* references.get("sdk")).toBeUndefined()
|
|
|
+ expect(yield* references.resolveMention("sdk")).toBeUndefined()
|
|
|
+ expect(
|
|
|
+ yield* references.containsManagedPath(path.join(tmp.path, "repos", "github.com", "owner", "repo")),
|
|
|
+ ).toBe(false)
|
|
|
+ yield* references.ensurePath()
|
|
|
+ expect(calls).toEqual([])
|
|
|
+ }).pipe(
|
|
|
+ Effect.provide(
|
|
|
+ testLayer({
|
|
|
+ directory: tmp.path,
|
|
|
+ project: tmp.path,
|
|
|
+ repos: path.join(tmp.path, "repos"),
|
|
|
+ documents: [document({ sdk: "owner/repo" })],
|
|
|
+ ensure: (input) => Effect.sync(() => result(path.join(tmp.path, "repos"), calls, input)),
|
|
|
+ }),
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ }),
|
|
|
+ ),
|
|
|
)
|
|
|
|
|
|
it.live("starts Git materialization in the background without blocking the location layer", () =>
|
|
|
@@ -173,7 +191,10 @@ describe("ProjectReference", () => {
|
|
|
Effect.gen(function* () {
|
|
|
expect(yield* (yield* ProjectReference.Service).list()).toHaveLength(1)
|
|
|
yield* Deferred.await(started).pipe(
|
|
|
- Effect.timeoutOrElse({ duration: "1 second", orElse: () => Effect.die(new Error("refresh did not start")) }),
|
|
|
+ Effect.timeoutOrElse({
|
|
|
+ duration: "1 second",
|
|
|
+ orElse: () => Effect.die(new Error("refresh did not start")),
|
|
|
+ }),
|
|
|
)
|
|
|
}).pipe(
|
|
|
Effect.provide(
|
|
|
@@ -196,7 +217,11 @@ function document(references: ConfigReference.Info) {
|
|
|
return new Config.Loaded({ source: { type: "memory" }, info: Schema.decodeUnknownSync(Config.Info)({ references }) })
|
|
|
}
|
|
|
|
|
|
-function result(repos: string, calls: RepositoryCache.EnsureInput[], input: RepositoryCache.EnsureInput): RepositoryCache.Result {
|
|
|
+function result(
|
|
|
+ repos: string,
|
|
|
+ calls: RepositoryCache.EnsureInput[],
|
|
|
+ input: RepositoryCache.EnsureInput,
|
|
|
+): RepositoryCache.Result {
|
|
|
calls.push(input)
|
|
|
return {
|
|
|
repository: input.reference.label,
|
|
|
@@ -223,10 +248,16 @@ function testLayer(input: {
|
|
|
Layer.succeed(
|
|
|
Location.Service,
|
|
|
Location.Service.of(
|
|
|
- location({ directory: AbsolutePath.make(input.directory) }, { projectDirectory: AbsolutePath.make(input.project) }),
|
|
|
+ location(
|
|
|
+ { directory: AbsolutePath.make(input.directory) },
|
|
|
+ { projectDirectory: AbsolutePath.make(input.project) },
|
|
|
+ ),
|
|
|
),
|
|
|
),
|
|
|
- Layer.succeed(Config.Service, Config.Service.of({ directories: () => Effect.succeed([]), get: () => Effect.succeed(input.documents) })),
|
|
|
+ Layer.succeed(
|
|
|
+ Config.Service,
|
|
|
+ Config.Service.of({ directories: () => Effect.succeed([]), get: () => Effect.succeed(input.documents) }),
|
|
|
+ ),
|
|
|
Layer.succeed(RepositoryCache.Service, RepositoryCache.Service.of({ ensure: input.ensure })),
|
|
|
),
|
|
|
),
|
|
|
@@ -234,7 +265,11 @@ function testLayer(input: {
|
|
|
}
|
|
|
|
|
|
function withTmp<A, E, R>(body: (tmp: Awaited<ReturnType<typeof tmpdir>>) => Effect.Effect<A, E, R>) {
|
|
|
- return Effect.acquireUseRelease(Effect.promise(() => tmpdir()), body, (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()))
|
|
|
+ return Effect.acquireUseRelease(
|
|
|
+ Effect.promise(() => tmpdir()),
|
|
|
+ body,
|
|
|
+ (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
|
|
|
+ )
|
|
|
}
|
|
|
|
|
|
function withReferences<A, E, R>(body: Effect.Effect<A, E, R>) {
|