Skip to content

Commit 8edcb28

Browse files
authored
Update script to ping only on waiting-for-author label (microsoft#4812)
* update script to ping only on certain waiting for author label * Update .github/scripts/stale_issue_pr_ping.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update .github/scripts/stale_issue_pr_ping.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix docstring --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 81e2336 commit 8edcb28

2 files changed

Lines changed: 30 additions & 17 deletions

File tree

‎.github/scripts/stale_issue_pr_ping.py‎

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
# Copyright (c) Microsoft. All rights reserved.
22

3-
"""Scan open issues and PRs for stale follow-ups from external authors.
3+
"""Scan open issues and PRs labeled 'waiting-for-author' for stale follow-ups.
44
5-
If a team member commented and the external author hasn't replied within
6-
DAYS_THRESHOLD days, post a reminder comment and add the 'needs-info' label.
5+
Team members manually add the 'waiting-for-author' label when they need a
6+
response from the external author. If the author hasn't replied within
7+
DAYS_THRESHOLD days of the last team comment, post a reminder and add the
8+
'requested-info' label to prevent duplicate pings.
79
"""
810

911
from __future__ import annotations
@@ -22,7 +24,8 @@
2224
"@{author}, friendly reminder — this issue is waiting on your response. "
2325
"Please share any updates when you get a chance. (This is an automated message.)"
2426
)
25-
LABEL = "needs-info"
27+
TRIGGER_LABEL = "waiting-for-author"
28+
PINGED_LABEL = "requested-info"
2629

2730

2831
def get_team_members(g: Github, org: str, team_slug: str) -> set[str]:
@@ -76,15 +79,21 @@ def should_ping(
7679
days_threshold: int,
7780
now: datetime,
7881
) -> bool:
79-
"""Determine whether this issue/PR should be pinged."""
82+
"""Determine whether this issue/PR should be pinged.
83+
84+
Only issues/PRs carrying the 'waiting-for-author' label are candidates.
85+
"""
8086
author = issue.user.login
8187

88+
# Skip if the trigger label is not present
89+
if not any(label.name == TRIGGER_LABEL for label in issue.labels):
90+
return False
8291
# Skip if author is a team member
8392
if author in team_members:
8493
return False
8594

86-
# Skip if already labeled
87-
if any(label.name == LABEL for label in issue.labels):
95+
# Skip if already pinged
96+
if any(label.name == PINGED_LABEL for label in issue.labels):
8897
return False
8998

9099
# Skip if no comments at all
@@ -112,7 +121,7 @@ def should_ping(
112121

113122

114123
def ping(issue: Issue, dry_run: bool) -> bool:
115-
"""Post a reminder comment and add the needs-info label. Returns True on success."""
124+
"""Post a reminder comment and add the 'requested-info' label. Returns True on success."""
116125
author = issue.user.login
117126
kind = "PR" if issue.pull_request else "Issue"
118127

@@ -129,7 +138,7 @@ def ping(issue: Issue, dry_run: bool) -> bool:
129138
issue.create_comment(PING_COMMENT.format(author=author))
130139
commented = True
131140
if not labeled:
132-
issue.add_to_labels(LABEL)
141+
issue.add_to_labels(PINGED_LABEL)
133142
labeled = True
134143
print(f" Pinged {kind} #{issue.number} (@{author})")
135144
return True
@@ -184,9 +193,9 @@ def main() -> None:
184193
failed = []
185194
scanned = 0
186195

187-
print(f"Scanning open issues and PRs (threshold: {days_threshold} days)...\n")
196+
print(f"Scanning open issues and PRs labeled '{TRIGGER_LABEL}' (threshold: {days_threshold} days)...\n")
188197

189-
for issue in repo.get_issues(state="open"):
198+
for issue in repo.get_issues(state="open", labels=[TRIGGER_LABEL]):
190199
scanned += 1
191200

192201
if should_ping(issue, team_members, days_threshold, now):

‎.github/tests/test_stale_issue_pr_ping.py‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "scripts"))
1616

1717
from stale_issue_pr_ping import (
18-
LABEL,
18+
PINGED_LABEL,
1919
PING_COMMENT,
20+
TRIGGER_LABEL,
2021
author_replied_after,
2122
find_last_team_comment,
2223
get_team_members,
@@ -63,7 +64,10 @@ def _make_issue(
6364
issue.user = MagicMock()
6465
issue.user.login = author
6566
issue.number = number
66-
issue.labels = [_make_label(n) for n in (labels or [])]
67+
# Default to having the trigger label, since the API query pre-filters.
68+
if labels is None:
69+
labels = [TRIGGER_LABEL]
70+
issue.labels = [_make_label(n) for n in labels]
6771
issue.comments = comment_count
6872
issue.pull_request = MagicMock() if pull_request else None
6973
if comments is not None:
@@ -136,11 +140,11 @@ def test_should_ping_stale_issue(self):
136140
assert should_ping(issue, TEAM, 4, NOW) is True
137141

138142
def test_skip_team_member_author(self):
139-
issue = _make_issue(author="alice", comment_count=1)
143+
issue = _make_issue(author="alice", labels=[TRIGGER_LABEL], comment_count=1)
140144
assert should_ping(issue, TEAM, 4, NOW) is False
141145

142-
def test_skip_already_labeled(self):
143-
issue = _make_issue(labels=[LABEL], comment_count=1)
146+
def test_skip_already_pinged(self):
147+
issue = _make_issue(labels=[TRIGGER_LABEL, PINGED_LABEL], comment_count=1)
144148
assert should_ping(issue, TEAM, 4, NOW) is False
145149

146150
def test_skip_no_comments(self):
@@ -194,7 +198,7 @@ def test_success(self, capsys):
194198
issue = _make_issue()
195199
assert ping(issue, dry_run=False) is True
196200
issue.create_comment.assert_called_once()
197-
issue.add_to_labels.assert_called_once_with(LABEL)
201+
issue.add_to_labels.assert_called_once_with(PINGED_LABEL)
198202

199203
@patch("stale_issue_pr_ping.time.sleep")
200204
def test_retry_on_failure(self, mock_sleep):

0 commit comments

Comments
 (0)