refactor: simplify createPR and improve type hierarchy

- Replace 3 nearly-identical createPR branches (70+ lines each)
  with a single function using PLATFORM_CLI lookup table
- Add BaseContext interface and have PRContext/ProjectContext
  extend it to eliminate field duplication

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-06-18 01:56:13 +08:00
parent d4ba4da9d5
commit 4fbac6a6e1
2 changed files with 39 additions and 84 deletions
+33 -77
View File
@@ -124,6 +124,36 @@ export async function getRemoteHostname(): Promise<string | null> {
} }
} }
const PLATFORM_CLI: Record<Platform, {
bin: string;
args: (title: string, body: string, base: string, draft: boolean) => string[];
label: string;
}> = {
github: {
bin: "gh",
args: (title, body, base, draft) => {
const a = ["pr", "create", "--title", title, "--body", body, "--base", base];
if (draft) a.push("--draft");
return a;
},
label: "gh pr create",
},
gitlab: {
bin: "glab",
args: (title, body, base, draft) => {
const a = ["mr", "create", "--title", title, "--description", body, "--target-branch", base];
if (draft) a.push("--draft");
return a;
},
label: "glab mr create",
},
gitea: {
bin: "tea",
args: (title, body, base, _draft) => ["pulls", "create", "--title", title, "--description", body, "--base", base],
label: "tea pulls create",
},
};
export async function createPR( export async function createPR(
platform: Platform, platform: Platform,
title: string, title: string,
@@ -131,80 +161,8 @@ export async function createPR(
base: string, base: string,
draft: boolean, draft: boolean,
): Promise<string> { ): Promise<string> {
if (platform === "github") { const cli = PLATFORM_CLI[platform];
const args = [ const proc = Bun.spawn([cli.bin, ...cli.args(title, body, base, draft)], {
"pr",
"create",
"--title",
title,
"--body",
body,
"--base",
base,
];
if (draft) args.push("--draft");
const proc = Bun.spawn(["gh", ...args], {
stdout: "pipe",
stderr: "pipe",
});
const exitCode = await proc.exited;
const stdout = await new Response(proc.stdout).text();
const stderr = await new Response(proc.stderr).text();
if (exitCode !== 0) {
throw new Error(
stderr.trim() || `gh pr create failed (exit code ${exitCode})`,
);
}
const match = stdout.match(/(https?:\/\/[^\s]+)/);
return match?.[1] ?? stdout.trim();
}
if (platform === "gitlab") {
const args = [
"mr",
"create",
"--title",
title,
"--description",
body,
"--target-branch",
base,
];
if (draft) args.push("--draft");
const proc = Bun.spawn(["glab", ...args], {
stdout: "pipe",
stderr: "pipe",
});
const exitCode = await proc.exited;
const stdout = await new Response(proc.stdout).text();
const stderr = await new Response(proc.stderr).text();
if (exitCode !== 0) {
throw new Error(
stderr.trim() || `glab mr create failed (exit code ${exitCode})`,
);
}
const match = stdout.match(/(https?:\/\/[^\s]+)/);
return match?.[1] ?? stdout.trim();
}
const args = [
"pulls",
"create",
"--title",
title,
"--description",
body,
"--base",
base,
];
const proc = Bun.spawn(["tea", ...args], {
stdout: "pipe", stdout: "pipe",
stderr: "pipe", stderr: "pipe",
}); });
@@ -213,9 +171,7 @@ export async function createPR(
const stderr = await new Response(proc.stderr).text(); const stderr = await new Response(proc.stderr).text();
if (exitCode !== 0) { if (exitCode !== 0) {
throw new Error( throw new Error(stderr.trim() || `${cli.label} failed (exit code ${exitCode})`);
stderr.trim() || `tea pulls create failed (exit code ${exitCode})`,
);
} }
const match = stdout.match(/(https?:\/\/[^\s]+)/); const match = stdout.match(/(https?:\/\/[^\s]+)/);
+6 -7
View File
@@ -12,22 +12,21 @@ export interface FileEntry {
label: string; label: string;
} }
export interface ProjectContext { export interface BaseContext {
readme: string | null; readme: string | null;
packageDescription: string | null; packageDescription: string | null;
structure: string | null; structure: string | null;
recentCommits: string[];
diff: string; diff: string;
} }
export interface PRContext { export interface ProjectContext extends BaseContext {
readme: string | null; recentCommits: string[];
packageDescription: string | null; }
structure: string | null;
export interface PRContext extends BaseContext {
branchName: string; branchName: string;
baseBranch: string; baseBranch: string;
branchCommits: string[]; branchCommits: string[];
diff: string;
} }
export interface CommitResult { export interface CommitResult {