def get_recipient()

in notifier.py [0:0]


    def get_recipient(self, repository, itype, action="comment", userid=None):
        m = RE_PROJECT.match(repository)
        if m:
            project = m.group(1)
        else:
            project = "infra"
        repo_path = None
        scheme = {}
        for root_dir in self.config["repository_paths"]:
            for path in glob.glob(root_dir):
                if os.path.basename(path) == f"{repository}.git":
                    repo_path = path
                    break
        if repo_path:
            scheme_path = os.path.join(repo_path, self.config["scheme_file"])
            if os.path.exists(scheme_path):
                try:
                    scheme = yaml.safe_load(open(scheme_path))
                except Exception: # TODO: narrow further to expected Exceptions
                    pass

            # Check standard git config
            cfg_path = os.path.join(repo_path, "config")
            cfg = git.GitConfigParser(cfg_path)

            # If the yaml scheme is missing parts, weave in the defaults from the git config in their place
            # Commits mailing list
            if "commits" not in scheme:
                scheme["commits"] = cfg.get("hooks.asfgit", "recips") or self.config["default_recipient"]
            # Issues and Pull Requests
            if cfg.has_option("apache", "dev"):
                default_issue = cfg.get("apache", "dev")
                if "issues" not in scheme:
                    scheme["issues"] = default_issue
                if "pullrequests" not in scheme:
                    scheme["pullrequests"] = default_issue
            # Jira notification options
            if cfg.has_option("apache", "jira"):
                default_jira = cfg.get("apache", "jira")
                if "jira_options" not in scheme:
                    scheme["jira_options"] = default_jira

        if scheme:
            if itype not in ("commit", "jira") and userid:
                # Work out whether issue or pullrequest
                github_issue_type = itype == "issue" and "issues" or "pullrequests"

                # Work out the type of event (ticket status change, or comment)
                event_category = "unknown"
                if action in ("comment", "diffcomment", "diffcomment_collated", "edited", "deleted", "created"):
                    event_category = "comment"
                elif action in ("open", "close", "merge"):
                    event_category = "status"

                # Order of preference for scheme (most specific -> least specific)
                # Special rules that are only valid for bots like dependabot
                rule_order_bots = (
                    "{issue_type}_{event_category}_bot_{userid}",  # e.g. pullrequests_comment_bot_dependabot
                    "{issue_type}_bot_{userid}",  # e.g. pullrequests_bot_dependabot
                )
                # Humans (and bots with no bot-specific rules)
                rule_order_humans = (
                    "{issue_type}_{event_category}",  # e.g. pullrequests_comment
                    "{issue_type}",  # e.g. pullrequests
                )

                rule_dict = {
                    "issue_type": github_issue_type,
                    "event_category": event_category,
                    "userid": userid.replace("[bot]", ""),  # Only bot rules use this, so the bot tag is implied anyway.
                }

                # If bot, we remove the [bot] in the user ID and check the bot rules
                if is_bot(userid):
                    print(f"{userid} is a known bot, expanding rule-set")
                    for rule in rule_order_bots:
                        key = rule.format(**rule_dict)
                        if key in scheme and scheme[key]:  # If we have this scheme and it is non-empty, return it
                            return scheme[key]
                # Human rules (also applies to bots with no specific rules for them)
                for rule in rule_order_humans:
                    key = rule.format(**rule_dict)
                    if key in scheme and scheme[key]:  # If we have this scheme and it is non-empty, return it
                        return scheme[key]
                # return self.config["default_recipient"]  # No (non-empty) scheme found, return default git recipient

            elif itype == "commit" and "commits" in scheme:
                return scheme["commits"]
            elif itype == "jira":
                return scheme.get("jira_options", self.config["jira"]["default_options"])
        if itype == "jira":
            return self.config["jira"]["default_options"]
        return "dev@%s.apache.org" % project