def matchesStatuses(self, change): if self.required_statuses or self.reject_statuses: if not hasattr(change, 'number'): # not a PR, no status return FalseWithReason("Can't match statuses without PR") if self.required_statuses and not change.status: return FalseWithReason( "Required statuses %s does not match %s" % ( self.required_statuses, change.status)) required_statuses_results = self.matchesRequiredStatuses(change) if not required_statuses_results: return required_statuses_results return self.matchesNoRejectStatuses(change)
def matchesReviews(self, change): if self.required_reviews or self.reject_reviews: if not hasattr(change, 'number'): # not a PR, no reviews return FalseWithReason("Change is not a PR") if self.required_reviews and not change.reviews: # No reviews means no matching of required bits # having reject reviews but no reviews on the change is okay return FalseWithReason("Reviews %s does not match %s" % ( self.required_reviews, change.reviews)) return (self.matchesRequiredReviews(change) and self.matchesNoRejectReviews(change))
def matchesNoRejectReviews(self, change): for rreview in self.reject_reviews: for review in change.reviews: if self._match_review_required_review(rreview, review): # A review matched, we can reject right away return FalseWithReason("Reject reviews %s matches %s" % ( self.reject_reviews, change.reviews)) return True
def matchesNoRejectStatuses(self, change): # statuses are ANDed # If any of the rejected statusses are present, we return false for rstatus in self.reject_statuses: for status in change.status: if re2.fullmatch(rstatus, status): return FalseWithReason("NoRejectStatuses %s matches %s" % ( self.reject_statuses, change.status)) return True
def matches(self, change): statuses_result = self.matchesStatuses(change) if not statuses_result: return statuses_result if self.open is not None: # if a "change" has no number, it's not a change, but a push # and cannot possibly pass this test. if hasattr(change, 'number'): if self.open != change.open: return FalseWithReason("Change is not a PR") else: return FalseWithReason("Change is not a PR") if self.merged is not None: # if a "change" has no number, it's not a change, but a push # and cannot possibly pass this test. if hasattr(change, 'number'): if self.merged != change.is_merged: return FalseWithReason("Change is not a PR") else: return FalseWithReason("Change is not a PR") if self.current_patchset is not None: # if a "change" has no number, it's not a change, but a push # and cannot possibly pass this test. if hasattr(change, 'number'): if self.current_patchset != change.is_current_patchset: return FalseWithReason("Change is not current") else: return FalseWithReason("Change is not a PR") # required reviews are ANDed (reject reviews are ORed) reviews_result = self.matchesReviews(change) if not reviews_result: return reviews_result # required labels are ANDed for label in self.labels: if label not in change.labels: return FalseWithReason("Labels %s does not match %s" % ( self.labels, change.labels)) # rejected reviews are OR'd for label in self.reject_labels: if label in change.labels: return FalseWithReason("RejectLabels %s matches %s" % ( self.reject_labels, change.labels)) return True
def matchesRequiredStatuses(self, change): # statuses are ORed # A PR head can have multiple statuses on it. If the change # statuses and the filter statuses are a null intersection, there # are no matches and we return false if self.required_statuses: for required_status in self.required_statuses: for status in change.status: if re2.fullmatch(required_status, status): return True return FalseWithReason("RequiredStatuses %s does not match %s" % ( self.required_statuses, change.status)) return True
def matchesRequiredReviews(self, change): for rreview in self.required_reviews: matches_review = False for review in change.reviews: if self._match_review_required_review(rreview, review): # Consider matched if any review matches matches_review = True break if not matches_review: return FalseWithReason( "Required reviews %s does not match %s" % ( self.required_reviews, change.reviews)) return True
def matches(self, event, change): # event types are ORed matches_type = False for etype in self.types: if etype.match(event.type): matches_type = True if self.types and not matches_type: return FalseWithReason("Types %s doesn't match %s" % ( self.types, event.type)) # branches are ORed matches_branch = False for branch in self.branches: if branch.match(event.branch): matches_branch = True if self.branches and not matches_branch: return FalseWithReason("Branches %s doesn't match %s" % ( self.branches, event.branch)) # refs are ORed matches_ref = False if event.ref is not None: for ref in self.refs: if ref.match(event.ref): matches_ref = True if self.refs and not matches_ref: return FalseWithReason( "Refs %s doesn't match %s" % (self.refs, event.ref)) if self.ignore_deletes and event.newrev == EMPTY_GIT_REF: # If the updated ref has an empty git sha (all 0s), # then the ref is being deleted return FalseWithReason("Ref deletion are ignored") # comments are ORed matches_comment_re = False for comment_re in self.comments: if (event.comment is not None and comment_re.search(event.comment)): matches_comment_re = True if self.comments and not matches_comment_re: return FalseWithReason("Comments %s doesn't match %s" % ( self.comments, event.comment)) # actions are ORed matches_action = False for action in self.actions: if (event.action == action): matches_action = True if self.actions and not matches_action: return FalseWithReason("Actions %s doesn't match %s" % ( self.actions, event.action)) # check_runs are ORed if self.check_runs: check_run_found = False for check_run in self.check_runs: if re2.fullmatch(check_run, event.check_run): check_run_found = True break if not check_run_found: return FalseWithReason("Check_runs %s doesn't match %s" % ( self.check_runs, event.check_run)) # labels are ORed if self.labels and event.label not in self.labels: return FalseWithReason("Labels %s doesn't match %s" % ( self.labels, event.label)) # unlabels are ORed if self.unlabels and event.unlabel not in self.unlabels: return FalseWithReason("Unlabels %s doesn't match %s" % ( self.unlabels, event.unlabel)) # states are ORed if self.states and event.state not in self.states: return FalseWithReason("States %s doesn't match %s" % ( self.states, event.state)) # statuses are ORed if self.statuses: status_found = False for status in self.statuses: if re2.fullmatch(status, event.status): status_found = True break if not status_found: return FalseWithReason("Statuses %s doesn't match %s" % ( self.statuses, event.status)) return self.matchesStatuses(change)