Skip to content
This repository was archived by the owner on Mar 14, 2023. It is now read-only.

Commit 2c3c564

Browse files
Merge pull request #249 from LeSeulArtichaut/assign-team
Assign a random team member on r? @rust-lang/<team>
2 parents 5c68ac0 + 699c894 commit 2c3c564

File tree

3 files changed

+68
-18
lines changed

3 files changed

+68
-18
lines changed

highfive/newpr.py

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
review_with_reviewer = 'r? @%s\n\n(rust-highfive has picked a reviewer for you, use r? to override)'
3434
review_without_reviewer = '@%s: no appropriate reviewer found, use r? to override'
3535

36-
reviewer_re = re.compile("\\b[rR]\?[:\- ]*@([a-zA-Z0-9\-]+)")
36+
reviewer_re = re.compile("\\b[rR]\?[:\- ]*@(?:([a-zA-Z0-9\-]+)/)?([a-zA-Z0-9\-]+)")
3737
submodule_re = re.compile(".*\+Subproject\scommit\s.*", re.DOTALL | re.MULTILINE)
3838
target_re = re.compile("^[+-]{3} [ab]/compiler/rustc_target/src/spec/", re.MULTILINE)
3939

@@ -230,27 +230,46 @@ def is_new_contributor(self, username, owner, repo):
230230
else:
231231
raise e
232232

233-
def find_reviewer(self, msg):
233+
def get_groups(self):
234+
groups = deepcopy(self.repo_config['groups'])
235+
236+
# fill in the default groups, ensuring that overwriting is an
237+
# error.
238+
global_ = self._load_json_file('_global.json')
239+
for name, people in global_['groups'].items():
240+
assert name not in groups, "group %s overlaps with _global.json" % name
241+
groups[name] = people
242+
243+
return groups
244+
245+
def find_reviewer(self, msg, exclude):
234246
"""
235247
If the user specified a reviewer, return the username, otherwise returns
236248
None.
237249
"""
238250
if msg is not None:
239251
match = reviewer_re.search(msg)
240-
return match.group(1) if match else None
252+
if match:
253+
if match.group(1):
254+
# assign someone from the specified team
255+
groups = self.get_groups()
256+
potential = groups.get(match.group(2))
257+
if potential is None:
258+
potential = groups.get("%s/%s" % (match.group(1), match.group(2)))
259+
if potential is None:
260+
potential = groups["all"]
261+
else:
262+
potential.extend(groups["all"])
263+
264+
return self.pick_reviewer(groups, potential, exclude)
265+
else:
266+
return match.group(2)
241267

242268
def choose_reviewer(self, repo, owner, diff, exclude):
243269
"""Choose a reviewer for the PR."""
244270
# Get JSON data on reviewers.
245271
dirs = self.repo_config.get('dirs', {})
246-
groups = deepcopy(self.repo_config['groups'])
247-
248-
# fill in the default groups, ensuring that overwriting is an
249-
# error.
250-
global_ = self._load_json_file('_global.json')
251-
for name, people in global_['groups'].items():
252-
assert name not in groups, "group %s overlaps with _global.json" % name
253-
groups[name] = people
272+
groups = self.get_groups()
254273

255274
most_changed = None
256275
# If there's directories with specially assigned groups/users
@@ -293,6 +312,9 @@ def choose_reviewer(self, repo, owner, diff, exclude):
293312
if not potential:
294313
potential = groups['core']
295314

315+
return self.pick_reviewer(groups, potential, exclude)
316+
317+
def pick_reviewer(self, groups, potential, exclude):
296318
# expand the reviewers list by group
297319
reviewers = []
298320
seen = {"all"}
@@ -382,7 +404,7 @@ def new_pr(self):
382404
if not self.payload['pull_request', 'assignees']:
383405
# Only try to set an assignee if one isn't already set.
384406
msg = self.payload['pull_request', 'body']
385-
reviewer = self.find_reviewer(msg)
407+
reviewer = self.find_reviewer(msg, author)
386408
post_msg = False
387409

388410
if not reviewer:
@@ -437,7 +459,7 @@ def new_comment(self):
437459

