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 |