scrum4me-mcp/src/git/pr.ts
janpeter visser 1015264558 feat(M13): auto-PR via gh CLI after successful push (auto_pr=true)
New src/git/pr.ts helper wraps 'gh pr create'; returns { url } or { error }.
maybeCreateAutoPr() in update-job-status checks product.auto_pr, builds title
from story.code + task.title, writes pr_url to DB. Non-fatal: gh failure logs
a warning and leaves DONE status intact. Also syncs schema: auto_pr on Product,
pr_url on ClaudeJob.
2026-05-01 13:30:38 +02:00

38 lines
1.2 KiB
TypeScript

import { execFile } from 'node:child_process'
import { promisify } from 'node:util'
const exec = promisify(execFile)
export async function createPullRequest(opts: {
worktreePath: string
branchName: string
title: string
body: string
}): Promise<{ url: string } | { error: string }> {
const { worktreePath, branchName, title, body } = opts
try {
const { stdout } = await exec(
'gh',
['pr', 'create', '--title', title, '--body', body, '--head', branchName],
{ cwd: worktreePath },
)
// gh prints the PR URL as the last non-empty line
const lines = stdout.trim().split('\n').filter(Boolean)
const url = lines[lines.length - 1]?.trim() ?? ''
if (!url.startsWith('http')) {
return { error: `gh pr create produced unexpected output: ${stdout.slice(0, 200)}` }
}
return { url }
} catch (err: unknown) {
const msg = (err as { message?: string }).message ?? String(err)
const isNotFound =
msg.includes('command not found') ||
msg.includes('is not recognized') ||
msg.includes('ENOENT')
if (isNotFound) {
return { error: 'gh CLI not found — install GitHub CLI to enable auto-PR' }
}
return { error: `gh pr create failed: ${msg.slice(0, 300)}` }
}
}