Merge lp:~fgiff/linaro-android-bot-review/create-bot-metrics into lp:linaro-android-bot-review

Proposed by Frans Gifford
Status: Merged
Approved by: Frans Gifford
Approved revision: 79
Merged at revision: 79
Proposed branch: lp:~fgiff/linaro-android-bot-review/create-bot-metrics
Merge into: lp:linaro-android-bot-review
Diff against target: 104 lines (+100/-0)
1 file modified
bot-stats.py (+100/-0)
To merge this branch: bzr merge lp:~fgiff/linaro-android-bot-review/create-bot-metrics
Reviewer Review Type Date Requested Status
Frans Gifford (community) Approve
Review via email: mp+81443@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Frans Gifford (fgiff) wrote :

New code, doesn't affect existing functionality.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'bot-stats.py'
2--- bot-stats.py 1970-01-01 00:00:00 +0000
3+++ bot-stats.py 2011-11-07 11:57:23 +0000
4@@ -0,0 +1,100 @@
5+#!/usr/bin/env python
6+import urllib2
7+import json
8+import argparse
9+
10+# Headers needed to use JSON-RPC API.
11+headers = {"Accept": "application/json,application/jsonrequest",
12+ "Content-Type": "application/json; charset=UTF-8"}
13+
14+def allQueryNext(review_host, query, pos, pageSize):
15+ """Use JSON-RPC api to query for reviews.
16+ See ChangeListServiceImpl.java in gerrit source for definition."""
17+ url = "http://%s/gerrit/rpc/ChangeListService" % review_host
18+ data = '{"jsonrpc":"2.0","method":"allQueryNext","params":["%s", "%s", %i],"id":1}' % (
19+ query, pos, pageSize)
20+ req = urllib2.Request(url, data, headers)
21+ resp = urllib2.urlopen(req)
22+ return json.loads(resp.read())
23+
24+
25+def changeDetail(review_host, change_id):
26+ """Use JSON-RPC api to query a particular review.
27+ See ChangeDetailServiceImpl.java in gerrit source for definition
28+ we rename the parameter to avoid collision with python reserved word."""
29+ url = "http://%s/gerrit/rpc/ChangeDetailService" % review_host
30+ data = '{"jsonrpc":"2.0","method":"changeDetail","params":[{"id":%i}],"id":1}' % (
31+ change_id)
32+ req = urllib2.Request(url, data, headers)
33+ resp = urllib2.urlopen(req)
34+ return json.loads(resp.read())
35+
36+
37+def main():
38+ parser = argparse.ArgumentParser(
39+ description="Report bot usage metrics.")
40+ # Reviewer to look for.
41+ parser.add_argument('--bot-email', default="linaro.androud.build.bot@gmail.com")
42+ # Gerrit server.
43+ parser.add_argument('--review-host', default="review.android.git.linaro.org")
44+ args = parser.parse_args()
45+ bot_email = args.bot_email
46+ review_host = args.review_host
47+
48+ # Exclude ineligible projects.
49+ excluded_projects = ["-platform/manifest",
50+ "-device/linaro/beagleboard",
51+ "-device/linaro/origen",
52+ "-device/linaro/snowball",
53+ "-device/linaro/imx53"]
54+ # Time period to report on.
55+ time = "-age:4w"
56+ print "In time period '%s' there were:" % time
57+
58+ # Get number of completed reviews.
59+ reviews = allQueryNext(review_host, "%s status:merged %s" % (time, " ".join(excluded_projects)), "z", 200)
60+ print "%3i review(s) completed" % len(reviews["result"]["changes"])
61+ # Get number of completed reviews with bot as a reviewer.
62+ reviews = allQueryNext(review_host, "%s status:merged reviewer:%s %s" % (time, bot_email, " ".join(excluded_projects)), "z", 200)
63+ print "%3i review(s) completed with bot reviewer" % len(reviews["result"]["changes"])
64+ # Get bot's uid in gerrit so we can parse gerrit's data.
65+ reviewer_id = (detail["id"]["id"] for detail in changeDetail(review_host, allQueryNext(review_host, "reviewer:%s" % bot_email, "z", 1)["result"]["changes"][0]["id"]["id"])["result"]["accounts"]["accounts"] if "fullName" in detail and detail["preferredEmail"] == bot_email).next()
66+ # Filter all completed reviews for ones with comments from bot.
67+ reviews = (detail for detail in (changeDetail(review_host, change["id"]["id"])["result"] for change in allQueryNext(review_host, "%s status:merged %s" % (time, " ".join(excluded_projects)), "z", 200)["result"]["changes"]) if filter(lambda x: "id" in x and x["id"] == reviewer_id, detail["accounts"]["accounts"]))
68+ # Draw 'league table' of Played (run), Won (passed) and Lost (failed).
69+ print """Bot feedback summary:
70+| Review | Builds | Tests | Author | Authored | Committer | Committed |
71+|--------| P W L | P W L |------------------------|------------------|------------------------|------------------|"""
72+ # Count reviews with one or more bot comments.
73+ participation_count = 0
74+ for r in reviews:
75+ # Capture changeid, first line of message in the gerrit comment. (Bot
76+ # comments always start with "Patch Set #\n\n"), author and committer.
77+ try:
78+ details = {"id": r["change"]["changeId"]["id"], "comments": map(lambda x: x["message"].splitlines()[2], filter(lambda x: "author" in x and "id" in x["author"] and x["author"]["id"] == reviewer_id, r["messages"])), "author": r["currentDetail"]["info"]["author"], "committer": r["currentDetail"]["info"]["committer"]}
79+ except IndexError:
80+ # This happens if comment doesn't start with "Patch Set #\n\n"
81+ # We expect this for patch submissions from human reviewers,
82+ # but we don't expect this for any bot comments.
83+ # Handling the error allows us to run the metrics against
84+ # human reviewers too.
85+ continue
86+ print "| %6s | %2i %2i %2i | %2i %2i %2i | %22s | %16s | %22s | %16s |" % (
87+ details["id"],
88+ len(filter(lambda x: x.startswith("Started build"), details["comments"])),
89+ len(filter(lambda x: x.startswith("Build status: SUCCESS"), details["comments"])),
90+ len(filter(lambda x: x.startswith("Build status: FAILURE"), details["comments"])),
91+ len(filter(lambda x: x.startswith("Build status: SUCCESS"), details["comments"])),
92+ len(filter(lambda x: x.startswith("Test status: PASS"), details["comments"])),
93+ len(filter(lambda x: x.startswith("Test status: FAIL"), details["comments"])),
94+ details["author"]["name"],
95+ details["author"]["when"][0:16],
96+ details["committer"]["name"],
97+ details["committer"]["when"][0:16])
98+ participation_count += 1
99+ print "%3i review(s) completed with bot feedback" % participation_count
100+
101+
102+if __name__ == "__main__":
103+ main()
104+

Subscribers

People subscribed via source and target branches

to all changes: