Skip to content

Commit d07fbdc

Browse files
refactor(source-control): git and process behaviour comes from forge hooks
GitManager, the git driver and VcsProcess still held forge knowledge: every host's change request head was fetched from GitHub's refs/pull/<n>/head (the review guide guessed GitHub's then GitLab's), GitManager imported GitHub's GH_REPO/gh-resolved resolution and ran it for every forge, guessed a fork's owner/repo from a GitHub-shaped URL, matched change request routes with its own regex, and kept a per-forge terminology table in shared; the driver wrote and read gh's branch.<b>.gh-merge-base for every host; VcsProcess matched gh/glab/az sign-in and not-found strings and throttled gh by command name, and the contracts error picked "Merge request"/"Pull request" by CLI name. Forges now answer through hooks. Client definitions gain changeRequestHeadRef (GitHub and Forgejo refs/pull/<n>/head, GitLab refs/merge-requests/<n>/head; Bitbucket Cloud, Azure DevOps and GitCafe publish none). Source control providers gain createsChangeRequestsIn (GitHub: GH_REPO and gh-resolved) and recordBranchBase (GitHub writes gh-merge-base so `gh pr create` in a T3 worktree picks the base). The git driver fetches a given ref (fetchRefIntoBranch, fetchRefCommit), records the base under T3's own branch.<b>.t3-merge-base and reads gh-merge-base only as a fallback for branches cut before. Process input carries a forge classifier, a not-found detail and a concurrency key; GitLab and Azure DevOps supply theirs, and gh keeps its limit of four through the GitHub package. GitManager reads terminology from the registry's definitions and change request repositories through parseChangeRequestUrl, and no longer imports any forge package. Behaviour changes: a GitLab merge request with no reachable head branch is checked out from refs/merge-requests/<n>/head. Other hosts no longer receive gh-merge-base. A fork whose host does not name its head repository is no longer guessed from the base repository's name. Co-Authored-By: Claude Opus 5.5 <[email protected]>
1 parent 077a8ee commit d07fbdc

26 files changed

Lines changed: 592 additions & 565 deletions

‎apps/server/src/git/GitManager.test.ts‎

Lines changed: 43 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -4576,63 +4576,6 @@ it.layer(layerGitManagerTest)("GitManager", (it) => {
45764576
}),
45774577
);
45784578