438460
# Check for r? and set the assignee.
439461
msg = self.payload['comment', 'body']
440-
reviewer = self.find_reviewer(msg)
462+
reviewer = self.find_reviewer(msg, author)
441463
if reviewer:
442464
issue = str(self.payload['issue', 'number'])
443465
self.set_assignee(

highfive/tests/fakes.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ def get_repo_configs():
7575
"reviewers": ["@JohnTitor"],
7676
}
7777
}
78+
},
79+
'teams': {
80+
"groups": {"all": [], "a": ["@pnkfelix"], "b/c": ["@nrc"]}
7881
}
7982
}
8083

highfive/tests/test_newpr.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -351,11 +351,11 @@ def test_find_reviewer(self):
351351
handler = HighfiveHandlerMock(Payload({})).handler
352352

353353
for (msg, reviewer) in found_cases:
354-
assert handler.find_reviewer(msg) == reviewer, \
354+
assert handler.find_reviewer(msg, None) == reviewer, \
355355
"expected '%s' from '%s'" % (reviewer, msg)
356356

357357
for msg in not_found_cases:
358-
assert handler.find_reviewer(msg) is None, \
358+
assert handler.find_reviewer(msg, None) is None, \
359359
"expected '%s' to have no reviewer extracted" % msg
360360

361361
class TestApiReq(TestNewPR):
@@ -792,7 +792,7 @@ def assert_set_assignee_branch_calls(self, reviewer, to_mention):
792792
self.mocks['api_req'].assert_called_once_with(
793793
'GET', 'https://the.url/', None, 'application/vnd.github.v3.diff'
794794
)
795-
self.mocks['find_reviewer'].assert_called_once_with('The PR comment.')
795+
self.mocks['find_reviewer'].assert_called_once_with('The PR comment.', 'prAuthor')
796796
self.mocks['set_assignee'].assert_called_once_with(
797797
reviewer, 'repo-owner', 'repo-name', '7', self.user, 'prAuthor',
798798
to_mention
@@ -1052,7 +1052,7 @@ def test_no_reviewer(self):
10521052
self.mocks['find_reviewer'].return_value = None
10531053
handler.new_comment()
10541054
self.mocks['is_collaborator'].assert_not_called()
1055-
self.mocks['find_reviewer'].assert_called_with('comment!')
1055+
self.mocks['find_reviewer'].assert_called_with('comment!', 'userA')
10561056
self.mocks['set_assignee'].assert_not_called()
10571057

10581058
def test_has_reviewer(self):
@@ -1061,7 +1061,7 @@ def test_has_reviewer(self):
10611061
self.mocks['find_reviewer'].return_value = 'userD'
10621062
handler.new_comment()
10631063
self.mocks['is_collaborator'].assert_not_called()
1064-
self.mocks['find_reviewer'].assert_called_with('comment!')
1064+
self.mocks['find_reviewer'].assert_called_with('comment!', 'userA')
10651065
self.mocks['set_assignee'].assert_called_with(
10661066
'userD', 'repo-owner', 'repo-name', '7', 'integrationUser',
10671067
'userA', None
@@ -1260,6 +1260,31 @@ def test_mentions_without_dirs(self):
12601260
)
12611261
assert set(["@JohnTitor"]) == mentions
12621262

1263+
def test_with_team_ping(self):
1264+
"""Test choosing a reviewer when passed a team ping"""
1265+
handler = HighfiveHandlerMock(
1266+
Payload({}), repo_config=self.fakes['config']['teams']
1267+
).handler
1268+
1269+
found_cases = (
1270+
("r? @foo/a", "pnkfelix"),
1271+
("r? @b/c", "nrc"),
1272+
)
1273+
1274+
not_found_cases = (
1275+
"r? @/a",
1276+
"r? @a/b",
1277+
)
1278+
1279+
for (msg, reviewer) in found_cases:
1280+
assert handler.find_reviewer(msg, None) == reviewer, \
1281+
"expected '%s' from '%s'" % (reviewer, msg)
1282+
1283+
for msg in not_found_cases:
1284+
assert handler.find_reviewer(msg, None) is None, \
1285+
"expected '%s' to have no reviewer extracted" % msg
1286+
1287+
12631288
class TestRun(TestNewPR):
12641289
@pytest.fixture(autouse=True)
12651290
def make_mocks(cls, patcherize):

0 commit comments

Comments
 (0)