@@ -408,6 +408,13 @@ def record_retry_log(self, src, body):
408408 [self .repo_label , self .num , src , body ],
409409 )
410410
411+ @property
412+ def author (self ):
413+ """
414+ Get the GitHub login name of the author of the pull request
415+ """
416+ return self .get_issue ().user .login
417+
411418
412419def sha_cmp (short , full ):
413420 return len (short ) >= 4 and short == full [:len (short )]
@@ -576,9 +583,18 @@ def parse_commands(body, username, repo_label, repo_cfg, state, my_username,
576583 state .change_labels (LabelEvent .APPROVED )
577584
578585 elif word == 'r-' :
579- if not verify_auth (username , repo_label , repo_cfg , state ,
580- AuthState .REVIEWER , realtime , my_username ):
581- continue
586+ # Allow the author of a pull request to unapprove their own PR. The
587+ # author can already perform other actions that effectively
588+ # unapprove the PR (change the target branch, push more commits,
589+ # etc.) so allowing them to directly unapprove it is also allowed.
590+
591+ # Because verify_auth has side-effects (especially, it may leave a
592+ # comment on the pull request if the user is not authorized), we
593+ # need to do the author check BEFORE the verify_auth check.
594+ if state .author != username :
595+ if not verify_auth (username , repo_label , repo_cfg , state ,
596+ AuthState .REVIEWER , realtime , my_username ):
597+ continue
582598
583599 state .approved_by = ''
584600 state .save ()
0 commit comments