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

Subscribers

People subscribed via source and target branches

to all changes: