Skip to content

Commit 8ec4b51

Browse files
committed
fix(reviewer-bot): clarify /release self vs triage usage
1 parent 3f1ae80 commit 8ec4b51

2 files changed

Lines changed: 88 additions & 11 deletions

File tree

.github/reviewer-bot-tests/test_reviewer_bot.py

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,20 @@ def test_parse_command_malformed_unknown():
191191
assert args == ["greetings"]
192192

193193

194+
@pytest.mark.parametrize(
195+
("guidance_builder", "builder_args"),
196+
[
197+
(reviewer_bot.get_issue_guidance, ("alice", "bob")),
198+
(reviewer_bot.get_fls_audit_guidance, ("alice", "bob")),
199+
(reviewer_bot.get_pr_guidance, ("alice", "bob")),
200+
],
201+
)
202+
def test_guidance_release_commands_are_explicit(guidance_builder, builder_args):
203+
guidance = guidance_builder(*builder_args)
204+
assert "@guidelines-bot /release [reason]" in guidance
205+
assert "@guidelines-bot /release @username [reason]" in guidance
206+
207+
194208
def test_github_api_error_handling(monkeypatch):
195209
class FakeResponse:
196210
def __init__(self, status_code, content):
@@ -426,7 +440,10 @@ def test_handle_comment_event_commands_command(stub_api, captured_comments):
426440
handled = reviewer_bot.handle_comment_event(state)
427441
assert handled is False
428442
assert len(captured_comments) == 1
429-
assert "Available Commands" in captured_comments[0]["body"]
443+
response = captured_comments[0]["body"]
444+
assert "Available Commands" in response
445+
assert "@guidelines-bot /release [reason]" in response
446+
assert "@guidelines-bot /release @username [reason]" in response
430447

431448

