blob: edcdc6995741060b8f0e8ce6682699c44bf46639 [file] [log] [blame]
# coding=utf8
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Look for a LGTM in the messages from a valid reviewer."""
import logging
import re
from verification import base
def _regexp_check(value, whitelist, blacklist):
"""Returns True if value passes whitelist and not blacklist.
Both whitelist and blacklist are a list of regexp strings.
"""
def match(value, checklist):
return any(re.match(i, value) for i in checklist)
return match(value, whitelist) and not match(value, blacklist)
class LgtmStatus(base.SimpleStatus):
NO_COMMENT = 'No comments yet.'
NO_LGTM = (
'No LGTM from a valid reviewer yet. Only full committers are accepted.\n'
'Even if an LGTM may have been provided, it was from a non-committer or\n'
'a lowly provisional committer, _not_ a full super star committer.\n'
'See http://www.chromium.org/getting-involved/become-a-committer\n'
'Note that this has nothing to do with OWNERS files.')
def __init__(self, pending=None, whitelist=None, blacklist=None, **kwargs):
super(LgtmStatus, self).__init__(**kwargs)
# Can't save 'pending' reference here but postpone() will need it as a
# parameter.
if pending:
self._check(pending, whitelist, blacklist)
def _check(self, pending, whitelist, blacklist):
"""Updates self.state and self.error_message properties."""
# The owner cannot be a reviewer.
blacklist_owner = blacklist + [re.escape(pending.owner)]
if self._is_tbr(pending):
logging.debug('Change %s is TBR' % pending.issue)
if _regexp_check(pending.owner, whitelist, blacklist):
# TBR changes from a committer are fine.
self.state = base.SUCCEEDED
return
if not pending.messages:
self.error_message = self.NO_COMMENT
self.state = base.FAILED
return
def match_reviewer(r):
return _regexp_check(r, whitelist, blacklist_owner)
for i in pending.messages:
if i['approval'] and match_reviewer(i['sender']):
logging.info('Found lgtm by %s' % i['sender'])
self.state = base.SUCCEEDED
return
# TODO: Force a refresh of the meta data and use postpone() instead of
# bailing out if there is a valid reviewer that hasn't replied yet.
self.error_message = self.NO_LGTM
self.state = base.FAILED
@staticmethod
def _is_tbr(pending):
"""Returns True if a description contains TBR=.
This function should be moved elsewhere.
"""
return bool(re.search(r'^TBR=.*$', pending.description, re.MULTILINE))
class ReviewerLgtmVerifier(base.Verifier):
"""Needs at least one reviewer matching at least one regexp in
self.reviewers that is not also the owner of the issue.
"""
name = 'reviewer_lgtm'
def __init__(self, whitelist, blacklist):
super(ReviewerLgtmVerifier, self).__init__()
self.whitelist = whitelist
self.blacklist = blacklist
def verify(self, pending):
pending.verifications[self.name] = LgtmStatus(
pending=pending, whitelist=self.whitelist, blacklist=self.blacklist)
def update_status(self, queue):
pass