| ... | @@ -2,7 +2,11 @@ import { randomUUID } from "node:crypto"; | ... | @@ -2,7 +2,11 @@ import { randomUUID } from "node:crypto"; |
| 2 | import { realpathSync } from "node:fs"; | 2 | import { realpathSync } from "node:fs"; |
| 3 | | 3 | |
| 4 | import { Effect, FileSystem, Layer, Path } from "effect"; | 4 | import { Effect, FileSystem, Layer, Path } from "effect"; |
| 5 | import { resolveAutoFeatureBranchName, sanitizeFeatureBranchName } from "@t3tools/shared/git"; | 5 | import { |
| | 6 | resolveAutoFeatureBranchName, |
| | 7 | sanitizeBranchFragment, |
| | 8 | sanitizeFeatureBranchName, |
| | 9 | } from "@t3tools/shared/git"; |
| 6 | | 10 | |
| 7 | import { GitManagerError } from "../Errors.ts"; | 11 | import { GitManagerError } from "../Errors.ts"; |
| 8 | import { GitManager, type GitManagerShape } from "../Services/GitManager.ts"; | 12 | import { GitManager, type GitManagerShape } from "../Services/GitManager.ts"; |
| ... | @@ -66,6 +70,18 @@ function resolveHeadRepositoryNameWithOwner( | ... | @@ -66,6 +70,18 @@ function resolveHeadRepositoryNameWithOwner( |
| 66 | return `${ownerLogin}/${repositoryName}`; | 70 | return `${ownerLogin}/${repositoryName}`; |
| 67 | } | 71 | } |
| 68 | | 72 | |
| | 73 | function resolvePullRequestWorktreeLocalBranchName( |
| | 74 | pullRequest: ResolvedPullRequest & PullRequestHeadRemoteInfo, |
| | 75 | ): string { |
| | 76 | if (!pullRequest.isCrossRepository) { |
| | 77 | return pullRequest.headBranch; |
| | 78 | } |
| | 79 | |
| | 80 | const sanitizedHeadBranch = sanitizeBranchFragment(pullRequest.headBranch).trim(); |
| | 81 | const suffix = sanitizedHeadBranch.length > 0 ? sanitizedHeadBranch : "head"; |
| | 82 | return `pr/${pullRequest.number}-${suffix}`; |
| | 83 | } |
| | 84 | |
| 69 | function parsePullRequestList(raw: unknown): PullRequestInfo[] { | 85 | function parsePullRequestList(raw: unknown): PullRequestInfo[] { |
| 70 | if (!Array.isArray(raw)) return []; | 86 | if (!Array.isArray(raw)) return []; |
| 71 | | 87 | |
| ... | @@ -322,6 +338,7 @@ export const makeGitManager = Effect.gen(function* () { | ... | @@ -322,6 +338,7 @@ export const makeGitManager = Effect.gen(function* () { |
| 322 | const materializePullRequestHeadBranch = ( | 338 | const materializePullRequestHeadBranch = ( |
| 323 | cwd: string, | 339 | cwd: string, |
| 324 | pullRequest: ResolvedPullRequest & PullRequestHeadRemoteInfo, | 340 | pullRequest: ResolvedPullRequest & PullRequestHeadRemoteInfo, |
| | 341 | localBranch = pullRequest.headBranch, |
| 325 | ) => | 342 | ) => |
| 326 | Effect.gen(function* () { | 343 | Effect.gen(function* () { |
| 327 | const repositoryNameWithOwner = resolveHeadRepositoryNameWithOwner(pullRequest) ?? ""; | 344 | const repositoryNameWithOwner = resolveHeadRepositoryNameWithOwner(pullRequest) ?? ""; |
| ... | @@ -330,7 +347,7 @@ export const makeGitManager = Effect.gen(function* () { | ... | @@ -330,7 +347,7 @@ export const makeGitManager = Effect.gen(function* () { |
| 330 | yield* gitCore.fetchPullRequestBranch({ | 347 | yield* gitCore.fetchPullRequestBranch({ |
| 331 | cwd, | 348 | cwd, |
| 332 | prNumber: pullRequest.number, | 349 | prNumber: pullRequest.number, |
| 333 | branch: pullRequest.headBranch, | 350 | branch: localBranch, |
| 334 | }); | 351 | }); |
| 335 | return; | 352 | return; |
| 336 | } | 353 | } |
| ... | @@ -355,11 +372,11 @@ export const makeGitManager = Effect.gen(function* () { | ... | @@ -355,11 +372,11 @@ export const makeGitManager = Effect.gen(function* () { |
| 355 | cwd, | 372 | cwd, |
| 356 | remoteName, | 373 | remoteName, |
| 357 | remoteBranch: pullRequest.headBranch, | 374 | remoteBranch: pullRequest.headBranch, |
| 358 | localBranch: pullRequest.headBranch, | 375 | localBranch, |
| 359 | }); | 376 | }); |
| 360 | yield* gitCore.setBranchUpstream({ | 377 | yield* gitCore.setBranchUpstream({ |
| 361 | cwd, | 378 | cwd, |
| 362 | branch: pullRequest.headBranch, | 379 | branch: localBranch, |
| 363 | remoteName, | 380 | remoteName, |
| 364 | remoteBranch: pullRequest.headBranch, | 381 | remoteBranch: pullRequest.headBranch, |
| 365 | }); | 382 | }); |
| ... | @@ -368,7 +385,7 @@ export const makeGitManager = Effect.gen(function* () { | ... | @@ -368,7 +385,7 @@ export const makeGitManager = Effect.gen(function* () { |
| 368 | gitCore.fetchPullRequestBranch({ | 385 | gitCore.fetchPullRequestBranch({ |
| 369 | cwd, | 386 | cwd, |
| 370 | prNumber: pullRequest.number, | 387 | prNumber: pullRequest.number, |
| 371 | branch: pullRequest.headBranch, | 388 | branch: localBranch, |
| 372 | }), | 389 | }), |
| 373 | ), | 390 | ), |
| 374 | ); | 391 | ); |
| ... | @@ -701,14 +718,32 @@ export const makeGitManager = Effect.gen(function* () { | ... | @@ -701,14 +718,32 @@ export const makeGitManager = Effect.gen(function* () { |
| 701 | ...pullRequest, | 718 | ...pullRequest, |
| 702 | ...toPullRequestHeadRemoteInfo(pullRequestSummary), | 719 | ...toPullRequestHeadRemoteInfo(pullRequestSummary), |
| 703 | } as const; | 720 | } as const; |
| | 721 | const localPullRequestBranch = resolvePullRequestWorktreeLocalBranchName( |
| | 722 | pullRequestWithRemoteInfo, |
| | 723 | ); |
| 704 | | 724 | |
| 705 | const findLocalHeadBranch = (cwd: string) => | 725 | const findLocalHeadBranch = (cwd: string) => |
| 706 | gitCore.listBranches({ cwd }).pipe( | 726 | gitCore.listBranches({ cwd }).pipe( |
| 707 | Effect.map((result) => | 727 | Effect.map((result) => { |
| 708 | result.branches.find( | 728 | const localBranch = result.branches.find( |
| 709 | (branch) => !branch.isRemote && branch.name === pullRequest.headBranch, | 729 | (branch) => !branch.isRemote && branch.name === localPullRequestBranch, |
| 710 | ), | 730 | ); |
| 711 | ), | 731 | if (localBranch) { |
| | 732 | return localBranch; |
| | 733 | } |
| | 734 | if (localPullRequestBranch === pullRequest.headBranch) { |
| | 735 | return null; |
| | 736 | } |
| | 737 | return ( |
| | 738 | result.branches.find( |
| | 739 | (branch) => |
| | 740 | !branch.isRemote && |
| | 741 | branch.name === pullRequest.headBranch && |
| | 742 | branch.worktreePath !== null && |
| | 743 | canonicalizeExistingPath(branch.worktreePath) !== rootWorktreePath, |
| | 744 | ) ?? null |
| | 745 | ); |
| | 746 | }), |
| 712 | ); | 747 | ); |
| 713 | | 748 | |
| 714 | const existingBranchBeforeFetch = yield* findLocalHeadBranch(input.cwd); | 749 | const existingBranchBeforeFetch = yield* findLocalHeadBranch(input.cwd); |
| ... | @@ -722,7 +757,7 @@ export const makeGitManager = Effect.gen(function* () { | ... | @@ -722,7 +757,7 @@ export const makeGitManager = Effect.gen(function* () { |
| 722 | yield* ensureExistingWorktreeUpstream(existingBranchBeforeFetch.worktreePath); | 757 | yield* ensureExistingWorktreeUpstream(existingBranchBeforeFetch.worktreePath); |
| 723 | return { | 758 | return { |
| 724 | pullRequest, | 759 | pullRequest, |
| 725 | branch: pullRequest.headBranch, | 760 | branch: localPullRequestBranch, |
| 726 | worktreePath: existingBranchBeforeFetch.worktreePath, | 761 | worktreePath: existingBranchBeforeFetch.worktreePath, |
| 727 | }; | 762 | }; |
| 728 | } | 763 | } |
| ... | @@ -733,7 +768,11 @@ export const makeGitManager = Effect.gen(function* () { | ... | @@ -733,7 +768,11 @@ export const makeGitManager = Effect.gen(function* () { |
| 733 | ); | 768 | ); |
| 734 | } | 769 | } |
| 735 | | 770 | |
| 736 | yield* materializePullRequestHeadBranch(input.cwd, pullRequestWithRemoteInfo); | 771 | yield* materializePullRequestHeadBranch( |
| | 772 | input.cwd, |
| | 773 | pullRequestWithRemoteInfo, |
| | 774 | localPullRequestBranch, |
| | 775 | ); |
| 737 | | 776 | |
| 738 | const existingBranchAfterFetch = yield* findLocalHeadBranch(input.cwd); | 777 | const existingBranchAfterFetch = yield* findLocalHeadBranch(input.cwd); |
| 739 | const existingBranchAfterFetchPath = existingBranchAfterFetch?.worktreePath | 778 | const existingBranchAfterFetchPath = existingBranchAfterFetch?.worktreePath |
| ... | @@ -746,7 +785,7 @@ export const makeGitManager = Effect.gen(function* () { | ... | @@ -746,7 +785,7 @@ export const makeGitManager = Effect.gen(function* () { |
| 746 | yield* ensureExistingWorktreeUpstream(existingBranchAfterFetch.worktreePath); | 785 | yield* ensureExistingWorktreeUpstream(existingBranchAfterFetch.worktreePath); |
| 747 | return { | 786 | return { |
| 748 | pullRequest, | 787 | pullRequest, |
| 749 | branch: pullRequest.headBranch, | 788 | branch: localPullRequestBranch, |
| 750 | worktreePath: existingBranchAfterFetch.worktreePath, | 789 | worktreePath: existingBranchAfterFetch.worktreePath, |
| 751 | }; | 790 | }; |
| 752 | } | 791 | } |
| ... | @@ -759,7 +798,7 @@ export const makeGitManager = Effect.gen(function* () { | ... | @@ -759,7 +798,7 @@ export const makeGitManager = Effect.gen(function* () { |
| 759 | | 798 | |
| 760 | const worktree = yield* gitCore.createWorktree({ | 799 | const worktree = yield* gitCore.createWorktree({ |
| 761 | cwd: input.cwd, | 800 | cwd: input.cwd, |
| 762 | branch: pullRequest.headBranch, | 801 | branch: localPullRequestBranch, |
| 763 | path: null, | 802 | path: null, |
| 764 | }); | 803 | }); |
| 765 | yield* ensureExistingWorktreeUpstream(worktree.worktree.path); | 804 | yield* ensureExistingWorktreeUpstream(worktree.worktree.path); |