return bool(arg)
+def gerrit_client(config):
+ """
+ Returns tuple: GerritREST instance / error message
+ """
+ if not config.has_option("gerrit", "url"):
+ return (None, 'Gerrit URL is not defined in config!')
+
+ gerrit_url = config.get("gerrit", "url")
+ if config.has_option("gerrit", "username") \
+ and config.has_option("gerrit", "password"):
+ user = config.get("gerrit", "username")
+ password = config.get("gerrit", "password")
+ else:
+ # Fallback to ~/.netrc
+ try:
+ user, _, password = \
+ netrc.netrc().hosts[urlparse.urlparse(gerrit_url).netloc]
+ except KeyError:
+ return (None, "Unable to find credentials in ~/.netrc")
+
+ return (GerritREST(gerrit_url, user, password), None)
+
+
def patchset_created(hook = None, config = None, logger = None, params = None,
extra_params = None):
+ """Main entry on add_reviewers plugin"""
section_name = 'add_reviewers'
error_message = ''
- if not config.has_option("gerrit", "url"):
- error_message = 'Gerrit URL is not defined in config!'
if not params.change:
error_message = 'Change not defined'
if not params.project:
logger.error(error_message)
return 1
- gerrit_url = config.get("gerrit", "url")
-
-
- if config.has_option("gerrit", "username") \
- and config.has_option("gerrit", "password"):
- user = config.get("gerrit", "username")
- password = config.get("gerrit", "password")
- else:
- # Fallback to ~/.netrc
- try:
- user, _, password = \
- netrc.netrc().hosts[urlparse.urlparse(gerrit_url).netloc]
- except KeyError:
- logger.error("Unable to find credentials in ~/.netrc")
- return -1
-
- rules, rop = get_rules(config, section_name, logger)
+ rules, rop = get_rules(config, section_name)
if not rop['enabled']:
logger.warning("No rules enabled")
return 0
- gerrit = GerritREST(gerrit_url, user, password)
+ gerrit, error_message = gerrit_client(config)
+ if error_message:
+ logger.error(error_message)
+ return 1
# get change information from gerrit
change_query = "change:%s+project:%s+branch:%s" % \
reviewers = []
reviewer_groups = []
for rule in rules:
- if not rules[rule]['enabled']:
- continue
- rule_type = rules[rule].get('type', None)
- if rule_type == 'project_group':
- if not rules[rule].get('match', None):
- logger.warning("No match defined for %s", rule)
- continue
- group_match = re.compile(rules[rule]['match'])
- for group in project_groups:
- if group_match.search(group):
- logger.debug("[%s] Matched group %s", rule, group)
- reviewer_groups.append(group)
- elif rule_type == 'change_file':
- if not rules[rule].get('match', None):
- logger.warning("No match defined for %s", rule)
- continue
- file_match = re.compile(rules[rule]['match'])
- if params.commit and params.commit in change_info['revisions']:
- files = change_info['revisions'][params.commit].get('files', {})
- else:
- files = change_info['revisions']\
- [change_info['current_revision']].get('files',{})
- matched = False
- for change_file in files:
- if file_match.search(change_file):
- matched = True
- logger.debug("[%s] Matched file: %s", rule, change_file)
- break
- if matched:
- for reviewer in re.split(r'\s*[,;]\s*',
- rules[rule].get('reviewer',"")):
- reviewers.append(reviewer.strip())
- for group in re.split(r'\s*[,;]\s*',
- rules[rule].get('reviewer_group',"")):
- reviewer_groups.append(group.strip())
- elif rule_type == 'author':
- if not rules[rule].get('match', None):
- logger.warning("No match defined for %s", rule)
- continue
- owner_match = re.compile(rules[rule]['match'], re.IGNORECASE)
- owner_info = []
- owner_email = change_info['owner'].get('email', None)
- if owner_email:
- owner_info.append(owner_email)
- owner_name = change_info['owner'].get('name', None)
- if owner_name:
- owner_info.append(owner_name)
- logger.debug("match: %s Author: %s", rules[rule]['match'], owner_info)
- matched = False
- for info in owner_info:
- if owner_match.search(info):
- matched = True
- logger.debug("[%s] Matched owner: %s", rule, info)
- break
- if matched:
- for reviewer in re.split(r'\s*[,;]\s*',
- rules[rule].get('reviewer',"")):
- reviewers.append(reviewer.strip())
- for group in re.split(r'\s*[,;]\s*',
- rules[rule].get('reviewer_group',"")):
- reviewer_groups.append(group.strip())
+ if rules[rule]['enabled'] and \
+ match_branch(rules[rule], params.branch) and \
+ match_project(rules[rule], params.project) and \
+ match_change_author(rule, rules[rule], change_info, logger) and \
+ match_change_file(rule, rules[rule], change_info, params.commit,
+ logger):
+
+ reviewers, reviewer_groups = return_reviewers(rules[rule])
+ reviewer_groups.extend(
+ match_project_group(rule, rules[rule], project_groups, logger))
try:
dry_run = config.getboolean("add_reviewers", "dry_run")
add_reviewers(reviewer_groups, gerrit, change_info, dry_run, logger)
-def get_rules(config, section_name, logger):
+def match_project(rule, project):
+ """Checks if project rule is present and project matches it."""
+ if project and rule.get('project_regexp', None):
+ project_match = re.compile(rule['project_regexp'])
+ if not project_match.search(project):
+ return False
+ return True
+
+def match_branch(rule, branch):
+ """Checks if branch rule is present and branch matches it."""
+ if branch and rule.get('branch_regexp', None):
+ branch_match = re.compile(rule['branch_regexp'])
+ if not branch_match.search(branch):
+ return False
+ return True
+
+def match_change_file(name, rule, change, commit, logger):
+ """Matches files changed in this change"""
+
+ result = True
+ if rule.get('file_regexp', None):
+ file_match = re.compile(rule['file_regexp'])
+ if commit and commit in change['revisions']:
+ files = change['revisions'][commit].get('files', {})
+ else:
+ files = change['revisions']\
+ [change['current_revision']].get('files',{})
+ result = False
+ for change_file in files:
+ if file_match.search(change_file):
+ result = True
+ logger.debug("[%s] Matched file: %s", name, change_file)
+ break
+ return result
+
+def match_change_author(name, rule, change, logger):
+ """Matches change author"""
+ result = True
+ if rule.get('author_regexp', None):
+ owner_match = re.compile(rule['author_regexp'], re.IGNORECASE)
+ owner_info = []
+ owner_email = change['owner'].get('email', None)
+ if owner_email:
+ owner_info.append(owner_email)
+ owner_name = change['owner'].get('name', None)
+ if owner_name:
+ owner_info.append(owner_name)
+ logger.debug("[%s] Author info %s", name, owner_info)
+ result = False
+ for info in owner_info:
+ if owner_match.search(info):
+ result = True
+ logger.debug("[%s] Matched owner: %s", rule, info)
+ break
+ return result
+
+def match_project_group(name, rule, project_groups, logger):
+ """Matches group associated with project"""
+ result = []
+ if rule.get('project_groups_regexp', None):
+ group_match = re.compile(rule['project_groups_regexp'])
+ for group in project_groups:
+ if group_match.search(group):
+ logger.debug("[%s] Matched group %s", name, group)
+ result.append(group)
+ return result
+
+def return_reviewers(rule):
+ """Returns reviewers and reviewer groups from rule"""
+ reviewers = set()
+ reviewer_groups = set()
+ for reviewer in re.split(r'\s*[,;]\s*', rule.get('reviewer',"")):
+ reviewers.add(reviewer.strip())
+ for group in re.split(r'\s*[,;]\s*', rule.get('reviewer_group',"")):
+ reviewer_groups.add(group.strip())
+ return list(reviewers), list(reviewer_groups)
+
+
+def get_rules(config, section_name):
"""
Parses config options and returns rules + options
"""
rules[rule]['enabled'] = to_bool(rules[rule].get('enabled', None))
if rules[rule]['enabled']:
options['enabled'] = True
- rule_type = rules[rule].get('type', None)
- if rule_type == 'project_group':
+ if rules[rule].get('project_groups_regexp', None):
options['project_groups'] = True
- elif rule_type == 'change_file':
+ if rules[rule].get('file_regexp', None):
options['files'] = True
- elif rule_type == 'author':
+ if rules[rule].get('author_regexp', None):
options['owners'] = True
- else:
- logger.warning("Unknown type(%s) in %s", rule_type, section)
return rules, options