4579-
it.effect("derives fork repository identity from PR URL when GitHub omits nameWithOwner", () =>
4580-
Effect.gen(function* () {
4581-
const repoDir = yield* makeTempDir("t3code-git-manager-");
4582-
yield* initRepo(repoDir);
4583-
const originDir = yield* createBareRemote();
4584-
const forkDir = yield* createBareRemote();
4585-
yield* runGit(repoDir, ["remote", "add", "origin", originDir]);
4586-
yield* runGit(repoDir, ["push", "-u", "origin", "main"]);
4587-
yield* runGit(repoDir, ["remote", "add", "binbandit-seed", forkDir]);
4588-
yield* runGit(repoDir, ["checkout", "-b", "fix/git-action-default-without-origin"]);
4589-
NodeFS.writeFileSync(NodePath.join(repoDir, "derived-fork.txt"), "derived fork\n");
4590-
yield* runGit(repoDir, ["add", "derived-fork.txt"]);
4591-
yield* runGit(repoDir, ["commit", "-m", "Derived fork PR branch"]);
4592-
yield* runGit(repoDir, [
4593-
"push",
4594-
"-u",
4595-
"binbandit-seed",
4596-
"fix/git-action-default-without-origin",
4597-
]);
4598-
yield* runGit(repoDir, ["checkout", "main"]);
4599-
yield* runGit(repoDir, ["branch", "-D", "fix/git-action-default-without-origin"]);
4600-
4601-
const { manager } = yield* makeManager({
4602-
ghScenario: {
4603-
pullRequest: {
4604-
number: 642,
4605-
title: "fix: use commit as the default git action without origin",
4606-
url: "https://github.com/pingdotgg/t3code/pull/642",
4607-
baseRefName: "main",
4608-
headRefName: "fix/git-action-default-without-origin",
4609-
state: "open",
4610-
isCrossRepository: true,
4611-
headRepositoryOwnerLogin: "binbandit",
4612-
},
4613-
repositoryCloneUrls: {
4614-
"binbandit/t3code": {
4615-
url: forkDir,
4616-
sshUrl: forkDir,
4617-
},
4618-
},
4619-
},
4620-
});
4621-
4622-
const result = yield* preparePullRequestThread(manager, {
4623-
cwd: repoDir,
4624-
reference: "642",
4625-
mode: "local",
4626-
});
4627-
4628-
expect(result.branch).toBe("fix/git-action-default-without-origin");
4629-
expect(result.worktreePath).toBeNull();
4630-
expect(
4631-
(yield* runGit(repoDir, ["rev-parse", "--abbrev-ref", "@{upstream}"])).stdout.trim(),
4632-
).toBe("binbandit-seed/fix/git-action-default-without-origin");
4633-
}),
4634-
);
4635-
46364579
it.effect("refreshes a reused PR worktree onto the updated pull request head", () =>
46374580
Effect.gen(function* () {
46384581
const repoDir = yield* makeTempDir("t3code-git-manager-");
@@ -5058,6 +5001,49 @@ it.layer(layerGitManagerTest)("GitManager", (it) => {
50585001
}),
50595002
);
50605003

5004+
it.effect("creates a merge request worktree from the host's own head ref", () =>
5005+
Effect.gen(function* () {
5006+
const repoDir = yield* makeTempDir("t3code-git-manager-");
5007+
yield* initRepo(repoDir);
5008+
const remoteDir = yield* createBareRemote();
5009+
yield* runGit(repoDir, ["remote", "add", "origin", remoteDir]);
5010+
yield* runGit(repoDir, ["push", "-u", "origin", "main"]);
5011+
yield* runGit(repoDir, ["checkout", "-b", "feature/mr-ref-only"]);
5012+
NodeFS.writeFileSync(NodePath.join(repoDir, "mr.txt"), "merge request\n");
5013+
yield* runGit(repoDir, ["add", "mr.txt"]);
5014+
yield* runGit(repoDir, ["commit", "-m", "Merge request ref only"]);
5015+
const head = (yield* runGit(repoDir, ["rev-parse", "HEAD"])).stdout.trim();
5016+
yield* runGit(repoDir, ["push", "origin", "HEAD:refs/merge-requests/93/head"]);
5017+
yield* runGit(repoDir, ["checkout", "main"]);
5018+
yield* runGit(repoDir, ["branch", "-D", "feature/mr-ref-only"]);
5019+
5020+
const { service } = createGitHubProviderWithFakeGh({
5021+
pullRequest: {
5022+
number: 93,
5023+
title: "Merge request ref only",
5024+
url: "https://gitlab.com/pingdotgg/codething-mvp/-/merge_requests/93",
5025+
baseRefName: "main",
5026+
headRefName: "feature/mr-ref-only",
5027+
state: "open",
5028+
},
5029+
});
5030+
const { manager } = yield* makeManager({
5031+
sourceControlProvider: { ...service, kind: SourceControlProviderKind.make("gitlab") },
5032+
});
5033+
5034+
const result = yield* preparePullRequestThread(manager, {
5035+
cwd: repoDir,
5036+
reference: "93",
5037+
mode: "worktree",
5038+
});
5039+
5040+
expect(result.isOnPullRequestHead).toBe(true);
5041+
expect(
5042+
(yield* runGit(result.worktreePath as string, ["rev-parse", "HEAD"])).stdout.trim(),
5043+
).toBe(head);
5044+
}),
5045+
);
5046+
50615047
it.effect("preserves an unrelated local branch and upstream that share the fork head name", () =>
50625048
Effect.gen(function* () {
50635049
const repoDir = yield* makeTempDir("t3code-git-manager-");

0 commit comments

Comments
 (0)