Skip to content

Commit af17f95

Browse files
authored
repokitteh: add support for randomized auto-assign. (envoyproxy#14185)
This will allow us to pick dedicated API shepherds for each PR, ensuring we have clear review ownership. Fixes envoyproxy#13350 Signed-off-by: Harvey Tuch <[email protected]>
1 parent dee245d commit af17f95

File tree

2 files changed

+40
-14
lines changed

2 files changed

+40
-14
lines changed

ci/repokitteh/modules/ownerscheck.star

+39-14
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
# "path": "api/",
99
# "label": "api",
1010
# "allow_global_approval": True,
11-
# "github_status_label" = "any API change",
11+
# "github_status_label": "any API change",
12+
# "auto_assign": True,
1213
# },
1314
# ],
1415
# )
@@ -27,8 +28,13 @@
2728
#
2829
# 'label' refers to a GitHub label applied to any matching PR. The GitHub check status
2930
# can be customized with `github_status_label`.
31+
#
32+
# If 'auto_assign' is set True, a randomly selected reviwer from the owner team will
33+
# be selected and set as a reviewer on the PR if there is not already a member of the
34+
# owner team set as reviewer or assignee for the PR.
3035

3136
load("text", "match")
37+
load("time", "now")
3238
load("github.com/repokitteh/modules/lib/utils.star", "react")
3339

3440
def _store_partial_approval(who, files):
@@ -64,7 +70,8 @@ def _get_relevant_specs(specs, changed_files):
6470
label=spec.get("label", None),
6571
path_match=path_match,
6672
allow_global_approval=allow_global_approval,
67-
status_label=status_label))
73+
status_label=status_label,
74+
auto_assign=spec.get("auto_assign", False)))
6875

6976
print("specs: %s" % relevant)
7077

@@ -152,20 +159,19 @@ def _reconcile(config, specs=None):
152159
return results
153160

154161

155-
def _comment(config, results, force=False):
162+
def _comment(config, results, assignees, sender, force=False):
156163
lines = []
157164

158165
for spec, approved in results:
159166
if approved:
160167
continue
161168

162-
mention = spec.owner
169+
owner = spec.owner
163170

164-
if mention[0] != '@':
165-
mention = '@' + mention
171+
if owner[-1] == '!':
172+
owner = owner[:-1]
166173

167-
if mention[-1] == '!':
168-
mention = mention[:-1]
174+
mention = '@' + owner
169175

170176
match_description = spec.path_match
171177
if match_description:
@@ -185,21 +191,40 @@ def _comment(config, results, force=False):
185191
elif mode == 'fyi':
186192
lines.append('CC %s: FYI only%s.' % (mention, match_description))
187193

194+
if mode != 'skip' and spec.auto_assign:
195+
api_assignee = None
196+
# Find owners via github.team_get_by_name, github.team_list_members
197+
team_name = owner.split('/')[1]
198+
team = github.team_get_by_name(team_name)
199+
# Exclude author from assignment.
200+
members = [m['login'] for m in github.team_list_members(team['id']) if m['login'] != sender]
201+
# Is a team member already assigned? The first assigned team member is picked. Bad O(n^2) as
202+
# Starlark doesn't have sets, n is small.
203+
for assignee in assignees:
204+
if assignee in members:
205+
api_assignee = assignee
206+
break
207+
# Otherwise, pick at "random" (we just use timestamp).
208+
if not api_assignee:
209+
api_assignee = members[now().second % len(members)]
210+
lines.append('API shepherd assignee is @%s' % api_assignee)
211+
github.issue_assign(api_assignee)
212+
188213
if lines:
189214
github.issue_create_comment('\n'.join(lines))
190215

191216

192-
def _reconcile_and_comment(config):
193-
_comment(config, _reconcile(config))
217+
def _reconcile_and_comment(config, assignees, sender):
218+
_comment(config, _reconcile(config), assignees, sender)
194219

195220

196-
def _force_reconcile_and_comment(config):
197-
_comment(config, _reconcile(config), force=True)
221+
def _force_reconcile_and_comment(config, assignees, sender):
222+
_comment(config, _reconcile(config), assignees, sender, force=True)
198223

199224

200-
def _pr(action, config):
225+
def _pr(action, config, assignees, sender):
201226
if action in ['synchronize', 'opened']:
202-
_reconcile_and_comment(config)
227+
_reconcile_and_comment(config, assignees, sender)
203228

204229

205230
def _pr_review(action, review_state, config):

repokitteh.star

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use(
2121
"path": "api/envoy/",
2222
"label": "api",
2323
"github_status_label": "any API change",
24+
"auto_assign": True,
2425
},
2526
{
2627
"owner": "envoyproxy/api-watchers",

0 commit comments

Comments
 (0)