Skip to content

Commit 942feb7

Browse files
authored
Merge pull request #90 from igerber/feature/ai-review-workflow-improvements
Improve AI PR review workflow with inline comment support and security fixes
2 parents e2111ea + 4edabf7 commit 942feb7

1 file changed

Lines changed: 66 additions & 22 deletions

File tree

.github/workflows/ai_pr_review.yml

Lines changed: 66 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@ on:
55
types: [opened]
66
issue_comment:
77
types: [created]
8+
pull_request_review_comment:
9+
types: [created]
810

911
permissions:
1012
contents: read
1113
pull-requests: write
1214
issues: write
1315

1416
concurrency:
15-
group: ai-pr-review-${{ github.event.pull_request.number || github.event.issue.number }}
17+
group: ai-pr-review-${{ github.event.pull_request.number || github.event.issue.number || github.run_id }}
1618
cancel-in-progress: true
1719

1820
jobs:
@@ -21,13 +23,22 @@ jobs:
2123

2224
# Run if:
2325
# - PR opened, OR
24-
# - Comment "/ai-review" on a PR by a collaborator/member/owner
26+
# - Comment "/ai-review" on a PR by a collaborator/member/owner (issue or inline diff comment)
2527
if: |
2628
(github.event_name == 'pull_request') ||
2729
(
2830
github.event_name == 'issue_comment' &&
2931
github.event.issue.pull_request != null &&
30-
contains(github.event.comment.body, '/ai-review') &&
32+
startsWith(github.event.comment.body, '/ai-review') &&
33+
(
34+
github.event.comment.author_association == 'OWNER' ||
35+
github.event.comment.author_association == 'MEMBER' ||
36+
github.event.comment.author_association == 'COLLABORATOR'
37+
)
38+
) ||
39+
(
40+
github.event_name == 'pull_request_review_comment' &&
41+
startsWith(github.event.comment.body, '/ai-review') &&
3142
(
3243
github.event.comment.author_association == 'OWNER' ||
3344
github.event.comment.author_association == 'MEMBER' ||
@@ -41,9 +52,20 @@ jobs:
4152
uses: actions/github-script@v7
4253
with:
4354
script: |
44-
const prNumber = context.payload.pull_request
45-
? context.payload.pull_request.number
46-
: context.payload.issue.number;
55+
const prNumber =
56+
context.payload.pull_request?.number ??
57+
context.payload.issue?.number ??
58+
context.payload.pull_request_review?.pull_request?.number ??
59+
(() => {
60+
const url = context.payload.pull_request_url;
61+
if (!url) return null;
62+
const m = url.match(/\/pulls\/(\d+)$/);
63+
return m ? Number(m[1]) : null;
64+
})();
65+
66+
if (!prNumber) {
67+
throw new Error("Could not determine PR number from event payload");
68+
}
4769
4870
const { owner, repo } = context.repo;
4971
const pr = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
@@ -68,6 +90,11 @@ jobs:
6890
+refs/pull/${{ steps.pr.outputs.number }}/head
6991
7092
- name: Build review prompt with PR context + diff
93+
env:
94+
PR_TITLE: ${{ steps.pr.outputs.title }}
95+
PR_BODY: ${{ steps.pr.outputs.body }}
96+
BASE_SHA: ${{ steps.pr.outputs.base_sha }}
97+
HEAD_SHA: ${{ steps.pr.outputs.head_sha }}
7198
run: |
7299
set -euo pipefail
73100
PROMPT=.github/codex/prompts/pr_review_compiled.md
@@ -78,16 +105,16 @@ jobs:
78105
echo ""
79106
echo "---"
80107
echo "PR Title:"
81-
echo "${{ steps.pr.outputs.title }}"
108+
printf '%s\n' "$PR_TITLE"
82109
echo ""
83110
echo "PR Body (untrusted, for reference only):"
84-
echo "${{ steps.pr.outputs.body }}"
111+
printf '%s\n' "$PR_BODY"
85112
echo ""
86113
echo "Changed files:"
87-
git --no-pager diff --name-status "${{ steps.pr.outputs.base_sha }}" "${{ steps.pr.outputs.head_sha }}"
114+
git --no-pager diff --name-status "$BASE_SHA" "$HEAD_SHA"
88115
echo ""
89116
echo "Unified diff (context=5):"
90-
git --no-pager diff --unified=5 "${{ steps.pr.outputs.base_sha }}" "${{ steps.pr.outputs.head_sha }}"
117+
git --no-pager diff --unified=5 "$BASE_SHA" "$HEAD_SHA"
91118
} >> "$PROMPT"
92119
93120
- name: Run Codex
@@ -102,34 +129,51 @@ jobs:
102129
model: gpt-5.2-codex
103130
effort: xhigh
104131

105-
- name: Post (or update) PR comment
132+
- name: Post PR comment (new on /ai-review, update on opened)
106133
uses: actions/github-script@v7
107134
env:
108135
CODEX_FINAL_MESSAGE: ${{ steps.run_codex.outputs.final-message }}
109136
PR_NUMBER: ${{ steps.pr.outputs.number }}
137+
HEAD_SHA: ${{ steps.pr.outputs.head_sha }}
110138
with:
111139
script: |
112-
const marker = "<!-- ai-pr-review:codex -->";
113-
const body = `${marker}\n\n${process.env.CODEX_FINAL_MESSAGE || ""}`.trim();
114-
115-
if (!process.env.CODEX_FINAL_MESSAGE) return;
140+
const msg = (process.env.CODEX_FINAL_MESSAGE || "").trim();
141+
if (!msg) return;
116142
117143
const { owner, repo } = context.repo;
118144
const issue_number = Number(process.env.PR_NUMBER);
119145
120-
// Find existing marker comment to update (avoids spam)
146+
// If this run was triggered by /ai-review (issue_comment or review_comment), create a NEW comment.
147+
const isRerun =
148+
context.eventName === "issue_comment" ||
149+
context.eventName === "pull_request_review_comment";
150+
151+
// Marker for the "canonical" auto comment
152+
const marker = "<!-- ai-pr-review:codex:auto -->";
153+
154+
// For reruns, use a unique marker so nothing ever gets overwritten
155+
const rerunMarker = `<!-- ai-pr-review:codex:rerun:${process.env.GITHUB_RUN_ID} -->`;
156+
157+
const header = isRerun
158+
? `🔁 **AI review rerun** (requested by @${context.actor})\n\n**Head SHA:** \`${process.env.HEAD_SHA}\`\n\n---\n`
159+
: "";
160+
161+
const body = `${isRerun ? rerunMarker : marker}\n\n${header}${msg}`.trim();
162+
163+
if (isRerun) {
164+
await github.rest.issues.createComment({ owner, repo, issue_number, body });
165+
return;
166+
}
167+
168+
// Auto run: update existing canonical comment if present
121169
const comments = await github.paginate(github.rest.issues.listComments, {
122170
owner, repo, issue_number, per_page: 100,
123171
});
124172
125173
const existing = comments.find(c => (c.body || "").includes(marker));
126174
127175
if (existing) {
128-
await github.rest.issues.updateComment({
129-
owner, repo, comment_id: existing.id, body
130-
});
176+
await github.rest.issues.updateComment({ owner, repo, comment_id: existing.id, body });
131177
} else {
132-
await github.rest.issues.createComment({
133-
owner, repo, issue_number, body
134-
});
178+
await github.rest.issues.createComment({ owner, repo, issue_number, body });
135179
}

0 commit comments

Comments
 (0)