From: Alexander Kanevskiy Date: Thu, 15 Aug 2013 22:57:24 +0000 (+0300) Subject: Refactored logic of matching rules X-Git-Tag: submit/devel/20190730.075359~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=288eb36eb0a59d79678cdbe90f0bbde5d6d06aed;p=services%2Fgerrithooks-plugins.git Refactored logic of matching rules --- diff --git a/plugins/add_reviewers.py b/plugins/add_reviewers.py index d3c979d..2ea6527 100644 --- a/plugins/add_reviewers.py +++ b/plugins/add_reviewers.py @@ -35,13 +35,35 @@ def to_bool(arg): 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: @@ -52,29 +74,16 @@ def patchset_created(hook = None, config = None, logger = None, params = None, 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" % \ @@ -100,67 +109,16 @@ def patchset_created(hook = None, config = None, logger = None, params = None, 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") @@ -173,7 +131,85 @@ def patchset_created(hook = None, config = None, logger = None, params = None, 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 """ @@ -195,15 +231,12 @@ def get_rules(config, section_name, logger): 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