1d0269de8SPatrick Williams#!/usr/bin/python3 2d0269de8SPatrick Williams 3d0269de8SPatrick Williamsimport argparse 4d0269de8SPatrick Williamsimport json 5d0269de8SPatrick Williamsimport os 6d0269de8SPatrick Williamsimport re 7d0269de8SPatrick Williamsfrom collections import defaultdict 8d0269de8SPatrick Williamsfrom typing import Dict 9d0269de8SPatrick Williams 10a3db66b3SPatrick Williamsimport libvoters.acceptable as acceptable 11*9217099cSGunnar Millsfrom libvoters import ( 12*9217099cSGunnar Mills UserChanges, 13*9217099cSGunnar Mills UserComments, 14*9217099cSGunnar Mills changes_factory, 15*9217099cSGunnar Mills comments_factory, 16*9217099cSGunnar Mills) 17a3db66b3SPatrick Williamsfrom libvoters.time import TimeOfDay, timestamp 18a3db66b3SPatrick Williams 19d0269de8SPatrick Williams 20d0269de8SPatrick Williamsclass subcmd: 21d0269de8SPatrick Williams def __init__(self, parser: argparse._SubParsersAction) -> None: 22d0269de8SPatrick Williams p = parser.add_parser( 23d0269de8SPatrick Williams "analyze-reviews", help="Determine points for reviews" 24d0269de8SPatrick Williams ) 25d0269de8SPatrick Williams 26d0269de8SPatrick Williams p.add_argument( 27d0269de8SPatrick Williams "--before", 28d0269de8SPatrick Williams "-b", 29d0269de8SPatrick Williams help="Before timestamp (YYYY-MM-DD)", 30d0269de8SPatrick Williams required=True, 31d0269de8SPatrick Williams ) 32d0269de8SPatrick Williams p.add_argument( 33d0269de8SPatrick Williams "--after", 34d0269de8SPatrick Williams "-a", 35d0269de8SPatrick Williams help="After timestamp (YYYY-MM-DD)", 36d0269de8SPatrick Williams required=True, 37d0269de8SPatrick Williams ) 38d0269de8SPatrick Williams 39d0269de8SPatrick Williams p.set_defaults(cmd=self) 40d0269de8SPatrick Williams 41d0269de8SPatrick Williams def run(self, args: argparse.Namespace) -> int: 42d0269de8SPatrick Williams before = timestamp(args.before, TimeOfDay.AM) 43d0269de8SPatrick Williams after = timestamp(args.after, TimeOfDay.PM) 44d0269de8SPatrick Williams 45ed5643f6SAndrew Jeffery changes_per_user: Dict[str, UserChanges] = defaultdict(changes_factory) 46d0269de8SPatrick Williams 47d0269de8SPatrick Williams for f in sorted(os.listdir(args.dir)): 48d0269de8SPatrick Williams path = os.path.join(args.dir, f) 49d0269de8SPatrick Williams if not os.path.isfile(path): 50d0269de8SPatrick Williams continue 51d0269de8SPatrick Williams 52a3db66b3SPatrick Williams if not re.match(r"[0-9]*\.json", f): 53d0269de8SPatrick Williams continue 54d0269de8SPatrick Williams 55d0269de8SPatrick Williams with open(path, "r") as file: 56d0269de8SPatrick Williams data = json.load(file) 57d0269de8SPatrick Williams 58d0269de8SPatrick Williams project = data["project"] 59d0269de8SPatrick Williams id_number = data["number"] 60d0269de8SPatrick Williams author = data["owner"]["username"] 61d0269de8SPatrick Williams 62d0269de8SPatrick Williams if not acceptable.project(project): 63d0269de8SPatrick Williams print("Rejected project:", project, id_number) 64d0269de8SPatrick Williams 65ed5643f6SAndrew Jeffery comments_per_user: Dict[str, UserComments] = defaultdict( 66ed5643f6SAndrew Jeffery comments_factory 67ed5643f6SAndrew Jeffery ) 68d0269de8SPatrick Williams 69d0269de8SPatrick Williams for patch_set in data["patchSets"]: 70d0269de8SPatrick Williams created_on = data["createdOn"] 71d0269de8SPatrick Williams 72d0269de8SPatrick Williams if created_on > before or created_on < after: 73d0269de8SPatrick Williams continue 74d0269de8SPatrick Williams 75d0269de8SPatrick Williams if "comments" not in patch_set: 76d0269de8SPatrick Williams continue 77d0269de8SPatrick Williams 78d0269de8SPatrick Williams for comment in patch_set["comments"]: 79d0269de8SPatrick Williams reviewer = comment["reviewer"]["username"] 80d0269de8SPatrick Williams 81d0269de8SPatrick Williams if reviewer == author: 82d0269de8SPatrick Williams continue 83d0269de8SPatrick Williams if not acceptable.file(project, comment["file"]): 84d0269de8SPatrick Williams continue 85d0269de8SPatrick Williams 86ed5643f6SAndrew Jeffery user = comments_per_user[reviewer] 87ed5643f6SAndrew Jeffery user["name"] = comment["reviewer"]["name"] 88ed5643f6SAndrew Jeffery # We actually have a case where a reviewer does not have an email recorded[1]: 89ed5643f6SAndrew Jeffery # 90ed5643f6SAndrew Jeffery # [1]: https://gerrit.openbmc.org/c/openbmc/phosphor-pid-control/+/60303/comment/ceff60b9_9d2debe0/ 91ed5643f6SAndrew Jeffery # 92ed5643f6SAndrew Jeffery # {"file": "conf.hpp", 93ed5643f6SAndrew Jeffery # "line": 39, 94ed5643f6SAndrew Jeffery # "reviewer": {"name": "Akshat Jain", "username": "AkshatZen"}, 95ed5643f6SAndrew Jeffery # "message": "If we design SensorInput as base class and have derived ..."} 96ed5643f6SAndrew Jeffery # Traceback (most recent call last): 97ed5643f6SAndrew Jeffery # File "/mnt/host/andrew/home/andrew/src/openbmc/openbmc-tools/tof-voters/./voters", line 7, in <module> 98ed5643f6SAndrew Jeffery # sys.exit(main()) 99ed5643f6SAndrew Jeffery # ^^^^^^ 100ed5643f6SAndrew Jeffery # File "/mnt/host/andrew/home/andrew/src/openbmc/openbmc-tools/tof-voters/libvoters/entry_point.py", line 33, in main 101ed5643f6SAndrew Jeffery # return int(args.cmd.run(args)) 102ed5643f6SAndrew Jeffery # ^^^^^^^^^^^^^^^^^^ 103ed5643f6SAndrew Jeffery # File "/mnt/host/andrew/home/andrew/src/openbmc/openbmc-tools/tof-voters/libvoters/subcmd/analyze-reviews.py", line 82, in run 104ed5643f6SAndrew Jeffery # user["email"] = comment["reviewer"]["email"] 105ed5643f6SAndrew Jeffery # ~~~~~~~~~~~~~~~~~~~^^^^^^^^^ 106ed5643f6SAndrew Jeffery # KeyError: 'email' 107ed5643f6SAndrew Jeffery if "email" in comment["reviewer"]: 108ed5643f6SAndrew Jeffery user["email"] = comment["reviewer"]["email"] 109ed5643f6SAndrew Jeffery user["comments"] += 1 110d0269de8SPatrick Williams 111d0269de8SPatrick Williams print(project, id_number) 112ed5643f6SAndrew Jeffery for username, review in comments_per_user.items(): 113ed5643f6SAndrew Jeffery if review["comments"] < 3: 114d0269de8SPatrick Williams continue 115ed5643f6SAndrew Jeffery print(" ", user, review["comments"]) 116ed5643f6SAndrew Jeffery user = changes_per_user[username] 117ed5643f6SAndrew Jeffery user["name"] = review["name"] 118ed5643f6SAndrew Jeffery user["email"] = review["email"] 119ed5643f6SAndrew Jeffery user["changes"].append(id_number) 120d0269de8SPatrick Williams 121d0269de8SPatrick Williams with open(os.path.join(args.dir, "reviews.json"), "w") as outfile: 122d0269de8SPatrick Williams outfile.write(json.dumps(changes_per_user, indent=4)) 123d0269de8SPatrick Williams 124d0269de8SPatrick Williams return 0 125