| ... | @@ -3,7 +3,7 @@ import path from "node:path"; | ... | @@ -3,7 +3,7 @@ import path from "node:path"; |
| 3 | | 3 | |
| 4 | import * as NodeServices from "@effect/platform-node/NodeServices"; | 4 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 5 | import { it } from "@effect/vitest"; | 5 | import { it } from "@effect/vitest"; |
| 6 | import { Effect, FileSystem, Layer, PlatformError, Schema, Scope } from "effect"; | 6 | import { Effect, FileSystem, Layer, PlatformError, Scope } from "effect"; |
| 7 | import { expect } from "vitest"; | 7 | import { expect } from "vitest"; |
| 8 | | 8 | |
| 9 | import { GitCommandError, GitHubCliError, TextGenerationError } from "../Errors.ts"; | 9 | import { GitCommandError, GitHubCliError, TextGenerationError } from "../Errors.ts"; |
| ... | @@ -19,16 +19,11 @@ import { GitService } from "../Services/GitService.ts"; | ... | @@ -19,16 +19,11 @@ import { GitService } from "../Services/GitService.ts"; |
| 19 | import { GitCoreLive } from "./GitCore.ts"; | 19 | import { GitCoreLive } from "./GitCore.ts"; |
| 20 | import { makeGitManager } from "./GitManager.ts"; | 20 | import { makeGitManager } from "./GitManager.ts"; |
| 21 | | 21 | |
| 22 | class GitFixtureError extends Schema.TaggedErrorClass<GitFixtureError>()("GitFixtureError", { | | |
| 23 | message: Schema.String, | | |
| 24 | cause: Schema.optional(Schema.Defect), | | |
| 25 | }) {} | | |
| 26 | | | |
| 27 | interface FakeGhScenario { | 22 | interface FakeGhScenario { |
| 28 | prListSequence?: string[]; | 23 | prListSequence?: string[]; |
| 29 | createdPrUrl?: string; | 24 | createdPrUrl?: string; |
| 30 | defaultBranch?: string; | 25 | defaultBranch?: string; |
| 31 | failWith?: GitFixtureError; | 26 | failWith?: GitHubCliError; |
| 32 | } | 27 | } |
| 33 | | 28 | |
| 34 | interface FakeGitTextGeneration { | 29 | interface FakeGitTextGeneration { |
| ... | @@ -37,7 +32,7 @@ interface FakeGitTextGeneration { | ... | @@ -37,7 +32,7 @@ interface FakeGitTextGeneration { |
| 37 | branch: string | null; | 32 | branch: string | null; |
| 38 | stagedSummary: string; | 33 | stagedSummary: string; |
| 39 | stagedPatch: string; | 34 | stagedPatch: string; |
| 40 | }) => Effect.Effect<{ subject: string; body: string }, GitFixtureError>; | 35 | }) => Effect.Effect<{ subject: string; body: string }, TextGenerationError>; |
| 41 | generatePrContent: (input: { | 36 | generatePrContent: (input: { |
| 42 | cwd: string; | 37 | cwd: string; |
| 43 | baseBranch: string; | 38 | baseBranch: string; |
| ... | @@ -45,7 +40,7 @@ interface FakeGitTextGeneration { | ... | @@ -45,7 +40,7 @@ interface FakeGitTextGeneration { |
| 45 | commitSummary: string; | 40 | commitSummary: string; |
| 46 | diffSummary: string; | 41 | diffSummary: string; |
| 47 | diffPatch: string; | 42 | diffPatch: string; |
| 48 | }) => Effect.Effect<{ title: string; body: string }, GitFixtureError>; | 43 | }) => Effect.Effect<{ title: string; body: string }, TextGenerationError>; |
| 49 | } | 44 | } |
| 50 | | 45 | |
| 51 | function makeTempDir( | 46 | function makeTempDir( |
| ... | @@ -144,34 +139,6 @@ function createTextGeneration(overrides: Partial<FakeGitTextGeneration> = {}): T | ... | @@ -144,34 +139,6 @@ function createTextGeneration(overrides: Partial<FakeGitTextGeneration> = {}): T |
| 144 | }; | 139 | }; |
| 145 | } | 140 | } |
| 146 | | 141 | |
| 147 | const normalizeGhError = (error: GitFixtureError): GitHubCliError => { | | |
| 148 | if (error.message.includes("Command not found: gh")) { | | |
| 149 | return new GitHubCliError({ | | |
| 150 | operation: "execute", | | |
| 151 | detail: "GitHub CLI (`gh`) is required but not available on PATH.", | | |
| 152 | cause: error, | | |
| 153 | }); | | |
| 154 | } | | |
| 155 | const lower = error.message.toLowerCase(); | | |
| 156 | if ( | | |
| 157 | lower.includes("authentication failed") || | | |
| 158 | lower.includes("not logged in") || | | |
| 159 | lower.includes("gh auth login") || | | |
| 160 | lower.includes("no oauth token") | | |
| 161 | ) { | | |
| 162 | return new GitHubCliError({ | | |
| 163 | operation: "execute", | | |
| 164 | detail: "GitHub CLI is not authenticated. Run `gh auth login` and retry.", | | |
| 165 | cause: error, | | |
| 166 | }); | | |
| 167 | } | | |
| 168 | return new GitHubCliError({ | | |
| 169 | operation: "execute", | | |
| 170 | detail: error.message, | | |
| 171 | cause: error, | | |
| 172 | }); | | |
| 173 | }; | | |
| 174 | | | |
| 175 | function createGitHubCliWithFakeGh(scenario: FakeGhScenario = {}): { | 142 | function createGitHubCliWithFakeGh(scenario: FakeGhScenario = {}): { |
| 176 | service: GitHubCliShape; | 143 | service: GitHubCliShape; |
| 177 | ghCalls: string[]; | 144 | ghCalls: string[]; |
| ... | @@ -184,7 +151,7 @@ function createGitHubCliWithFakeGh(scenario: FakeGhScenario = {}): { | ... | @@ -184,7 +151,7 @@ function createGitHubCliWithFakeGh(scenario: FakeGhScenario = {}): { |
| 184 | ghCalls.push(args.join(" ")); | 151 | ghCalls.push(args.join(" ")); |
| 185 | | 152 | |
| 186 | if (scenario.failWith) { | 153 | if (scenario.failWith) { |
| 187 | return Effect.fail(normalizeGhError(scenario.failWith)); | 154 | return Effect.fail(scenario.failWith); |
| 188 | } | 155 | } |
| 189 | | 156 | |
| 190 | if (args[0] === "pr" && args[1] === "list") { | 157 | if (args[0] === "pr" && args[1] === "list") { |
| ... | @@ -378,7 +345,10 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { | ... | @@ -378,7 +345,10 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { |
| 378 | | 345 | |
| 379 | const { manager } = yield* makeManager({ | 346 | const { manager } = yield* makeManager({ |
| 380 | ghScenario: { | 347 | ghScenario: { |
| 381 | failWith: new GitFixtureError({ message: "Command not found: gh" }), | 348 | failWith: new GitHubCliError({ |
| | 349 | operation: "execute", |
| | 350 | detail: "GitHub CLI (`gh`) is required but not available on PATH.", |
| | 351 | }), |
| 382 | }, | 352 | }, |
| 383 | }); | 353 | }); |
| 384 | | 354 | |
| ... | @@ -622,7 +592,10 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { | ... | @@ -622,7 +592,10 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { |
| 622 | | 592 | |
| 623 | const { manager } = yield* makeManager({ | 593 | const { manager } = yield* makeManager({ |
| 624 | ghScenario: { | 594 | ghScenario: { |
| 625 | failWith: new GitFixtureError({ message: "Command not found: gh" }), | 595 | failWith: new GitHubCliError({ |
| | 596 | operation: "execute", |
| | 597 | detail: "GitHub CLI (`gh`) is required but not available on PATH.", |
| | 598 | }), |
| 626 | }, | 599 | }, |
| 627 | }); | 600 | }); |
| 628 | | 601 | |
| ... | @@ -648,7 +621,10 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { | ... | @@ -648,7 +621,10 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => { |
| 648 | | 621 | |
| 649 | const { manager } = yield* makeManager({ | 622 | const { manager } = yield* makeManager({ |
| 650 | ghScenario: { | 623 | ghScenario: { |
| 651 | failWith: new GitFixtureError({ message: "authentication failed" }), | 624 | failWith: new GitHubCliError({ |
| | 625 | operation: "execute", |
| | 626 | detail: "GitHub CLI is not authenticated. Run `gh auth login` and retry.", |
| | 627 | }), |
| 652 | }, | 628 | }, |
| 653 | }); | 629 | }); |
| 654 | | 630 | |