tof-voters: Record name and email in analysis
With this we can make the data a little easier to consume.
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Change-Id: Id1cc858dc002adfdf35e2a7bb790dc4872d9c570
diff --git a/tof-voters/README.md b/tof-voters/README.md
index 1d733cc..dd61232 100644
--- a/tof-voters/README.md
+++ b/tof-voters/README.md
@@ -15,8 +15,7 @@
./voters analyze-commits --before "2022-01-01" --after "2021-06-30"
./voters analyze-reviews --before "2022-01-01" --after "2021-06-30"
./voters report
-cat data/report.json | \
- jq "with_entries(select(.value.qualified) | .value = .value.points)"
+jq '[ .[] | select(.qualified) | {(.name): .points} ] | add | to_entries | sort_by(.value) | reverse | from_entries' data/report.json
```
The above will yield a JSON dictionary of "users:points" where 'qualified' is
@@ -24,8 +23,8 @@
```json
{
- "user1": 16,
- "user2": 19,
+ "User Name 2": 19,
+ "User Name 1": 16,
...
}
```
diff --git a/tof-voters/libvoters/__init__.py b/tof-voters/libvoters/__init__.py
index a93a4bf..9a2c4a6 100644
--- a/tof-voters/libvoters/__init__.py
+++ b/tof-voters/libvoters/__init__.py
@@ -1 +1,18 @@
#!/usr/bin/python3
+
+from typing import TypedDict
+
+UserChanges = TypedDict(
+ "User", {"name": str, "email": str, "changes": list[int]}
+)
+
+
+def changes_factory():
+ return {"name": None, "email": None, "changes": list()}
+
+
+UserComments = TypedDict("User", {"name": str, "email": str, "comments": int})
+
+
+def comments_factory():
+ return {"name": None, "email": None, "comments": 0}
diff --git a/tof-voters/libvoters/subcmd/analyze-commits.py b/tof-voters/libvoters/subcmd/analyze-commits.py
index ea92ed1..7957319 100644
--- a/tof-voters/libvoters/subcmd/analyze-commits.py
+++ b/tof-voters/libvoters/subcmd/analyze-commits.py
@@ -8,6 +8,7 @@
from typing import Dict
import libvoters.acceptable as acceptable
+from libvoters import UserChanges, changes_factory
from libvoters.time import TimeOfDay, timestamp
@@ -36,7 +37,7 @@
before = timestamp(args.before, TimeOfDay.AM)
after = timestamp(args.after, TimeOfDay.PM)
- changes_per_user: Dict[str, list[int]] = defaultdict(list)
+ changes_per_user: Dict[str, UserChanges] = defaultdict(changes_factory)
for f in sorted(os.listdir(args.dir)):
path = os.path.join(args.dir, f)
@@ -69,7 +70,7 @@
project = data["project"]
id_number = data["number"]
- user = data["owner"]["username"]
+ username = data["owner"]["username"]
if not acceptable.project(project):
print("Rejected project:", project, id_number)
@@ -93,11 +94,14 @@
print("Rejected for limited changes:", project, id_number)
continue
- print(project, id_number, user)
+ print(project, id_number, username)
for f in touched_files:
print(f" {f}")
- changes_per_user[user].append(id_number)
+ user = changes_per_user[username]
+ user["name"] = data["owner"]["name"]
+ user["email"] = data["owner"]["email"]
+ user["changes"].append(id_number)
with open(os.path.join(args.dir, "commits.json"), "w") as outfile:
outfile.write(json.dumps(changes_per_user, indent=4))
diff --git a/tof-voters/libvoters/subcmd/analyze-reviews.py b/tof-voters/libvoters/subcmd/analyze-reviews.py
index d5ccade..244e9bc 100644
--- a/tof-voters/libvoters/subcmd/analyze-reviews.py
+++ b/tof-voters/libvoters/subcmd/analyze-reviews.py
@@ -8,6 +8,7 @@
from typing import Dict
import libvoters.acceptable as acceptable
+from libvoters import UserChanges, UserComments, changes_factory, comments_factory
from libvoters.time import TimeOfDay, timestamp
@@ -36,7 +37,7 @@
before = timestamp(args.before, TimeOfDay.AM)
after = timestamp(args.after, TimeOfDay.PM)
- changes_per_user: Dict[str, list[int]] = defaultdict(list)
+ changes_per_user: Dict[str, UserChanges] = defaultdict(changes_factory)
for f in sorted(os.listdir(args.dir)):
path = os.path.join(args.dir, f)
@@ -56,7 +57,9 @@
if not acceptable.project(project):
print("Rejected project:", project, id_number)
- comments_per_user: Dict[str, int] = defaultdict(int)
+ comments_per_user: Dict[str, UserComments] = defaultdict(
+ comments_factory
+ )
for patch_set in data["patchSets"]:
created_on = data["createdOn"]
@@ -75,14 +78,40 @@
if not acceptable.file(project, comment["file"]):
continue
- comments_per_user[reviewer] += 1
+ user = comments_per_user[reviewer]
+ user["name"] = comment["reviewer"]["name"]
+ # We actually have a case where a reviewer does not have an email recorded[1]:
+ #
+ # [1]: https://gerrit.openbmc.org/c/openbmc/phosphor-pid-control/+/60303/comment/ceff60b9_9d2debe0/
+ #
+ # {"file": "conf.hpp",
+ # "line": 39,
+ # "reviewer": {"name": "Akshat Jain", "username": "AkshatZen"},
+ # "message": "If we design SensorInput as base class and have derived ..."}
+ # Traceback (most recent call last):
+ # File "/mnt/host/andrew/home/andrew/src/openbmc/openbmc-tools/tof-voters/./voters", line 7, in <module>
+ # sys.exit(main())
+ # ^^^^^^
+ # File "/mnt/host/andrew/home/andrew/src/openbmc/openbmc-tools/tof-voters/libvoters/entry_point.py", line 33, in main
+ # return int(args.cmd.run(args))
+ # ^^^^^^^^^^^^^^^^^^
+ # File "/mnt/host/andrew/home/andrew/src/openbmc/openbmc-tools/tof-voters/libvoters/subcmd/analyze-reviews.py", line 82, in run
+ # user["email"] = comment["reviewer"]["email"]
+ # ~~~~~~~~~~~~~~~~~~~^^^^^^^^^
+ # KeyError: 'email'
+ if "email" in comment["reviewer"]:
+ user["email"] = comment["reviewer"]["email"]
+ user["comments"] += 1
print(project, id_number)
- for user, count in comments_per_user.items():
- if count < 3:
+ for username, review in comments_per_user.items():
+ if review["comments"] < 3:
continue
- print(" ", user, count)
- changes_per_user[user].append(id_number)
+ print(" ", user, review["comments"])
+ user = changes_per_user[username]
+ user["name"] = review["name"]
+ user["email"] = review["email"]
+ user["changes"].append(id_number)
with open(os.path.join(args.dir, "reviews.json"), "w") as outfile:
outfile.write(json.dumps(changes_per_user, indent=4))
diff --git a/tof-voters/libvoters/subcmd/report.py b/tof-voters/libvoters/subcmd/report.py
index 87aa713..87c87ca 100644
--- a/tof-voters/libvoters/subcmd/report.py
+++ b/tof-voters/libvoters/subcmd/report.py
@@ -31,9 +31,11 @@
with open(reviews_fp, "r") as reviews_file:
reviews = json.load(reviews_file)
- for user in sorted(set(commits.keys()).union(reviews.keys())):
- user_commits = len(commits.get(user, []))
- user_reviews = len(reviews.get(user, []))
+ contributions = commits | reviews
+
+ for user in sorted(contributions.keys()):
+ user_commits = len(commits.get(user, {}).get("changes", []))
+ user_reviews = len(reviews.get(user, {}).get("changes", []))
points = user_commits * 3 + user_reviews
print(user, points, user_commits, user_reviews)
@@ -41,6 +43,8 @@
qualified = points >= 15
results[user] = {
+ "name": contributions[user]["name"],
+ "email": contributions[user]["email"],
"qualified": qualified,
"points": points,
"commits": user_commits,
diff --git a/tof-voters/voters b/tof-voters/voters
index 75c105e..4129d84 100755
--- a/tof-voters/voters
+++ b/tof-voters/voters
@@ -1,7 +1,8 @@
#!/bin/env -S python3 -B
-from libvoters.entry_point import main
import sys
+from libvoters.entry_point import main
+
if __name__ == "__main__":
sys.exit(main())