diff --git a/scripts/auto_close_needs_mre.py b/scripts/auto_close_needs_mre.py index a9185f584..240e83a01 100644 --- a/scripts/auto_close_needs_mre.py +++ b/scripts/auto_close_needs_mre.py @@ -19,6 +19,8 @@ from datetime import datetime, timedelta, timezone import httpx +MAINTAINER_AUTHOR_ASSOCIATIONS = {"OWNER", "MEMBER", "COLLABORATOR"} + @dataclass class Issue: @@ -31,6 +33,7 @@ class Issue: user_id: int user_login: str body: str | None + author_association: str @dataclass @@ -104,6 +107,7 @@ class GitHubClient: user_id=item["user"]["id"], user_login=item["user"]["login"], body=item.get("body"), + author_association=item.get("author_association", "NONE"), ) ) @@ -307,6 +311,10 @@ def should_close_as_needs_mre( timeline: list[dict], ) -> bool: """Determine if an issue should be closed for needing an MRE.""" + if issue.author_association in MAINTAINER_AUTHOR_ASSOCIATIONS: + print(f"Issue #{issue.number}: Skipping maintainer-authored issue") + return False + # Check if label is old enough (7 days) seven_days_ago = datetime.now(timezone.utc) - timedelta(days=7) diff --git a/tests/scripts/test_auto_close_needs_mre.py b/tests/scripts/test_auto_close_needs_mre.py new file mode 100644 index 000000000..8a4f089b3 --- /dev/null +++ b/tests/scripts/test_auto_close_needs_mre.py @@ -0,0 +1,68 @@ +from datetime import datetime, timedelta, timezone + +import pytest + +from scripts.auto_close_needs_mre import Comment, Issue, should_close_as_needs_mre + + +def make_issue(author_association: str = "NONE") -> Issue: + return Issue( + number=1, + title="Bug report", + state="open", + created_at="2026-01-01T00:00:00Z", + user_id=123, + user_login="octocat", + body="Something is broken", + author_association=author_association, + ) + + +@pytest.mark.parametrize( + "author_association", + ["OWNER", "MEMBER", "COLLABORATOR"], +) +def test_should_not_close_maintainer_issues(author_association: str): + label_date = datetime.now(timezone.utc) - timedelta(days=8) + + should_close = should_close_as_needs_mre( + issue=make_issue(author_association), + label_date=label_date, + comments=[], + timeline=[], + ) + + assert should_close is False + + +def test_should_close_non_maintainer_issue_without_author_activity(): + label_date = datetime.now(timezone.utc) - timedelta(days=8) + + should_close = should_close_as_needs_mre( + issue=make_issue("CONTRIBUTOR"), + label_date=label_date, + comments=[], + timeline=[], + ) + + assert should_close is True + + +def test_should_not_close_non_maintainer_issue_with_author_activity(): + label_date = datetime.now(timezone.utc) - timedelta(days=8) + comment = Comment( + id=1, + body="Here's the MRE", + created_at=(label_date + timedelta(days=1)).isoformat(), + user_id=123, + user_login="octocat", + ) + + should_close = should_close_as_needs_mre( + issue=make_issue("CONTRIBUTOR"), + label_date=label_date, + comments=[comment], + timeline=[], + ) + + assert should_close is False