Skip to content

Commit ac034d9

Browse files
fix(pr-review): do not restart completed reviews on delayed submitted events (#647)
Recognize the review a submitted delivery reports as completion even when it predates the latest review_requested event, let a newer verdict on the same head supersede it, and ignore dismissed reviews. Re-applied on current main; bundle 1.9.1. Closes #646.
1 parent c8bfeaa commit ac034d9

5 files changed

Lines changed: 246 additions & 21 deletions

File tree

‎automations/bundle-index.js‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎automations/catalog/github-pr-reviewer/manifest.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"id": "github-pr-reviewer",
3-
"version": "1.9.0",
3+
"version": "1.9.1",
44
"name": "GitHub code review",
55
"category": "Code review",
66
"description": "Review requested pull-request heads, resume an outstanding reviewer request on a schedule once its checks are green, classify all open non-draft pull requests that nobody requested and review eligible green heads, drain the backlog oldest-first under a small per-scan new-conversation bound, record exact-head decisions, stop early on out-of-scope changes, and optionally request a code-aware human maintainer after approval or a maintainer-decision scope stop.",
@@ -135,7 +135,7 @@
135135
}
136136
},
137137
"bundle": {
138-
"version": "1.9.0",
138+
"version": "1.9.1",
139139
"entrypoint": "python3 worker.py",
140140
"timeout": 300,
141141
"files": {

‎skills/github-pr-reviewer/scripts/worker.py‎

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -283,30 +283,55 @@ def _prompt(self, pr, trigger, label=None, delivery_key=None):
283283
f"second result.{self_review_note}"
284284
)
285285

286-
def _finish_completed_review(self, pr, trigger, label=None):
286+
def _finish_completed_review(self, pr, trigger, label=None, submitted_review=None):
287287
"""Complete an exact-head review, including an optional human handoff.
288288
289289
`trigger` is the event the current work is keyed on. It is None for an
290290
unrequested scheduled-scan PR, which has no trigger event: the head SHA
291291
is the whole key, so any submitted review by this account on the current
292292
head is the completion of that work. That is what lets an unrequested
293293
review the scan started be reconciled and handed off on a later scan
294-
instead of being restarted.
294+
instead of being restarted. `submitted_review` is the review a
295+
`submitted` delivery reports. It can predate the latest
296+
`review_requested` event, so it is found by id rather than by the
297+
trigger window; this account's later reviews of the head still count, so
298+
a newer verdict supersedes it. A dismissed review completes nothing.
295299
"""
296300
head_sha = pr["head"]["sha"]
297301
if trigger is not None:
298302
triggered_at = trigger.get("created_at") or ""
299303
else:
300304
triggered_at = ""
301305
reviews = self.gh_pages(f"/pulls/{pr['number']}/reviews")
302-
completed = [
306+
mine = [
303307
review
304308
for review in reviews
305309
if review.get("commit_id") == head_sha
306310
and ((review.get("user") or {}).get("login") or "").lower()
307311
== self.github_login.lower()
308-
and (review.get("submitted_at") or "") > triggered_at
312+
and (review.get("state") or "").upper() != "DISMISSED"
309313
]
314+
if submitted_review and submitted_review.get("id") is not None:
315+
reported = next(
316+
(review for review in mine if review.get("id") == submitted_review["id"]),
317+
None,
318+
)
319+
reported_at = (reported or {}).get("submitted_at") or ""
320+
completed = (
321+
[]
322+
if reported is None
323+
else [
324+
review
325+
for review in mine
326+
if (review.get("submitted_at") or "") >= reported_at
327+
]
328+
)
329+
else:
330+
completed = [
331+
review
332+
for review in mine
333+
if (review.get("submitted_at") or "") > triggered_at
334+
]
310335
if not completed:
311336
return False
312337
approved = None
@@ -858,6 +883,11 @@ def run(self):
858883
for candidate in prs:
859884
try:
860885
pr = self.gh("GET", f"/pulls/{candidate['number']}")
886+
submitted_review = (
887+
payload.get("review")
888+
if event_mode and payload.get("action") == "submitted"
889+
else None
890+
)
861891
has_label = label in {
862892
item["name"] for item in pr.get("labels", [])
863893
}
@@ -894,7 +924,11 @@ def run(self):
894924
delivery_key = self._unrequested_head(pr)
895925
unrequested_candidate = True
896926
if trigger is None and delivery_key is None:
897-
continue
927+
# A submitted review is its own completion signal: its
928+
# request can predate the issue-event window, and that
929+
# review must still be reconciled.
930+
if submitted_review is None:
931+
continue
898932
# A head this account already reviewed, with no clarifying
899933
# comment since, is done: another conversation would publish a
900934
# second review of identical code. This must come before the
@@ -918,7 +952,7 @@ def run(self):
918952
),
919953
flush=True,
920954
)
921-
if trigger is not None:
955+
if trigger is not None or submitted_review is not None:
922956
# Reconcile the completed review (clearing the label and
923957
# running the maintainer handoff) where the review is
924958
# this trigger's result. When it predates the trigger -
@@ -927,7 +961,7 @@ def run(self):
927961
# otherwise the label stays and every later scan re-reads
928962
# this head and re-logs with no effect.
929963
if not self._finish_completed_review(
930-
pr, trigger, trigger_label
964+
pr, trigger, trigger_label, submitted_review
931965
) and trigger_label:
932966
self.gh(
933967
"DELETE",
@@ -936,7 +970,7 @@ def run(self):
936970
)
937971
continue
938972
if delivery_key is None and self._finish_completed_review(
939-
pr, trigger, trigger_label
973+
pr, trigger, trigger_label, submitted_review
940974
):
941975
continue
942976
if event_mode and payload.get("action") == "submitted":

