[llvm] f4c18a4 - [Utils] Delete find_interesting_reviews.py script (#196347)

via llvm-commits llvm-commits at lists.llvm.org
Thu May 7 08:20:28 PDT 2026


Author: Aiden Grossman
Date: 2026-05-07T08:20:23-07:00
New Revision: f4c18a4d0796ced3a73bd453c807f41538b979be

URL: https://github.com/llvm/llvm-project/commit/f4c18a4d0796ced3a73bd453c807f41538b979be
DIFF: https://github.com/llvm/llvm-project/commit/f4c18a4d0796ced3a73bd453c807f41538b979be.diff

LOG: [Utils] Delete find_interesting_reviews.py script (#196347)

This was phabricator specific which has not been around for a while now.

Added: 
    

Modified: 
    

Removed: 
    llvm/utils/Reviewing/find_interesting_reviews.py


################################################################################
diff  --git a/llvm/utils/Reviewing/find_interesting_reviews.py b/llvm/utils/Reviewing/find_interesting_reviews.py
deleted file mode 100644
index c006691079b64..0000000000000
--- a/llvm/utils/Reviewing/find_interesting_reviews.py
+++ /dev/null
@@ -1,775 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import print_function
-
-import argparse
-import email.mime.multipart
-import email.mime.text
-import logging
-import os.path
-import pickle
-import re
-import smtplib
-import subprocess
-import sys
-from datetime import datetime, timedelta
-from phabricator import Phabricator
-
-# Setting up a virtualenv to run this script can be done by running the
-# following commands:
-# $ virtualenv venv
-# $ . ./venv/bin/activate
-# $ pip install Phabricator
-
-GIT_REPO_METADATA = (("llvm-monorepo", "https://github.com/llvm/llvm-project"),)
-
-# The below PhabXXX classes represent objects as modelled by Phabricator.
-# The classes can be serialized to disk, to try and make sure that we don't
-# needlessly have to re-fetch lots of data from Phabricator, as that would
-# make this script unusably slow.
-
-
-class PhabObject:
-    OBJECT_KIND = None
-
-    def __init__(self, id):
-        self.id = id
-
-
-class PhabObjectCache:
-    def __init__(self, PhabObjectClass):
-        self.PhabObjectClass = PhabObjectClass
-        self.most_recent_info = None
-        self.oldest_info = None
-        self.id2PhabObjects = {}
-
-    def get_name(self):
-        return self.PhabObjectClass.OBJECT_KIND + "sCache"
-
-    def get(self, id):
-        if id not in self.id2PhabObjects:
-            self.id2PhabObjects[id] = self.PhabObjectClass(id)
-        return self.id2PhabObjects[id]
-
-    def get_ids_in_cache(self):
-        return list(self.id2PhabObjects.keys())
-
-    def get_objects(self):
-        return list(self.id2PhabObjects.values())
-
-    DEFAULT_DIRECTORY = "PhabObjectCache"
-
-    def _get_pickle_name(self, directory):
-        file_name = "Phab" + self.PhabObjectClass.OBJECT_KIND + "s.pickle"
-        return os.path.join(directory, file_name)
-
-    def populate_cache_from_disk(self, directory=DEFAULT_DIRECTORY):
-        """
-        FIXME: consider if serializing to JSON would bring interoperability
-        advantages over serializing to pickle.
-        """
-        try:
-            f = open(self._get_pickle_name(directory), "rb")
-        except IOError as err:
-            print("Could not find cache. Error message: {0}. Continuing...".format(err))
-        else:
-            with f:
-                try:
-                    d = pickle.load(f)
-                    self.__dict__.update(d)
-                except EOFError as err:
-                    print(
-                        "Cache seems to be corrupt. "
-                        + "Not using cache. Error message: {0}".format(err)
-                    )
-
-    def write_cache_to_disk(self, directory=DEFAULT_DIRECTORY):
-        if not os.path.exists(directory):
-            os.makedirs(directory)
-        with open(self._get_pickle_name(directory), "wb") as f:
-            pickle.dump(self.__dict__, f)
-        print(
-            "wrote cache to disk, most_recent_info= {0}".format(
-                datetime.fromtimestamp(self.most_recent_info)
-                if self.most_recent_info is not None
-                else None
-            )
-        )
-
-
-class PhabReview(PhabObject):
-    OBJECT_KIND = "Review"
-
-    def __init__(self, id):
-        PhabObject.__init__(self, id)
-
-    def update(self, title, dateCreated, dateModified, author):
-        self.title = title
-        self.dateCreated = dateCreated
-        self.dateModified = dateModified
-        self.author = author
-
-    def setPhabDiffs(self, phabDiffs):
-        self.phabDiffs = phabDiffs
-
-
-class PhabUser(PhabObject):
-    OBJECT_KIND = "User"
-
-    def __init__(self, id):
-        PhabObject.__init__(self, id)
-
-    def update(self, phid, realName):
-        self.phid = phid
-        self.realName = realName
-
-
-class PhabHunk:
-    def __init__(self, rest_api_hunk):
-        self.oldOffset = int(rest_api_hunk["oldOffset"])
-        self.oldLength = int(rest_api_hunk["oldLength"])
-        # self.actual_lines_changed_offset will contain the offsets of the
-        # lines that were changed in this hunk.
-        self.actual_lines_changed_offset = []
-        offset = self.oldOffset
-        inHunk = False
-        hunkStart = -1
-        contextLines = 3
-        for line in rest_api_hunk["corpus"].split("\n"):
-            if line.startswith("+"):
-                # line is a new line that got introduced in this patch.
-                # Do not record it as a changed line.
-                if inHunk is False:
-                    inHunk = True
-                    hunkStart = max(self.oldOffset, offset - contextLines)
-                continue
-            if line.startswith("-"):
-                # line was changed or removed from the older version of the
-                # code. Record it as a changed line.
-                if inHunk is False:
-                    inHunk = True
-                    hunkStart = max(self.oldOffset, offset - contextLines)
-                offset += 1
-                continue
-            # line is a context line.
-            if inHunk is True:
-                inHunk = False
-                hunkEnd = offset + contextLines
-                self.actual_lines_changed_offset.append((hunkStart, hunkEnd))
-            offset += 1
-        if inHunk is True:
-            hunkEnd = offset + contextLines
-            self.actual_lines_changed_offset.append((hunkStart, hunkEnd))
-
-        # The above algorithm could result in adjacent or overlapping ranges
-        # being recorded into self.actual_lines_changed_offset.
-        # Merge the adjacent and overlapping ranges in there:
-        t = []
-        lastRange = None
-        for start, end in self.actual_lines_changed_offset + [
-            (sys.maxsize, sys.maxsize)
-        ]:
-            if lastRange is None:
-                lastRange = (start, end)
-            else:
-                if lastRange[1] >= start:
-                    lastRange = (lastRange[0], end)
-                else:
-                    t.append(lastRange)
-                    lastRange = (start, end)
-        self.actual_lines_changed_offset = t
-
-
-class PhabChange:
-    def __init__(self, rest_api_change):
-        self.oldPath = rest_api_change["oldPath"]
-        self.hunks = [PhabHunk(h) for h in rest_api_change["hunks"]]
-
-
-class PhabDiff(PhabObject):
-    OBJECT_KIND = "Diff"
-
-    def __init__(self, id):
-        PhabObject.__init__(self, id)
-
-    def update(self, rest_api_results):
-        self.revisionID = rest_api_results["revisionID"]
-        self.dateModified = int(rest_api_results["dateModified"])
-        self.dateCreated = int(rest_api_results["dateCreated"])
-        self.changes = [PhabChange(c) for c in rest_api_results["changes"]]
-
-
-class ReviewsCache(PhabObjectCache):
-    def __init__(self):
-        PhabObjectCache.__init__(self, PhabReview)
-
-
-class UsersCache(PhabObjectCache):
-    def __init__(self):
-        PhabObjectCache.__init__(self, PhabUser)
-
-
-reviews_cache = ReviewsCache()
-users_cache = UsersCache()
-
-
-def init_phab_connection():
-    phab = Phabricator()
-    phab.update_interfaces()
-    return phab
-
-
-def update_cached_info(
-    phab,
-    cache,
-    phab_query,
-    order,
-    record_results,
-    max_nr_entries_per_fetch,
-    max_nr_days_to_cache,
-):
-    q = phab
-    LIMIT = max_nr_entries_per_fetch
-    for query_step in phab_query:
-        q = getattr(q, query_step)
-    results = q(order=order, limit=LIMIT)
-    most_recent_info, oldest_info = record_results(cache, results, phab)
-    oldest_info_to_fetch = datetime.fromtimestamp(most_recent_info) - timedelta(
-        days=max_nr_days_to_cache
-    )
-    most_recent_info_overall = most_recent_info
-    cache.write_cache_to_disk()
-    after = results["cursor"]["after"]
-    print("after: {0!r}".format(after))
-    print("most_recent_info: {0}".format(datetime.fromtimestamp(most_recent_info)))
-    while (
-        after is not None and datetime.fromtimestamp(oldest_info) > oldest_info_to_fetch
-    ):
-        need_more_older_data = (
-            cache.oldest_info is None
-            or datetime.fromtimestamp(cache.oldest_info) > oldest_info_to_fetch
-        )
-        print(
-            (
-                "need_more_older_data={0} cache.oldest_info={1} "
-                + "oldest_info_to_fetch={2}"
-            ).format(
-                need_more_older_data,
-                datetime.fromtimestamp(cache.oldest_info)
-                if cache.oldest_info is not None
-                else None,
-                oldest_info_to_fetch,
-            )
-        )
-        need_more_newer_data = (
-            cache.most_recent_info is None or cache.most_recent_info < most_recent_info
-        )
-        print(
-            (
-                "need_more_newer_data={0} cache.most_recent_info={1} "
-                + "most_recent_info={2}"
-            ).format(need_more_newer_data, cache.most_recent_info, most_recent_info)
-        )
-        if not need_more_older_data and not need_more_newer_data:
-            break
-        results = q(order=order, after=after, limit=LIMIT)
-        most_recent_info, oldest_info = record_results(cache, results, phab)
-        after = results["cursor"]["after"]
-        print("after: {0!r}".format(after))
-        print("most_recent_info: {0}".format(datetime.fromtimestamp(most_recent_info)))
-        cache.write_cache_to_disk()
-    cache.most_recent_info = most_recent_info_overall
-    if after is None:
-        # We did fetch all records. Mark the cache to contain all info since
-        # the start of time.
-        oldest_info = 0
-    cache.oldest_info = oldest_info
-    cache.write_cache_to_disk()
-
-
-def record_reviews(cache, reviews, phab):
-    most_recent_info = None
-    oldest_info = None
-    for reviewInfo in reviews["data"]:
-        if reviewInfo["type"] != "DREV":
-            continue
-        id = reviewInfo["id"]
-        # phid = reviewInfo["phid"]
-        dateModified = int(reviewInfo["fields"]["dateModified"])
-        dateCreated = int(reviewInfo["fields"]["dateCreated"])
-        title = reviewInfo["fields"]["title"]
-        author = reviewInfo["fields"]["authorPHID"]
-        phabReview = cache.get(id)
-        if (
-            "dateModified" not in phabReview.__dict__
-            or dateModified > phabReview.dateModified
-        ):
-            
diff _results = phab.
diff erential.query
diff s(revisionIDs=[id])
-            
diff _ids = sorted(
diff _results.keys())
-            phabDiffs = []
-            for 
diff _id in 
diff _ids:
-                
diff Info = 
diff _results[
diff _id]
-                d = PhabDiff(
diff _id)
-                d.update(
diff Info)
-                phabDiffs.append(d)
-            phabReview.update(title, dateCreated, dateModified, author)
-            phabReview.setPhabDiffs(phabDiffs)
-            print(
-                "Updated D{0} modified on {1} ({2} 
diff s)".format(
-                    id, datetime.fromtimestamp(dateModified), len(phabDiffs)
-                )
-            )
-
-        if most_recent_info is None:
-            most_recent_info = dateModified
-        elif most_recent_info < dateModified:
-            most_recent_info = dateModified
-
-        if oldest_info is None:
-            oldest_info = dateModified
-        elif oldest_info > dateModified:
-            oldest_info = dateModified
-    return most_recent_info, oldest_info
-
-
-def record_users(cache, users, phab):
-    most_recent_info = None
-    oldest_info = None
-    for info in users["data"]:
-        if info["type"] != "USER":
-            continue
-        id = info["id"]
-        phid = info["phid"]
-        dateModified = int(info["fields"]["dateModified"])
-        # dateCreated = int(info["fields"]["dateCreated"])
-        realName = info["fields"]["realName"]
-        phabUser = cache.get(id)
-        phabUser.update(phid, realName)
-        if most_recent_info is None:
-            most_recent_info = dateModified
-        elif most_recent_info < dateModified:
-            most_recent_info = dateModified
-        if oldest_info is None:
-            oldest_info = dateModified
-        elif oldest_info > dateModified:
-            oldest_info = dateModified
-    return most_recent_info, oldest_info
-
-
-PHABCACHESINFO = (
-    (
-        reviews_cache,
-        ("
diff erential", "revision", "search"),
-        "updated",
-        record_reviews,
-        5,
-        7,
-    ),
-    (users_cache, ("user", "search"), "newest", record_users, 100, 1000),
-)
-
-
-def load_cache():
-    for cache, phab_query, order, record_results, _, _ in PHABCACHESINFO:
-        cache.populate_cache_from_disk()
-        print(
-            "Loaded {0} nr entries: {1}".format(
-                cache.get_name(), len(cache.get_ids_in_cache())
-            )
-        )
-        print(
-            "Loaded {0} has most recent info: {1}".format(
-                cache.get_name(),
-                datetime.fromtimestamp(cache.most_recent_info)
-                if cache.most_recent_info is not None
-                else None,
-            )
-        )
-
-
-def update_cache(phab):
-    load_cache()
-    for (
-        cache,
-        phab_query,
-        order,
-        record_results,
-        max_nr_entries_per_fetch,
-        max_nr_days_to_cache,
-    ) in PHABCACHESINFO:
-        update_cached_info(
-            phab,
-            cache,
-            phab_query,
-            order,
-            record_results,
-            max_nr_entries_per_fetch,
-            max_nr_days_to_cache,
-        )
-        ids_in_cache = cache.get_ids_in_cache()
-        print("{0} objects in {1}".format(len(ids_in_cache), cache.get_name()))
-        cache.write_cache_to_disk()
-
-
-def get_most_recent_reviews(days):
-    newest_reviews = sorted(reviews_cache.get_objects(), key=lambda r: -r.dateModified)
-    if len(newest_reviews) == 0:
-        return newest_reviews
-    most_recent_review_time = datetime.fromtimestamp(newest_reviews[0].dateModified)
-    cut_off_date = most_recent_review_time - timedelta(days=days)
-    result = []
-    for review in newest_reviews:
-        if datetime.fromtimestamp(review.dateModified) < cut_off_date:
-            return result
-        result.append(review)
-    return result
-
-
-# All of the above code is about fetching data from Phabricator and caching it
-# on local disk. The below code contains the actual "business logic" for this
-# script.
-
-_userphid2realname = None
-
-
-def get_real_name_from_author(user_phid):
-    global _userphid2realname
-    if _userphid2realname is None:
-        _userphid2realname = {}
-        for user in users_cache.get_objects():
-            _userphid2realname[user.phid] = user.realName
-    return _userphid2realname.get(user_phid, "unknown")
-
-
-def print_most_recent_reviews(phab, days, filter_reviewers):
-    msgs = []
-
-    def add_msg(msg):
-        msgs.append(msg)
-        print(msg.encode("utf-8"))
-
-    newest_reviews = get_most_recent_reviews(days)
-    add_msg(
-        "These are the reviews that look interesting to be reviewed. "
-        + "The report below has 2 sections. The first "
-        + "section is organized per review; the second section is organized "
-        + "per potential reviewer.\n"
-    )
-    oldest_review = newest_reviews[-1] if len(newest_reviews) > 0 else None
-    oldest_datetime = (
-        datetime.fromtimestamp(oldest_review.dateModified) if oldest_review else None
-    )
-    add_msg(
-        (
-            "The report below is based on analyzing the reviews that got "
-            + "touched in the past {0} days (since {1}). "
-            + "The script found {2} such reviews.\n"
-        ).format(days, oldest_datetime, len(newest_reviews))
-    )
-    reviewer2reviews_and_scores = {}
-    for i, review in enumerate(newest_reviews):
-        matched_reviewers = find_reviewers_for_review(review)
-        matched_reviewers = filter_reviewers(matched_reviewers)
-        if len(matched_reviewers) == 0:
-            continue
-        add_msg(
-            (
-                "{0:>3}. https://reviews.llvm.org/D{1} by {2}\n     {3}\n"
-                + "     Last updated on {4}"
-            ).format(
-                i,
-                review.id,
-                get_real_name_from_author(review.author),
-                review.title,
-                datetime.fromtimestamp(review.dateModified),
-            )
-        )
-        for reviewer, scores in matched_reviewers:
-            add_msg(
-                "    potential reviewer {0}, score {1}".format(
-                    reviewer,
-                    "(" + "/".join(["{0:.1f}%".format(s) for s in scores]) + ")",
-                )
-            )
-            if reviewer not in reviewer2reviews_and_scores:
-                reviewer2reviews_and_scores[reviewer] = []
-            reviewer2reviews_and_scores[reviewer].append((review, scores))
-
-    # Print out a summary per reviewer.
-    for reviewer in sorted(reviewer2reviews_and_scores.keys()):
-        reviews_and_scores = reviewer2reviews_and_scores[reviewer]
-        reviews_and_scores.sort(key=lambda rs: rs[1], reverse=True)
-        add_msg(
-            "\n\nSUMMARY FOR {0} (found {1} reviews):".format(
-                reviewer, len(reviews_and_scores)
-            )
-        )
-        for review, scores in reviews_and_scores:
-            add_msg(
-                "[{0}] https://reviews.llvm.org/D{1} '{2}' by {3}".format(
-                    "/".join(["{0:.1f}%".format(s) for s in scores]),
-                    review.id,
-                    review.title,
-                    get_real_name_from_author(review.author),
-                )
-            )
-    return "\n".join(msgs)
-
-
-def get_git_cmd_output(cmd):
-    output = None
-    try:
-        logging.debug(cmd)
-        output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
-    except subprocess.CalledProcessError as e:
-        logging.debug(str(e))
-    if output is None:
-        return None
-    return output.decode("utf-8", errors="ignore")
-
-
-reAuthorMail = re.compile("^author-mail <([^>]*)>.*$")
-
-
-def parse_blame_output_line_porcelain(blame_output_lines):
-    email2nr_occurences = {}
-    if blame_output_lines is None:
-        return email2nr_occurences
-    for line in blame_output_lines:
-        m = reAuthorMail.match(line)
-        if m:
-            author_email_address = m.group(1)
-            if author_email_address not in email2nr_occurences:
-                email2nr_occurences[author_email_address] = 1
-            else:
-                email2nr_occurences[author_email_address] += 1
-    return email2nr_occurences
-
-
-class BlameOutputCache:
-    def __init__(self):
-        self.cache = {}
-
-    def _populate_cache_for(self, cache_key):
-        assert cache_key not in self.cache
-        git_repo, base_revision, path = cache_key
-        cmd = (
-            "git -C {0} blame --encoding=utf-8 --date iso -f -e -w "
-            + "--line-porcelain {1} -- {2}"
-        ).format(git_repo, base_revision, path)
-        blame_output = get_git_cmd_output(cmd)
-        self.cache[cache_key] = (
-            blame_output.split("\n") if blame_output is not None else None
-        )
-        # FIXME: the blame cache could probably be made more effective still if
-        # instead of storing the requested base_revision in the cache, the last
-        # revision before the base revision this file/path got changed in gets
-        # stored. That way multiple project revisions for which this specific
-        # file/patch hasn't changed would get cache hits (instead of misses in
-        # the current implementation).
-
-    def get_blame_output_for(
-        self, git_repo, base_revision, path, start_line=-1, end_line=-1
-    ):
-        cache_key = (git_repo, base_revision, path)
-        if cache_key not in self.cache:
-            self._populate_cache_for(cache_key)
-        assert cache_key in self.cache
-        all_blame_lines = self.cache[cache_key]
-        if all_blame_lines is None:
-            return None
-        if start_line == -1 and end_line == -1:
-            return all_blame_lines
-        assert start_line >= 0
-        assert end_line >= 0
-        assert end_line <= len(all_blame_lines)
-        assert start_line <= len(all_blame_lines)
-        assert start_line <= end_line
-        return all_blame_lines[start_line:end_line]
-
-    def get_parsed_git_blame_for(
-        self, git_repo, base_revision, path, start_line=-1, end_line=-1
-    ):
-        return parse_blame_output_line_porcelain(
-            self.get_blame_output_for(
-                git_repo, base_revision, path, start_line, end_line
-            )
-        )
-
-
-blameOutputCache = BlameOutputCache()
-
-
-def find_reviewers_for_
diff _heuristic(
diff ):
-    # Heuristic 1: assume good reviewers are the ones that touched the same
-    # lines before as this patch is touching.
-    # Heuristic 2: assume good reviewers are the ones that touched the same
-    # files before as this patch is touching.
-    reviewers2nr_lines_touched = {}
-    reviewers2nr_files_touched = {}
-    # Assume last revision before 
diff  was modified is the revision the 
diff 
-    # applies to.
-    assert len(GIT_REPO_METADATA) == 1
-    git_repo = os.path.join("git_repos", GIT_REPO_METADATA[0][0])
-    cmd = 'git -C {0} rev-list -n 1 --before="{1}" main'.format(
-        git_repo,
-        datetime.fromtimestamp(
diff .dateModified).strftime("%Y-%m-%d %H:%M:%s"),
-    )
-    base_revision = get_git_cmd_output(cmd).strip()
-    logging.debug("Base revision={0}".format(base_revision))
-    for change in 
diff .changes:
-        path = change.oldPath
-        # Compute heuristic 1: look at context of patch lines.
-        for hunk in change.hunks:
-            for start_line, end_line in hunk.actual_lines_changed_offset:
-                # Collect git blame results for authors in those ranges.
-                for (
-                    reviewer,
-                    nr_occurences,
-                ) in blameOutputCache.get_parsed_git_blame_for(
-                    git_repo, base_revision, path, start_line, end_line
-                ).items():
-                    if reviewer not in reviewers2nr_lines_touched:
-                        reviewers2nr_lines_touched[reviewer] = 0
-                    reviewers2nr_lines_touched[reviewer] += nr_occurences
-        # Compute heuristic 2: don't look at context, just at files touched.
-        # Collect git blame results for authors in those ranges.
-        for reviewer, nr_occurences in blameOutputCache.get_parsed_git_blame_for(
-            git_repo, base_revision, path
-        ).items():
-            if reviewer not in reviewers2nr_files_touched:
-                reviewers2nr_files_touched[reviewer] = 0
-            reviewers2nr_files_touched[reviewer] += 1
-
-    # Compute "match scores"
-    total_nr_lines = sum(reviewers2nr_lines_touched.values())
-    total_nr_files = len(
diff .changes)
-    reviewers_matchscores = [
-        (
-            reviewer,
-            (
-                reviewers2nr_lines_touched.get(reviewer, 0) * 100.0 / total_nr_lines
-                if total_nr_lines != 0
-                else 0,
-                reviewers2nr_files_touched[reviewer] * 100.0 / total_nr_files
-                if total_nr_files != 0
-                else 0,
-            ),
-        )
-        for reviewer, nr_lines in reviewers2nr_files_touched.items()
-    ]
-    reviewers_matchscores.sort(key=lambda i: i[1], reverse=True)
-    return reviewers_matchscores
-
-
-def find_reviewers_for_review(review):
-    # Process the newest 
diff  first.
-    
diff s = sorted(review.phabDiffs, key=lambda d: d.dateModified, reverse=True)
-    if len(
diff s) == 0:
-        return
-    
diff  = 
diff s[0]
-    matched_reviewers = find_reviewers_for_
diff _heuristic(
diff )
-    # Show progress, as this is a slow operation:
-    sys.stdout.write(".")
-    sys.stdout.flush()
-    logging.debug("matched_reviewers: {0}".format(matched_reviewers))
-    return matched_reviewers
-
-
-def update_git_repos():
-    git_repos_directory = "git_repos"
-    for name, url in GIT_REPO_METADATA:
-        dirname = os.path.join(git_repos_directory, name)
-        if not os.path.exists(dirname):
-            cmd = "git clone {0} {1}".format(url, dirname)
-            output = get_git_cmd_output(cmd)
-        cmd = "git -C {0} pull --rebase".format(dirname)
-        output = get_git_cmd_output(cmd)
-
-
-def send_emails(email_addresses, sender, msg):
-    s = smtplib.SMTP()
-    s.connect()
-    for email_address in email_addresses:
-        email_msg = email.mime.multipart.MIMEMultipart()
-        email_msg["From"] = sender
-        email_msg["To"] = email_address
-        email_msg["Subject"] = "LLVM patches you may be able to review."
-        email_msg.attach(email.mime.text.MIMEText(msg.encode("utf-8"), "plain"))
-        # python 3.x: s.send_message(email_msg)
-        s.sendmail(email_msg["From"], email_msg["To"], email_msg.as_string())
-    s.quit()
-
-
-def filter_reviewers_to_report_for(people_to_look_for):
-    # The below is just an example filter, to only report potential reviews
-    # to do for the people that will receive the report email.
-    return lambda potential_reviewers: [
-        r for r in potential_reviewers if r[0] in people_to_look_for
-    ]
-
-
-def main():
-    parser = argparse.ArgumentParser(
-        description="Match open reviews to potential reviewers."
-    )
-    parser.add_argument(
-        "--no-update-cache",
-        dest="update_cache",
-        action="store_false",
-        default=True,
-        help="Do not update cached Phabricator objects",
-    )
-    parser.add_argument(
-        "--email-report",
-        dest="email_report",
-        nargs="*",
-        default="",
-        help="A email addresses to send the report to.",
-    )
-    parser.add_argument(
-        "--sender",
-        dest="sender",
-        default="",
-        help="The email address to use in 'From' on messages emailed out.",
-    )
-    parser.add_argument(
-        "--email-addresses",
-        dest="email_addresses",
-        nargs="*",
-        help="The email addresses (as known by LLVM git) of "
-        + "the people to look for reviews for.",
-    )
-    parser.add_argument("--verbose", "-v", action="count")
-
-    args = parser.parse_args()
-
-    if args.verbose >= 1:
-        logging.basicConfig(level=logging.DEBUG)
-
-    people_to_look_for = [e.decode("utf-8") for e in args.email_addresses]
-    logging.debug(
-        "Will look for reviews that following contributors could "
-        + "review: {}".format(people_to_look_for)
-    )
-    logging.debug("Will email a report to: {}".format(args.email_report))
-
-    phab = init_phab_connection()
-
-    if args.update_cache:
-        update_cache(phab)
-
-    load_cache()
-    update_git_repos()
-    msg = print_most_recent_reviews(
-        phab,
-        days=1,
-        filter_reviewers=filter_reviewers_to_report_for(people_to_look_for),
-    )
-
-    if args.email_report != []:
-        send_emails(args.email_report, args.sender, msg)
-
-
-if __name__ == "__main__":
-    main()


        


More information about the llvm-commits mailing list