feat: pull_request_review trigger

This commit is contained in:
Alpha Nerd 2026-05-11 17:22:48 +02:00
parent 5569e8952a
commit fcfea07f01
Signed by: alpha-nerd
SSH key fingerprint: SHA256:QkkAgVoYi9TQ0UKPkiKSfnerZy2h4qhi3SVPXJmBN+M

View file

@ -193,7 +193,7 @@ try {
proc = spawn(`opencode`, [`serve`, `--hostname=${HOST}`, `--port=${PORT}`], {
stdio: ["ignore", "inherit", "inherit"],
})
assertContextEvent("issue_comment", "pull_request_review_comment")
assertContextEvent("issue_comment", "pull_request_review_comment", "pull_request_review")
assertPayloadKeyword()
await assertOpencodeConnected()
await opencodeLog({ service: "forgejo-workflow", level: "info", message: "Prepare to react to Forgejo Workflow event" })
@ -338,9 +338,17 @@ async function forgejoFetch<T>(url: string, options?: RequestInit): Promise<T> {
return res.json() as Promise<T>
}
function getTriggerBody(): string {
const context = useContext()
const p = context.payload as any
if (context.eventName === "pull_request_review") {
return (p.review?.body ?? "").toString()
}
return (p.comment?.body ?? "").toString()
}
function assertPayloadKeyword() {
const payload = useContext().payload as IssueCommentEvent | PullRequestReviewCommentEvent
const body = payload.comment.body.trim()
const body = getTriggerBody().trim()
const mentions = (process.env["MENTIONS"] || "/opencode,/oc").split(",").map((m) => m.trim())
const escaped = mentions.map((m) => m.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")
const regex = new RegExp(`(?:^|\\s)(?:${escaped})(?=$|\\s)`, "i")
@ -446,12 +454,19 @@ function useContext() {
}
function useIssueId() {
const payload = useContext().payload as IssueCommentEvent
return payload.issue.number
const context = useContext()
const p = context.payload as any
if (context.eventName === "pull_request_review") {
return p.pull_request.number as number
}
return p.issue.number as number
}
function isPullRequest() {
const context = useContext()
if (context.eventName === "pull_request_review" || context.eventName === "pull_request_review_comment") {
return true
}
const payload = context.payload as IssueCommentEvent
return Boolean((payload as any).issue?.pull_request)
}
@ -486,8 +501,9 @@ type ForgejoRepoInfo = {
async function createComment(): Promise<ForgejoComment> {
const context = useContext()
const payload = context.payload as IssueCommentEvent
const issueIndex = (payload.issue as any).index ?? payload.issue.number
const p = context.payload as any
const target = context.eventName === "pull_request_review" ? p.pull_request : p.issue
const issueIndex = target.index ?? target.number
console.log("Creating comment...")
return await forgejoFetch<ForgejoComment>(
@ -522,8 +538,8 @@ async function fetchPR(): Promise<ForgejoPullRequest & {
reviewComments: ForgejoReviewComment[]
}> {
const context = useContext()
const payload = context.payload as IssueCommentEvent
const prNumber = payload.issue.number
const p = context.payload as any
const prNumber = (context.eventName === "pull_request_review" ? p.pull_request.number : p.issue.number) as number
console.log("Fetching prompt data for PR #", prNumber)
// 1. Get PR info
@ -910,21 +926,29 @@ async function chat(text: string, files: PromptFiles = []) {
async function getUserPrompt(): Promise<{ userPrompt: string; promptFiles: PromptFiles }> {
const context = useContext()
const payload = context.payload as IssueCommentEvent | PullRequestReviewCommentEvent
const p = context.payload as any
const reviewContext = getReviewCommentContext()
const isReviewSubmission = context.eventName === "pull_request_review"
const reviewState: string | undefined = isReviewSubmission ? p.review?.state : undefined
let prompt = (() => {
const body = payload.comment.body.trim()
const body = getTriggerBody().trim()
if (body === "/opencode" || body === "/oc") {
if (reviewContext) {
return `Review this code change and suggest improvements for the commented lines:\n\nFile: ${reviewContext.file}\nLines: ${reviewContext.line}\n\n${reviewContext.diffHunk}`
}
if (isReviewSubmission) {
return `Address the feedback from this pull request review (state: ${reviewState ?? "unknown"}).`
}
return "Summarize this thread"
}
if (body.includes("/opencode") || body.includes("/oc")) {
if (reviewContext) {
return `${body}\n\nContext: You are reviewing a comment on file "${reviewContext.file}" at line ${reviewContext.line}.\n\nDiff context:\n${reviewContext.diffHunk}`
}
if (isReviewSubmission) {
return `${body}\n\nContext: This was submitted as part of a pull request review (state: ${reviewState ?? "unknown"}).`
}
return body
}
throw new Error("Comments must mention /opencode or /oc")