66
77from github .PullRequest import PullRequest
88from github .Repository import Repository
9+ from github .MainClass import Github
10+ from github .GithubException import UnknownObjectException
11+ from github .Organization import Organization
12+ from github .Team import Team
913
1014from constants import (
1115 ALL_LABELS_DICT ,
2024 SUPPORTED_LABELS ,
2125 VERIFIED_LABEL_STR ,
2226 WELCOME_COMMENT ,
27+ APPROVED ,
2328)
24- from github import Github , UnknownObjectException
2529from simple_logger .logger import get_logger
2630
2731LOGGER = get_logger (name = "pr_labeler" )
@@ -41,6 +45,7 @@ class SupportedActions:
4145 def __init__ (self ) -> None :
4246 self .repo : Repository
4347 self .pr : PullRequest
48+ self .gh_client : Github
4449
4550 self .repo_name = os .environ ["GITHUB_REPOSITORY" ]
4651 self .pr_number = int (os .getenv ("GITHUB_PR_NUMBER" , 0 ))
@@ -77,8 +82,8 @@ def verify_base_config(self) -> None:
7782 )
7883
7984 def set_gh_config (self ) -> None :
80- gh_client : Github = Github (login_or_token = self .github_token )
81- self .repo = gh_client .get_repo (full_name_or_id = self .repo_name )
85+ self . gh_client = Github (login_or_token = self .github_token )
86+ self .repo = self . gh_client .get_repo (full_name_or_id = self .repo_name )
8287 self .pr = self .repo .get_pull (number = self .pr_number )
8388
8489
@@ -87,12 +92,29 @@ def __init__(self) -> None:
8792 super ().__init__ ()
8893 self .user_login = os .getenv ("GITHUB_USER_LOGIN" )
8994 self .review_state = os .getenv ("GITHUB_EVENT_REVIEW_STATE" )
95+ # We don't care if the body of the comment is in the discussion page or a review
9096 self .comment_body = os .getenv ("COMMENT_BODY" , "" )
97+ if self .comment_body == "" :
98+ # if it wasn't a discussion page comment, try to get a review comment, otherwise keep empty
99+ self .comment_body = os .getenv ("REVIEW_COMMENT_BODY" , "" )
91100 self .last_commit = list (self .pr .get_commits ())[- 1 ]
92101 self .last_commit_sha = self .last_commit .sha
93102
94103 self .verify_labeler_config ()
95104
105+ def verify_allowed_user (self ) -> None :
106+ org : Organization = self .gh_client .get_organization ("opendatahub-io" )
107+ # slug is the team name with replaced special characters,
108+ # all words to lowercase and spaces replace with a -
109+ team : Team = org .get_team_by_slug ("opendatahub-tests-contributors" )
110+ try :
111+ # check if the user is a member of opendatahub-tests-contributors
112+ membership = team .get_team_membership (self .user_login )
113+ LOGGER .info (f"User { self .user_login } is a member of the test contributor team. { membership } " )
114+ except UnknownObjectException :
115+ LOGGER .error (f"User { self .user_login } is not allowed for this action. Exiting." )
116+ sys .exit (0 )
117+
96118 def verify_labeler_config (self ) -> None :
97119 if self .action == self .SupportedActions .add_remove_labels_action_name and self .event_name in (
98120 "issue_comment" ,
@@ -101,17 +123,18 @@ def verify_labeler_config(self) -> None:
101123 if not self .user_login :
102124 sys .exit ("`GITHUB_USER_LOGIN` is not set" )
103125
104- if self . event_name == "issue_comment" and not self . comment_body :
105- sys . exit ( "`COMMENT_BODY` is not set" )
106-
107- if self . event_name == "pull_request_review" and not self . review_state :
108- sys .exit ("`GITHUB_EVENT_REVIEW_STATE` is not set" )
126+ if (
127+ self . event_name == "issue_comment" or self . event_name == "pull_request_review"
128+ ) and not self . comment_body :
129+ LOGGER . info ( "No comment, nothing to do. Exiting." )
130+ sys .exit (0 )
109131
110132 def run_pr_label_action (self ) -> None :
111133 if self .action == self .SupportedActions .pr_size_action_name :
112134 self .set_pr_size ()
113135
114136 if self .action == self .SupportedActions .add_remove_labels_action_name :
137+ self .verify_allowed_user ()
115138 self .add_remove_pr_labels ()
116139
117140 if self .action == self .SupportedActions .welcome_comment_action_name :
@@ -226,6 +249,10 @@ def add_remove_pr_labels(self) -> None:
226249
227250 return
228251
252+ # We will only reach here if the PR was created from a fork
253+ elif self .event_name == "workflow_run" and self .event_action == "submitted" :
254+ self .pull_request_review_label_actions ()
255+
229256 LOGGER .warning ("`add_remove_pr_label` called without a supported event" )
230257
231258 def pull_request_review_label_actions (
@@ -239,7 +266,7 @@ def pull_request_review_label_actions(
239266 label_to_remove = None
240267 label_to_add = None
241268
242- if self .review_state == "approved" :
269+ if self .review_state == APPROVED :
243270 label_to_remove = change_requested_label
244271 label_to_add = lgtm_label
245272
@@ -276,12 +303,20 @@ def issue_comment_label_actions(
276303 LOGGER .info (f"Processing labels: { labels } " )
277304 for label , action in labels .items ():
278305 if label == LGTM_LABEL_STR :
279- label = f"{ LGTM_BY_LABEL_PREFIX } { self .user_login } "
306+ if self .user_login == self .pr .user .login :
307+ LOGGER .info ("PR submitter cannot approve for their own PR" )
308+ continue
309+ else :
310+ label = f"{ LGTM_BY_LABEL_PREFIX } { self .user_login } "
311+ if not action [CANCEL_ACTION ] or self .event_action == "deleted" :
312+ self .approve_pr ()
280313
281314 label_in_pr = any ([label == _label .lower () for _label in self .pr_labels ])
282315 LOGGER .info (f"Processing label: { label } , action: { action } " )
283316
284317 if action [CANCEL_ACTION ] or self .event_action == "deleted" :
318+ if label == LGTM_LABEL_STR :
319+ self .dismiss_pr_approval ()
285320 if label_in_pr :
286321 LOGGER .info (f"Removing label { label } " )
287322 self .pr .remove_from_labels (label = label )
@@ -296,7 +331,23 @@ def issue_comment_label_actions(
296331
297332 def add_welcome_comment_set_assignee (self ) -> None :
298333 self .pr .create_issue_comment (body = WELCOME_COMMENT )
299- self .pr .add_to_assignees (self .pr .user .login )
334+ try :
335+ self .pr .add_to_assignees (self .pr .user .login )
336+ except UnknownObjectException :
337+ LOGGER .warning (f"User { self .pr .user .login } can not be assigned to the PR." )
338+
339+ def approve_pr (self ) -> None :
340+ self .pr .create_review (event = "APPROVE" )
341+
342+ def dismiss_pr_approval (self ) -> None :
343+ all_reviews = self .pr .get_reviews ()
344+ current_user = self .gh_client .get_user ().login
345+ LOGGER .info (f"Looking for approving review by user { current_user } " )
346+ # The reviews are paginated in chronological order. We need to get the newest by our account
347+ for review in all_reviews .reversed :
348+ if review .user .login == current_user and review .state == APPROVED :
349+ LOGGER .info (f"found review by user { current_user } with id { review .id } " )
350+ review .dismiss (message = "Dismissing review due to '/lgtm cancel' comment" )
300351
301352
302353def main () -> None :
0 commit comments