| OLD | NEW |
| (Empty) |
| 1 # coding=utf8 | |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 3 # Use of this source code is governed by a BSD-style license that can be | |
| 4 # found in the LICENSE file. | |
| 5 """Look for a LGTM in the messages from a valid reviewer.""" | |
| 6 | |
| 7 import logging | |
| 8 import re | |
| 9 | |
| 10 from verification import base | |
| 11 | |
| 12 | |
| 13 def _regexp_check(value, whitelist, blacklist): | |
| 14 """Returns True if value passes whitelist and not blacklist. | |
| 15 | |
| 16 Both whitelist and blacklist are a list of regexp strings. | |
| 17 """ | |
| 18 def match(value, checklist): | |
| 19 return any(re.match(i, value) for i in checklist) | |
| 20 return match(value, whitelist) and not match(value, blacklist) | |
| 21 | |
| 22 | |
| 23 class LgtmStatus(base.SimpleStatus): | |
| 24 NO_COMMENT = 'No comments yet.' | |
| 25 NO_LGTM = ( | |
| 26 'No LGTM from a valid reviewer yet. Only full committers are accepted.\n' | |
| 27 'Even if an LGTM may have been provided, it was from a non-committer or\n' | |
| 28 'a lowly provisional committer, _not_ a full super star committer.\n' | |
| 29 'See http://www.chromium.org/getting-involved/become-a-committer\n' | |
| 30 'Note that this has nothing to do with OWNERS files.') | |
| 31 | |
| 32 def __init__(self, pending=None, whitelist=None, blacklist=None, **kwargs): | |
| 33 super(LgtmStatus, self).__init__(**kwargs) | |
| 34 # Can't save 'pending' reference here but postpone() will need it as a | |
| 35 # parameter. | |
| 36 if pending: | |
| 37 self._check(pending, whitelist, blacklist) | |
| 38 | |
| 39 def _check(self, pending, whitelist, blacklist): | |
| 40 """Updates self.state and self.error_message properties.""" | |
| 41 # The owner cannot be a reviewer. | |
| 42 blacklist_owner = blacklist + [re.escape(pending.owner)] | |
| 43 | |
| 44 if self._is_tbr(pending): | |
| 45 logging.debug('Change %s is TBR' % pending.issue) | |
| 46 if _regexp_check(pending.owner, whitelist, blacklist): | |
| 47 # TBR changes from a committer are fine. | |
| 48 self.state = base.SUCCEEDED | |
| 49 return | |
| 50 | |
| 51 if not pending.messages: | |
| 52 self.error_message = self.NO_COMMENT | |
| 53 self.state = base.FAILED | |
| 54 return | |
| 55 | |
| 56 def match_reviewer(r): | |
| 57 return _regexp_check(r, whitelist, blacklist_owner) | |
| 58 | |
| 59 for i in pending.messages: | |
| 60 if i['approval'] and match_reviewer(i['sender']): | |
| 61 logging.info('Found lgtm by %s' % i['sender']) | |
| 62 self.state = base.SUCCEEDED | |
| 63 return | |
| 64 | |
| 65 # TODO: Force a refresh of the meta data and use postpone() instead of | |
| 66 # bailing out if there is a valid reviewer that hasn't replied yet. | |
| 67 self.error_message = self.NO_LGTM | |
| 68 self.state = base.FAILED | |
| 69 | |
| 70 @staticmethod | |
| 71 def _is_tbr(pending): | |
| 72 """Returns True if a description contains TBR=. | |
| 73 | |
| 74 This function should be moved elsewhere. | |
| 75 """ | |
| 76 return bool(re.search(r'^TBR=.*$', pending.description, re.MULTILINE)) | |
| 77 | |
| 78 | |
| 79 class ReviewerLgtmVerifier(base.Verifier): | |
| 80 """Needs at least one reviewer matching at least one regexp in | |
| 81 self.reviewers that is not also the owner of the issue. | |
| 82 """ | |
| 83 name = 'reviewer_lgtm' | |
| 84 | |
| 85 def __init__(self, whitelist, blacklist): | |
| 86 super(ReviewerLgtmVerifier, self).__init__() | |
| 87 self.whitelist = whitelist | |
| 88 self.blacklist = blacklist | |
| 89 | |
| 90 def verify(self, pending): | |
| 91 pending.verifications[self.name] = LgtmStatus( | |
| 92 pending=pending, whitelist=self.whitelist, blacklist=self.blacklist) | |
| 93 | |
| 94 def update_status(self, queue): | |
| 95 pass | |
| OLD | NEW |