Skip to content

Commit bcda4ca

Browse files
committed
Update
[ghstack-poisoned]
1 parent 02ad0c3 commit bcda4ca

2 files changed

Lines changed: 68 additions & 15 deletions

File tree

greenlight/src/greenlight/github_client.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ def fingerprint_pr(
308308
REVIEW_EVENT_COMMENT = "COMMENT"
309309
_REVIEW_EVENTS: frozenset[str] = frozenset({REVIEW_EVENT_APPROVE, REVIEW_EVENT_REQUEST_CHANGES, REVIEW_EVENT_COMMENT})
310310
_REVIEW_STATE_APPROVED = "APPROVED"
311+
_REVIEW_STATE_COMMENTED = "COMMENTED"
311312

312313

313314
def get_pr(client: VerdictClient, repo: str, number: int) -> VerdictPR:
@@ -365,31 +366,34 @@ def upsert_issue_comment(
365366
pr.create_issue_comment(body)
366367

367368

368-
def _iter_greenlight_approvals(pr: VerdictPR, bot_login: str) -> Iterator[_VerdictReview]:
369-
"""Yield each live APPROVED review authored by ``bot_login`` -- greenlight's own approvals.
369+
def _iter_greenlight_reviews(pr: VerdictPR, bot_login: str) -> Iterator[_VerdictReview]:
370+
"""Yield every review authored by ``bot_login`` (any state) -- greenlight's own reviews.
370371
371-
The login is passed in (the greenlight GitHub App's ``<slug>[bot]`` account) rather than read
372-
via ``get_user``, which an App installation token cannot call. Null-user, empty-login, and
373-
non-APPROVED reviews are skipped; the login match is case-insensitive.
372+
The login is passed in (the greenlight App's ``<slug>[bot]`` account) since an App token
373+
cannot call ``get_user``. Null-user and empty-login reviews are skipped; match is case-insensitive.
374374
"""
375375
target = bot_login.lower()
376376
for review in pr.get_reviews():
377377
user = review.user
378-
if user is None or not user.login:
379-
continue
380-
if user.login.lower() == target and review.state == _REVIEW_STATE_APPROVED:
378+
if user is not None and user.login and user.login.lower() == target:
381379
yield review
382380

383381

384382
def has_live_greenlight_approval(pr: VerdictPR, *, bot_login: str) -> bool:
385-
"""Return True iff ``bot_login`` has at least one live (undismissed) APPROVED review on ``pr``."""
386-
return next(_iter_greenlight_approvals(pr, bot_login), None) is not None
383+
"""Return True iff greenlight's latest non-COMMENTED review on ``pr`` is APPROVED.
384+
385+
Mirrors trymerge's approver rule (latest non-COMMENTED state per login wins), so a stale
386+
APPROVED behind a newer DISMISSED never reads as approved. Assumes ``get_reviews()`` is oldest-first.
387+
"""
388+
states = [r.state for r in _iter_greenlight_reviews(pr, bot_login) if r.state != _REVIEW_STATE_COMMENTED]
389+
return bool(states) and states[-1] == _REVIEW_STATE_APPROVED
387390

388391

389392
def dismiss_prior_greenlight_approvals(pr: VerdictPR, *, bot_login: str, message: str) -> list[int]:
390-
"""Dismiss every prior APPROVED review authored by ``bot_login`` (see ``_iter_greenlight_approvals``)."""
393+
"""Dismiss every prior APPROVED review authored by ``bot_login`` (see ``_iter_greenlight_reviews``)."""
391394
dismissed: list[int] = []
392-
for review in _iter_greenlight_approvals(pr, bot_login):
393-
review.dismiss(message)
394-
dismissed.append(review.id)
395+
for review in _iter_greenlight_reviews(pr, bot_login):
396+
if review.state == _REVIEW_STATE_APPROVED:
397+
review.dismiss(message)
398+
dismissed.append(review.id)
395399
return dismissed

greenlight/tests/test_github_client.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1365,7 +1365,7 @@ def test_has_live_greenlight_approval_false_for_commented_and_dismissed():
13651365
assert github_client.has_live_greenlight_approval(pr, bot_login="greenlight-app[bot]") is False
13661366

13671367

1368-
def test_has_live_greenlight_approval_true_when_any_own_approved_among_many():
1368+
def test_has_live_greenlight_approval_true_when_latest_non_commented_approved():
13691369
reviews = [
13701370
_FakeVerdictReview(1, _FakeActor("alice"), "APPROVED"),
13711371
_FakeVerdictReview(2, _FakeActor("greenlight-app[bot]"), "COMMENTED"),
@@ -1374,3 +1374,52 @@ def test_has_live_greenlight_approval_true_when_any_own_approved_among_many():
13741374
pr = _FakeVerdictPR(reviews=reviews)
13751375

13761376
assert github_client.has_live_greenlight_approval(pr, bot_login="greenlight-app[bot]") is True
1377+
1378+
1379+
def test_has_live_greenlight_approval_false_when_approved_then_dismissed():
1380+
reviews = [
1381+
_FakeVerdictReview(1, _FakeActor("greenlight-app[bot]"), "APPROVED"),
1382+
_FakeVerdictReview(2, _FakeActor("greenlight-app[bot]"), "DISMISSED"),
1383+
]
1384+
pr = _FakeVerdictPR(reviews=reviews)
1385+
1386+
# trymerge collapses greenlight to its latest non-COMMENTED state (DISMISSED), so it would
1387+
# not count greenlight as an approver; an older APPROVED must not read as a live approval.
1388+
assert github_client.has_live_greenlight_approval(pr, bot_login="greenlight-app[bot]") is False
1389+
1390+
1391+
def test_has_live_greenlight_approval_true_when_dismissed_then_approved():
1392+
reviews = [
1393+
_FakeVerdictReview(1, _FakeActor("greenlight-app[bot]"), "DISMISSED"),
1394+
_FakeVerdictReview(2, _FakeActor("greenlight-app[bot]"), "APPROVED"),
1395+
]
1396+
pr = _FakeVerdictPR(reviews=reviews)
1397+
1398+
assert github_client.has_live_greenlight_approval(pr, bot_login="greenlight-app[bot]") is True
1399+
1400+
1401+
def test_has_live_greenlight_approval_true_when_commented_after_approved():
1402+
reviews = [
1403+
_FakeVerdictReview(1, _FakeActor("greenlight-app[bot]"), "APPROVED"),
1404+
_FakeVerdictReview(2, _FakeActor("greenlight-app[bot]"), "COMMENTED"),
1405+
]
1406+
pr = _FakeVerdictPR(reviews=reviews)
1407+
1408+
assert github_client.has_live_greenlight_approval(pr, bot_login="greenlight-app[bot]") is True
1409+
1410+
1411+
def test_has_live_greenlight_approval_false_when_latest_changes_requested():
1412+
reviews = [
1413+
_FakeVerdictReview(1, _FakeActor("greenlight-app[bot]"), "APPROVED"),
1414+
_FakeVerdictReview(2, _FakeActor("greenlight-app[bot]"), "CHANGES_REQUESTED"),
1415+
]
1416+
pr = _FakeVerdictPR(reviews=reviews)
1417+
1418+
assert github_client.has_live_greenlight_approval(pr, bot_login="greenlight-app[bot]") is False
1419+
1420+
1421+
def test_has_live_greenlight_approval_false_when_only_other_author_approved():
1422+
reviews = [_FakeVerdictReview(1, _FakeActor("alice"), "APPROVED")]
1423+
pr = _FakeVerdictPR(reviews=reviews)
1424+
1425+
assert github_client.has_live_greenlight_approval(pr, bot_login="greenlight-app[bot]") is False

0 commit comments

Comments
 (0)