forked from github/issue-metrics
-
Notifications
You must be signed in to change notification settings - Fork 0
/
most_active_mentors.py
executable file
·181 lines (153 loc) · 6.4 KB
/
most_active_mentors.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
"""A module for measuring the number of very active mentors
This module provides functions for measuring the number of active mentors on a
project.
This is measured by number of PR comments. We are working under the assumption
that PR comments are left in good faith to move contributors further instead of
nitpicking and discouraging them.
Open questions:
- should there be an option to limit this to certain users, e.g. core
maintainers?
- should there be a limit to how many comments per PR we consider to avoid
having the statistic dominated by contested PRs?
- should this metric count consecutive comments coming from the same user as
only one to avoid people unnessesarily splitting their comments to game the
metric?
- instead of PR comments should we count PRs on which a username was seen as
commenter?
Functions:
collect_response_usernames(
issue: Union[github3.issues.Issue, None],
discussion: Union[dict, None],
pull_request: Union[github3.pulls.PullRequest, None],
max_comments_to_evaluate,
) -> ____________
Collect the number of responses per username for single item. Take only
top n comments (max_comments_to_evaluate) into consideration.
get_number_of_active_reviewers(
mentors: List [mentors with metrics)
) -> int active_number
Count the number of mentors active at least n times
"""
from collections import Counter
from datetime import datetime
from typing import Dict, List, Union
import github3
from classes import IssueWithMetrics
def count_comments_per_user(
issue: Union[github3.issues.Issue, None], # type: ignore
discussion: Union[dict, None] = None,
pull_request: Union[github3.pulls.PullRequest, None] = None,
ready_for_review_at: Union[datetime, None] = None,
ignore_users: List[str] | None = None,
max_comments_to_eval=20,
heavily_involved=3,
) -> dict:
"""Count the number of times a user was seen commenting on a single item.
Args:
issue (Union[github3.issues.Issue, None]): A GitHub issue.
pull_request (Union[github3.pulls.PullRequest, None]): A GitHub pull
request.
ignore_users (List[str]): A list of GitHub usernames to ignore.
max_comments_to_eval: Maximum number of comments per item to look at.
heavily_involved: Maximum number of comments to count for one
user per issue.
Returns:
dict: A dictionary of usernames seen and number of comments they left.
"""
if ignore_users is None:
ignore_users = []
mentor_count: Dict[str, int] = {}
# Get the first comments
if issue:
comments = issue.issue.comments(
number=max_comments_to_eval, sort="created", direction="asc"
) # type: ignore
for comment in comments:
if ignore_comment(
issue.issue.user,
comment.user,
ignore_users,
comment.created_at,
ready_for_review_at,
):
continue
# increase the number of comments left by current user by 1
if comment.user.login in mentor_count:
if mentor_count[comment.user.login] < heavily_involved:
mentor_count[comment.user.login] += 1
else:
mentor_count[comment.user.login] = 1
# Check if the issue is actually a pull request
# so we may also get the first review comment time
if pull_request:
review_comments = pull_request.reviews(number=max_comments_to_eval)
# type: ignore
for review_comment in review_comments:
if ignore_comment(
issue.issue.user,
review_comment.user,
ignore_users,
review_comment.submitted_at,
ready_for_review_at,
):
continue
# increase the number of comments left by current user by 1
if review_comment.user.login in mentor_count:
mentor_count[review_comment.user.login] += 1
else:
mentor_count[review_comment.user.login] = 1
if discussion and len(discussion["comments"]["nodes"]) > 0:
for comment in discussion["comments"]["nodes"]:
if ignore_comment(
comment.user,
comment.user,
ignore_users,
comment.submitted_at,
comment.ready_for_review_at,
):
continue
# increase the number of comments left by current user by 1
if comment.user.login in mentor_count:
mentor_count[comment.user.login] += 1
else:
mentor_count[comment.user.login] = 1
return mentor_count
def ignore_comment(
issue_user: github3.users.User,
comment_user: github3.users.User,
ignore_users: List[str],
comment_created_at: datetime,
ready_for_review_at: Union[datetime, None],
) -> bool:
"""Check if a comment should be ignored."""
return bool(
# ignore comments by IGNORE_USERS
comment_user.login in ignore_users
# ignore comments by bots
or comment_user.type == "Bot"
# ignore comments by the issue creator
or comment_user.login == issue_user.login
# ignore pending reviews
or not comment_created_at
# ignore comments created before the issue was ready for review
or (ready_for_review_at and comment_created_at < ready_for_review_at)
)
def get_mentor_count(issues_with_metrics: List[IssueWithMetrics], cutoff: int) -> int:
"""Calculate the number of active mentors on the project.
Args:
issues_with_metrics (List[IssueWithMetrics]): A list of issues w/
metrics
cutoff (int: the minimum number of comments a user has to leave
to count as active mentor.)
Returns:
int: Number of active mentors
"""
mentor_count: Counter[str] = Counter({})
for issue_with_metrics in issues_with_metrics:
current_counter = Counter(issue_with_metrics.mentor_activity)
mentor_count = mentor_count + current_counter
active_mentor_count = 0
for count in mentor_count.values():
if count >= cutoff:
active_mentor_count += 1
return active_mentor_count