‎tests/fixtures/automations/github-pr-reviewer.json‎

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
"timeout": 300,
6969
"template": {
7070
"id": "github-pr-reviewer",
71-
"version": "1.9.0",
71+
"version": "1.9.1",
7272
"config": {
7373
"repos": [
7474
"OpenHands/agent-server-gui"
@@ -108,7 +108,7 @@
108108
"timeout": 300,
109109
"template": {
110110
"id": "github-pr-reviewer",
111-
"version": "1.9.0",
111+
"version": "1.9.1",
112112
"config": {
113113
"repos": [
114114
"OpenHands/agent-server-gui"
@@ -213,7 +213,7 @@
213213
"timeout": 300,
214214
"template": {
215215
"id": "github-pr-reviewer",
216-
"version": "1.9.0",
216+
"version": "1.9.1",
217217
"config": {
218218
"repos": [
219219
"OpenHands/agent-server-gui",
@@ -254,7 +254,7 @@
254254
"timeout": 300,
255255
"template": {
256256
"id": "github-pr-reviewer",
257-
"version": "1.9.0",
257+
"version": "1.9.1",
258258
"config": {
259259
"repos": [
260260
"OpenHands/agent-server-gui",
@@ -296,7 +296,7 @@
296296
"preset_metadata": {
297297
"template": {
298298
"id": "github-pr-reviewer",
299-
"version": "1.9.0",
299+
"version": "1.9.1",
300300
"config": {
301301
"repos": [
302302
"OpenHands/agent-server-gui",
@@ -351,7 +351,7 @@
351351
"timeout": 300,
352352
"template": {
353353
"id": "github-pr-reviewer",
354-
"version": "1.9.0",
354+
"version": "1.9.1",
355355
"config": {
356356
"repos": [
357357
"OpenHands/agent-server-gui"
@@ -444,7 +444,7 @@
444444
"timeout": 300,
445445
"template": {
446446
"id": "github-pr-reviewer",
447-
"version": "1.9.0",
447+
"version": "1.9.1",
448448
"config": {
449449
"repos": [
450450
"OpenHands/agent-server-gui"
@@ -540,7 +540,7 @@
540540
"timeout": 300,
541541
"template": {
542542
"id": "github-pr-reviewer",
543-
"version": "1.9.0",
543+
"version": "1.9.1",
544544
"config": {
545545
"repos": [
546546
"OpenHands/agent-server-gui"
@@ -616,7 +616,7 @@
616616
"timeout": 300,
617617
"template": {
618618
"id": "github-pr-reviewer",
619-
"version": "1.9.0",
619+
"version": "1.9.1",
620620
"config": {
621621
"repos": [
622622
"OpenHands/automation"

0 commit comments

Comments
 (0)