432449
def test_handle_comment_event_away_command(stub_api, captured_comments, monkeypatch):
@@ -462,6 +479,49 @@ def test_handle_comment_event_release_command_self(stub_api, captured_comments,
462479
assert "has released" in captured_comments[0]["body"]
463480

464481

482+
def test_handle_comment_event_release_command_self_not_current_suggests_target(
483+
stub_api, captured_comments, monkeypatch
484+
):
485+
state = make_state()
486+
state["active_reviews"]["42"] = {
487+
"skipped": [],
488+
"current_reviewer": "alice",
489+
"assignment_method": "round-robin",
490+
}
491+
monkeypatch.setattr(reviewer_bot, "get_issue_assignees", lambda *args, **kwargs: ["alice"])
492+
os.environ["COMMENT_BODY"] = "@guidelines-bot /release"
493+
os.environ["COMMENT_AUTHOR"] = "bob"
494+
os.environ["ISSUE_NUMBER"] = "42"
495+
496+
handled = reviewer_bot.handle_comment_event(state)
497+
498+
assert handled is False
499+
assert len(captured_comments) == 1
500+
response = captured_comments[0]["body"]
501+
assert "@bob is not the current reviewer" in response
502+
assert "Current reviewer: @alice" in response
503+
assert "@guidelines-bot /release @alice" in response
504+
assert "triage+ required" in response
505+
506+
507+
def test_handle_release_command_self_not_assigned_uses_single_assignee_hint(stub_api, monkeypatch):
508+
state = make_state()
509+
monkeypatch.setattr(reviewer_bot, "get_issue_assignees", lambda *args, **kwargs: ["alice"])
510+
511+
response, success = reviewer_bot.handle_release_command(
512+
state=state,
513+
issue_number=42,
514+
comment_author="bob",
515+
args=[],
516+
)
517+
518+
assert success is False
519+
assert "@bob is not assigned to this issue/PR" in response
520+
assert "Current assignee(s): @alice" in response
521+
assert "@guidelines-bot /release @alice" in response
522+
assert "triage+ required" in response
523+
524+
465525
def test_handle_comment_event_release_command_other_requires_permission(
466526
stub_api, captured_comments, monkeypatch
467527
):

scripts/reviewer_bot.py

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,12 @@
2020
- Assign yourself as the reviewer for this issue/PR
2121
- Removes any existing reviewer assignment
2222
23-
@guidelines-bot /release [@username] [reason]
24-
- Release your assignment from this issue/PR (or someone else's with triage+ permission)
23+
@guidelines-bot /release [reason]
24+
- Release your own assignment from this issue/PR
25+
- Leaves this issue/PR unassigned
26+
27+
@guidelines-bot /release @username [reason]
28+
- Release someone else's assignment from this issue/PR (triage+ required)
2529
- Does NOT auto-assign the next reviewer (use /pass for that)
2630
2731
@guidelines-bot /rectify
@@ -96,7 +100,7 @@
96100
COMMANDS = {
97101
"pass": "Pass this review to next in queue",
98102
"away": "Step away from queue until date (YYYY-MM-DD)",
99-
"release": "Release assignment (yours, or @username with triage+ permission)",
103+
"release": "Release your assignment (/release) or another's (/release @username, triage+)",
100104
"rectify": "Reconcile this issue/PR's review state from GitHub",
101105
"claim": "Claim this review for yourself",
102106
"r?": "Assign a reviewer (@username or 'producers')",
@@ -673,7 +677,8 @@ def get_issue_guidance(reviewer: str, issue_author: str) -> str:
673677
If you need to pass this review:
674678
- `{BOT_MENTION} /pass [reason]` - Pass just this issue to the next reviewer
675679
- `{BOT_MENTION} /away YYYY-MM-DD [reason]` - Step away from the queue until a date
676-
- `{BOT_MENTION} /release [@username] [reason]` - Release assignment (yours or someone else's with triage+ permission)
680+
- `{BOT_MENTION} /release [reason]` - Release your own assignment and leave this issue unassigned
681+
- `{BOT_MENTION} /release @username [reason]` - Release another reviewer's assignment (triage+ required)
677682
678683
To assign someone else:
679684
- `{BOT_MENTION} /r? @username` - Assign a specific reviewer
@@ -709,7 +714,8 @@ def get_fls_audit_guidance(reviewer: str, issue_author: str) -> str:
709714
If you need to pass this review:
710715
- `{BOT_MENTION} /pass [reason]` - Pass just this issue to the next reviewer
711716
- `{BOT_MENTION} /away YYYY-MM-DD [reason]` - Step away from the queue until a date
712-
- `{BOT_MENTION} /release [@username] [reason]` - Release assignment (yours or someone else's with triage+ permission)
717+
- `{BOT_MENTION} /release [reason]` - Release your own assignment and leave this issue unassigned
718+
- `{BOT_MENTION} /release @username [reason]` - Release another reviewer's assignment (triage+ required)
713719
714720
To assign someone else:
715721
- `{BOT_MENTION} /r? @username` - Assign a specific reviewer
@@ -753,7 +759,8 @@ def get_pr_guidance(reviewer: str, pr_author: str) -> str:
753759
If you need to pass this review:
754760
- `{BOT_MENTION} /pass [reason]` - Pass just this PR to the next reviewer
755761
- `{BOT_MENTION} /away YYYY-MM-DD [reason]` - Step away from the queue until a date
756-
- `{BOT_MENTION} /release [@username] [reason]` - Release assignment (yours or someone else's with triage+ permission)
762+
- `{BOT_MENTION} /release [reason]` - Release your own assignment and leave this PR unassigned
763+
- `{BOT_MENTION} /release @username [reason]` - Release another reviewer's assignment (triage+ required)
757764
758765
To assign someone else:
759766
- `{BOT_MENTION} /r? @username` - Assign a specific reviewer
@@ -1437,7 +1444,8 @@ def handle_commands_command() -> tuple[str, bool]:
14371444
f"**Pass or step away:**\n"
14381445
f"- `{BOT_MENTION} /pass [reason]` - Pass this review to next in queue (current reviewer only)\n"
14391446
f"- `{BOT_MENTION} /away YYYY-MM-DD [reason]` - Step away from queue until a date\n"
1440-
f"- `{BOT_MENTION} /release [@username] [reason]` - Release assignment (yours or someone else's with triage+ permission)\n\n"
1447+
f"- `{BOT_MENTION} /release [reason]` - Release your own assignment and leave this unassigned\n"
1448+
f"- `{BOT_MENTION} /release @username [reason]` - Release another reviewer's assignment (triage+ required)\n\n"
14411449
f"**Assign reviewers:**\n"
14421450
f"- `{BOT_MENTION} /r? @username` - Assign a specific reviewer\n"
14431451
f"- `{BOT_MENTION} /r? producers` - Request the next reviewer from the queue\n"
@@ -1572,10 +1580,19 @@ def handle_release_command(state: dict, issue_number: int,
15721580
# Trying to release self when not assigned
15731581
if tracked_reviewer:
15741582
return (f"❌ @{comment_author} is not the current reviewer. "
1575-
f"Current reviewer: @{tracked_reviewer}"), False
1583+
f"Current reviewer: @{tracked_reviewer}\n\n"
1584+
f"If you meant to release @{tracked_reviewer}, use "
1585+
f"`{BOT_MENTION} /release @{tracked_reviewer}` "
1586+
f"(triage+ required)."), False
15761587
elif current_assignees:
1577-
return (f"❌ @{comment_author} is not assigned to this issue/PR. "
1578-
f"Current assignee(s): @{', @'.join(current_assignees)}"), False
1588+
response = (f"❌ @{comment_author} is not assigned to this issue/PR. "
1589+
f"Current assignee(s): @{', @'.join(current_assignees)}")
1590+
if len(current_assignees) == 1:
1591+
current_assignee = current_assignees[0]
1592+
response += (f"\n\nIf you meant to release @{current_assignee}, use "
1593+
f"`{BOT_MENTION} /release @{current_assignee}` "
1594+
f"(triage+ required).")
1595+
return response, False
15791596
else:
15801597
return "❌ No reviewer is currently assigned to release.", False
15811598

0 commit comments

Comments
 (0)