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(
platform: Platform,
title: string,
@@ -131,80 +161,8 @@ export async function createPR(
base: string,
draft: boolean,
): Promise<string> {
if (platform === "github") {
const args = [
"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], {
const cli = PLATFORM_CLI[platform];
const proc = Bun.spawn([cli.bin, ...cli.args(title, body, base, draft)], {
stdout: "pipe",
stderr: "pipe",
});
@@ -213,9 +171,7 @@ export async function createPR(
const stderr = await new Response(proc.stderr).text();
if (exitCode !== 0) {
throw new Error(
stderr.trim() || `tea pulls create failed (exit code ${exitCode})`,
);
throw new Error(stderr.trim() || `${cli.label} failed (exit code ${exitCode})`);
}
const match = stdout.match(/(https?:\/\/[^\s]+)/);
+6 -7
View File
@@ -12,22 +12,21 @@ export interface FileEntry {
label: string;
}
export interface ProjectContext {
export interface BaseContext {
readme: string | null;
packageDescription: string | null;
structure: string | null;
recentCommits: string[];
diff: string;
}
export interface PRContext {
readme: string | null;
packageDescription: string | null;
structure: string | null;
export interface ProjectContext extends BaseContext {
recentCommits: string[];
}
export interface PRContext extends BaseContext {
branchName: string;
baseBranch: string;
branchCommits: string[];
diff: string;
}
export interface CommitResult {