Skip to content

Commit 93e18c4

Browse files
feat(issues): add rejection count badge (#6735)
1 parent 7347ce5 commit 93e18c4

2 files changed

Lines changed: 88 additions & 20 deletions

File tree

src/updater.py

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,18 @@
110110
JSON_EXTENSION = '.json'
111111
PNG_CONTENT_TYPE = 'image/png'
112112
APPROVE_THEME_LABEL = 'approve-theme'
113-
CONTRIBUTION_BADGE_LABEL = 'contributions'
114-
CONTRIBUTION_BADGE_STYLE = 'for-the-badge'
113+
ISSUE_AUTHOR_BADGE_STYLE = 'for-the-badge'
114+
ISSUE_AUTHOR_BADGES = {
115+
'contributions': {
116+
'label': 'contributions',
117+
'query_filters': (f'label:{APPROVE_THEME_LABEL}',),
118+
},
119+
'rejections': {
120+
'label': 'rejections',
121+
'query_filters': ('reason:not-planned',),
122+
'color': 'red',
123+
},
124+
}
115125
DEFAULT_GITHUB_REPOSITORY = 'LizardByte/ThemerrDB'
116126
REPLACEMENT_REQUEST_OPTION = 'This is a replacement request. If checked, please provide a reason below.'
117127
SAME_YOUTUBE_URL_CLOSE_MESSAGE = 'The YouTube url provided is the same as the current one.'
@@ -1053,11 +1063,15 @@ def _load_existing_item_data(item_file: str) -> dict:
10531063
return json.load(fp=og_f)
10541064

10551065

1056-
def _build_contribution_badge(author: Optional[str] = None, repository: Optional[str] = None) -> str:
1057-
"""Build a contribution-count badge for the issue author.
1066+
def _build_issue_author_badge(badge_type: str,
1067+
author: Optional[str] = None,
1068+
repository: Optional[str] = None) -> str:
1069+
"""Build an author-scoped issue-count badge.
10581070
10591071
Parameters
10601072
----------
1073+
badge_type : str
1074+
Badge config key from ISSUE_AUTHOR_BADGES.
10611075
author : str, optional
10621076
GitHub username to search for. Defaults to the issue author login.
10631077
repository : str, optional
@@ -1068,19 +1082,45 @@ def _build_contribution_badge(author: Optional[str] = None, repository: Optional
10681082
str
10691083
Markdown badge link, or an empty string when no author is available.
10701084
"""
1085+
badge_config = ISSUE_AUTHOR_BADGES[badge_type]
10711086
author = author or os.environ.get('ISSUE_AUTHOR_LOGIN', '')
10721087
if not author:
10731088
return ''
10741089

10751090
repository = repository or os.environ.get('GITHUB_REPOSITORY', DEFAULT_GITHUB_REPOSITORY)
1076-
query = f'repo:{repository} is:closed label:{APPROVE_THEME_LABEL} author:{author}'
1091+
label = badge_config['label']
1092+
query = ' '.join([
1093+
f'repo:{repository}',
1094+
'is:closed',
1095+
*badge_config['query_filters'],
1096+
f'author:{author}',
1097+
])
10771098
encoded_query = quote(query, safe='')
1078-
badge_url = (
1079-
'https://img.shields.io/github/issues-search?'
1080-
f'query={encoded_query}&style={CONTRIBUTION_BADGE_STYLE}&label={CONTRIBUTION_BADGE_LABEL}'
1081-
)
1099+
badge_options = [
1100+
f'query={encoded_query}',
1101+
f'style={ISSUE_AUTHOR_BADGE_STYLE}',
1102+
f'label={label}',
1103+
]
1104+
if badge_config.get('color'):
1105+
badge_options.append(f'color={badge_config["color"]}')
1106+
1107+
badge_query = '&'.join(badge_options)
1108+
badge_url = f'https://img.shields.io/github/issues-search?{badge_query}'
10821109
issues_url = f'https://github.com/{repository}/issues?q={encoded_query}'
1083-
return f'[![{CONTRIBUTION_BADGE_LABEL}]({badge_url})]({issues_url})'
1110+
return f'[![{label}]({badge_url})]({issues_url})'
1111+
1112+
1113+
def _build_issue_comment_badges(author: Optional[str] = None, repository: Optional[str] = None) -> str:
1114+
"""Build the leading issue comment badges for an author."""
1115+
badges = [
1116+
_build_issue_author_badge(
1117+
badge_type=badge_type,
1118+
author=author,
1119+
repository=repository,
1120+
)
1121+
for badge_type in ISSUE_AUTHOR_BADGES
1122+
]
1123+
return ' '.join(badge for badge in badges if badge)
10841124

10851125

10861126
def _write_issue_comment_header() -> None:
@@ -1089,14 +1129,14 @@ def _write_issue_comment_header() -> None:
10891129
Returns
10901130
-------
10911131
None
1092-
The comment file is initialized only when a contribution badge can be built.
1132+
The comment file is initialized only when author badges can be built.
10931133
"""
1094-
badge = _build_contribution_badge()
1095-
if not badge:
1134+
badges = _build_issue_comment_badges()
1135+
if not badges:
10961136
return
10971137

10981138
with open("comment.md", "w", encoding='utf-8') as comment_f:
1099-
comment_f.write(f'{badge}\n\n')
1139+
comment_f.write(f'{badges}\n\n')
11001140

11011141

11021142
def _html_line_breaks(value: str) -> str:

tests/unit/test_issue_updater.py

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -277,14 +277,15 @@ def test_load_existing_item_data_writes_duplicate_marker(tmp_path, monkeypatch):
277277
assert (tmp_path / 'duplicate.md').read_text(encoding='utf-8') == 'This item already exists in the database.'
278278

279279

280-
def test_build_contribution_badge_links_to_approved_author_issues():
280+
def test_build_issue_author_badge_links_to_approved_author_issues():
281281
"""Test contribution badge generation for an issue author."""
282282
encoded_query = (
283283
'repo%3ALizardByte%2FThemerrDB%20is%3Aclosed%20'
284284
'label%3Aapprove-theme%20author%3Aoctocat'
285285
)
286286

287-
badge = updater._build_contribution_badge(
287+
badge = updater._build_issue_author_badge(
288+
badge_type='contributions',
288289
author='octocat',
289290
repository='LizardByte/ThemerrDB',
290291
)
@@ -296,6 +297,26 @@ def test_build_contribution_badge_links_to_approved_author_issues():
296297
)
297298

298299

300+
def test_build_issue_author_badge_links_to_rejected_author_issues():
301+
"""Test rejection badge generation for an issue author."""
302+
encoded_query = (
303+
'repo%3ALizardByte%2FThemerrDB%20is%3Aclosed%20'
304+
'reason%3Anot-planned%20author%3Aoctocat'
305+
)
306+
307+
badge = updater._build_issue_author_badge(
308+
badge_type='rejections',
309+
author='octocat',
310+
repository='LizardByte/ThemerrDB',
311+
)
312+
313+
assert badge == (
314+
'[![rejections](https://img.shields.io/github/issues-search?'
315+
f'query={encoded_query}&style=for-the-badge&label=rejections&color=red)]'
316+
f'(https://github.com/LizardByte/ThemerrDB/issues?q={encoded_query})'
317+
)
318+
319+
299320
def test_write_issue_comment_header_skips_without_author(tmp_path, monkeypatch):
300321
"""Test issue comment header is omitted when the author login is unavailable."""
301322
monkeypatch.chdir(tmp_path)
@@ -1266,8 +1287,8 @@ def test_process_issue_update_reports_unsupported_database_url(tmp_path, monkeyp
12661287
assert exceptions.count('Exception Occurred') == 6
12671288

12681289

1269-
def test_process_issue_update_writes_contribution_badge_first(tmp_path, monkeypatch, youtube_url):
1270-
"""Test issue update comments start with the contributor badge."""
1290+
def test_process_issue_update_writes_author_badges_first(tmp_path, monkeypatch, youtube_url):
1291+
"""Test issue update comments start with the author badges."""
12711292
monkeypatch.chdir(tmp_path)
12721293
monkeypatch.setenv('GITHUB_REPOSITORY', 'LizardByte/ThemerrDB')
12731294
monkeypatch.setenv('ISSUE_AUTHOR_LOGIN', 'octocat')
@@ -1277,13 +1298,20 @@ def test_process_issue_update_writes_contribution_badge_first(tmp_path, monkeypa
12771298
youtube_url=youtube_url,
12781299
)
12791300

1280-
expected_badge = updater._build_contribution_badge(
1301+
expected_contribution_badge = updater._build_issue_author_badge(
1302+
badge_type='contributions',
1303+
author='octocat',
1304+
repository='LizardByte/ThemerrDB',
1305+
)
1306+
expected_rejection_badge = updater._build_issue_author_badge(
1307+
badge_type='rejections',
12811308
author='octocat',
12821309
repository='LizardByte/ThemerrDB',
12831310
)
1311+
expected_badges = f'{expected_contribution_badge} {expected_rejection_badge}'
12841312
comment = (tmp_path / 'comment.md').read_text(encoding='utf-8')
12851313
assert result is False
1286-
assert comment.startswith(f'{expected_badge}\n\n')
1314+
assert comment.startswith(f'{expected_badges}\n\n')
12871315
assert 'Exception Occurred' in comment
12881316

12891317

0 commit comments

Comments
 (0)