From 7416df88c93308aba256ba8e9e1ef1ede52e154e Mon Sep 17 00:00:00 2001 From: Nirav Patel Date: Tue, 18 Aug 2026 23:52:43 -0400 Subject: [PATCH] feat: pull PR commits for Co-Authored-By attribution on PR reviews PR webhooks only carry title/body; fetch /pulls/{i}/commits so the trailer ledger and per-agent digests attribute PR reviews correctly. Co-Authored-By: Claude Fable 5 --- src/lib/gitea.js | 4 ++++ src/lib/review.js | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/lib/gitea.js b/src/lib/gitea.js index 0e69b5c..7a8fcd1 100644 --- a/src/lib/gitea.js +++ b/src/lib/gitea.js @@ -65,6 +65,10 @@ export class GiteaClient { }); } + getPrCommits(owner, repo, index) { + return this.req('GET', `/api/v1/repos/${owner}/${repo}/pulls/${index}/commits?limit=50`); + } + getCommit(owner, repo, sha) { return this.req('GET', `/api/v1/repos/${owner}/${repo}/git/commits/${sha}?stat=false&verification=false&files=false`); } diff --git a/src/lib/review.js b/src/lib/review.js index 20e13b2..8af01b1 100644 --- a/src/lib/review.js +++ b/src/lib/review.js @@ -19,6 +19,18 @@ export async function runReview({ cfg, gitea, db, job, withGlobal, log }) { const dashboardUrl = `${cfg.publicBaseUrl}/review/${owner}/${repo}`; const t0 = Date.now(); + // For PR events the webhook only carries title/body; pull the PR's commits + // so Co-Authored-By trailer attribution sees real commit messages. + if (job.prIndex) { + const commits = await safe(log, 'pr-commits', () => gitea.getPrCommits(owner, repo, job.prIndex)); + if (Array.isArray(commits)) { + job.commitMessages = job.commitMessages.concat( + commits.map(c => c?.commit?.message || '').filter(Boolean)); + const names = commits.map(c => c?.commit?.author?.name || c?.author?.login).filter(Boolean); + job.authors = [...new Set(job.authors.concat(names))]; + } + } + // 0. pending status (best-effort) await safe(log, 'pending-status', () => gitea.postStatus(owner, repo, sha, {