Merge lp:~jibel/canonical-qa-tracking/isotesters_breakdown into lp:canonical-qa-tracking

Proposed by Jean-Baptiste Lallement
Status: Needs review
Proposed branch: lp:~jibel/canonical-qa-tracking/isotesters_breakdown
Merge into: lp:canonical-qa-tracking
Diff against target: 227 lines (+205/-0)
2 files modified
sru-tools/thankyou-testers (+5/-0)
statistic-scripts/isotesters_breakdown.py (+200/-0)
To merge this branch: bzr merge lp:~jibel/canonical-qa-tracking/isotesters_breakdown
Reviewer Review Type Date Requested Status
Brian Murray Needs Fixing
Review via email: mp+56718@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Brian Murray (brian-murray) wrote :

python-psycopg2 is the more commonly used python module to connect to postgresql databases and I'd prefer we use that one although I don't think it'll make much difference.

review: Needs Fixing
513. By Jean-Baptiste Lallement

* port to psycopg2.
* added port parameter
* pass variable using execute rather than string interpolation

Revision history for this message
Jean-Baptiste Lallement (jibel) wrote :

I also removed the miserable string interpolation to pass the argument to the query.

Unmerged revisions

513. By Jean-Baptiste Lallement

* port to psycopg2.
* added port parameter
* pass variable using execute rather than string interpolation

512. By Jean-Baptiste Lallement

* Added a script to report the repartition between Canonical vs Community
  for ISO Testing

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'sru-tools/thankyou-testers'
2--- sru-tools/thankyou-testers 2010-09-24 10:13:11 +0000
3+++ sru-tools/thankyou-testers 2011-04-11 22:23:36 +0000
4@@ -119,6 +119,8 @@
5 xlpm_m = xlpm_pattern.search(xlpm_header)
6 if xlpm_m:
7 modifier=xlpm_m.groupdict() # {display_name, lp_id}
8+ else:
9+ continue
10 action_date = time.mktime(sent_date)
11 try:
12 srubugs[bug_id].append((sender[0], sender[1], modifier, action_date))
13@@ -218,6 +220,9 @@
14 person = lp.people[personId]
15 except KeyError:
16 continue
17+ except AttributeError, e:
18+ print e
19+ continue
20 if person:
21 logging.debug("= Found: [%s] %s" % (v[2]['id'],person.name))
22 people[person.name] = {
23
24=== added file 'statistic-scripts/isotesters_breakdown.py'
25--- statistic-scripts/isotesters_breakdown.py 1970-01-01 00:00:00 +0000
26+++ statistic-scripts/isotesters_breakdown.py 2011-04-11 22:23:36 +0000
27@@ -0,0 +1,200 @@
28+#!/usr/bin/python
29+# Copyright 2011 Canonical, Ltd
30+# Author: Jean-Baptiste Lallement <jean-baptiste.lallement@canonical.com>
31+#
32+# Licensed under the GNU General Public License, version 3.
33+#
34+# This script retrieves the list of iso testers for a milestone and splits the
35+# the results between tests done by Canonical vs Community for each flavor
36+
37+
38+from launchpadlib.launchpad import Launchpad
39+import logging
40+import sys
41+import psycopg2
42+from optparse import OptionParser
43+
44+logging.basicConfig(level=logging.DEBUG)
45+
46+lp = None
47+
48+db_name="qatracker"
49+
50+def lp_init():
51+ """ init the connection to lp"""
52+ return Launchpad.login_with("lookup-canonical-employee", "production")
53+
54+def db_init(db_host, db_name, db_user, db_password, db_port = "5432"):
55+ """ init the connection to the database"""
56+ try:
57+ db=psycopg2.connect(user=db_user, password=db_password, host=db_host,
58+ port=db_port, database=db_name)
59+ cursor=db.cursor()
60+ except:
61+ sys.exit("Failed to connect to the DB")
62+
63+ return (db, cursor)
64+
65+
66+def get_isotesters(cursor, milestone_title):
67+ """ Returns the list of testers for a milestone corresponding to
68+ the milestone_title.
69+ Partial matching on the title is used to return more than one milestone
70+
71+ :param milestone_title: Title of the milestone following 'like' syntax
72+
73+ :return: List of testers
74+ """
75+
76+ sql = """SELECT m.title
77+,SUBSTRING(CASE WHEN p.title like 'Ubuntu Studio%%' then 'UbuntuStudio' ELSE p.title END FROM '^[^ ]*')
78+,u.name
79+,u.mail
80+,s.value
81+,COUNT('*')
82+FROM qatracker_product p
83+JOIN qatracker_build b ON b.productid = p.id
84+JOIN qatracker_milestone m ON b.milestoneid = m.id
85+JOIN qatracker_testcase t ON t.productid = p.id
86+JOIN qatracker_result r ON ( r.testcaseid = t.id AND r.buildid = b.id )
87+JOIN users u ON ( u.uid = r.reporterid )
88+LEFT JOIN qawebsite_user_setting_info s ON ( s.userid = u.uid AND s.settingid = 1 )
89+WHERE m.siteid = 1
90+AND p.title not like 'Upgrade%%'
91+AND p.title not like 'Generic%%'
92+AND m.title ilike %s
93+GROUP BY m.id, m.title, p.title, u.name, u.mail, s.value
94+ORDER BY m.id,p.title"""
95+
96+ cursor.execute(sql, (milestone_title +'%',) )
97+ return cursor.fetchall()
98+
99+def isCanonicalEmployee(person):
100+ """ Return true if we think the person is a Canonical employee
101+
102+ We assume that any member of a canonical team is a canonical employee
103+ """
104+ canonical_teams = ('canonical', 'landscape')
105+ for tm in person.memberships_details:
106+ for ct in canonical_teams:
107+ if ct in tm.team.name:
108+ return True
109+ return False
110+
111+def resolve_employees(testers):
112+ """ Tries to guess if a user is a canonical employee """
113+ global lp
114+ result = []
115+ users = {}
116+ for row in testers:
117+ #(milestone, distro, name, mail, lpid, testcount) = line.strip().split(';')
118+ (milestone, distro, name, mail, lpid, testcount) = row
119+ if name not in users:
120+ users[name] = False
121+ person = None
122+ try:
123+ person = lp.people[lpid]
124+ except:
125+ logging.debug("No person found with id [%s]" % lpid)
126+
127+ if not person:
128+ try:
129+ persons = lp.people.findPerson(text = mail)
130+ person = persons[0]
131+ lpid = person.name
132+ except:
133+ logging.debug("No person found with email [%s]" % mail)
134+
135+ if person:
136+ users[name] = isCanonicalEmployee(person)
137+
138+ result.append((milestone, distro, name, mail, lpid, testcount, users[name]))
139+ return result
140+
141+def print_report(testers):
142+ """Print the report for a list of testers
143+
144+ :param testers: list of testers with employee status set
145+ """
146+
147+ report = {}
148+ distros = []
149+
150+ for row in testers:
151+ (milestone, distro, name, mail, lpid, testcount, iscanonical) = row
152+
153+ if milestone not in report:
154+ report[milestone] = {}
155+
156+ if not distro in distros:
157+ distros.append(distro)
158+
159+ if not distro in report[milestone]:
160+ report[milestone][distro] = [0,0]
161+
162+ if iscanonical:
163+ report[milestone][distro][0] += int(testcount)
164+ else:
165+ report[milestone][distro][1] += int(testcount)
166+
167+
168+ print "Milestone;%s;;;;;" % ";;;;;".join(sorted(distros))
169+ print ";" + "Canonical;Community;Total;%Canonical;%Community;" * len(distro)
170+
171+ for milestone, row in sorted(report.iteritems()):
172+ sys.stdout.write("%s;" % milestone)
173+ for distro in sorted(distros):
174+ try:
175+ res = row[distro]
176+ sys.stdout.write("%d;%d;%d;%.2f;%.2f;" % (res[0],
177+ res[1],
178+ res[0]+res[1],
179+ res[0]*100.0/(res[0]+res[1]),
180+ res[1]*100.0/(res[0]+res[1])))
181+ except KeyError:
182+ sys.stdout.write("0;" * 5)
183+
184+ print
185+
186+
187+def main():
188+ """ Main loop"""
189+ global lp
190+ global db_host, db_name, db_username, db_password
191+
192+ usage = "Usage: %prog [options] milestone_title"
193+
194+ parser = OptionParser(usage=usage)
195+
196+ parser.add_option('-U', '--username', dest="db_user" , help='database Username')
197+ parser.add_option('-P', '--password', dest="db_password" , help='database Username')
198+ parser.add_option('-H', '--host', dest="db_host" , help='database Username')
199+ parser.add_option('-p', '--port', dest="db_port" , default="5432", help='database port')
200+
201+ (options, args) = parser.parse_args()
202+
203+ if len(args) != 1:
204+ parser.error("Incorrect number of arguments")
205+
206+ milestone_title = args[0]
207+
208+ db_host = options.db_host
209+ db_user= options.db_user
210+ db_password = options.db_password
211+ db_port = options.db_port
212+
213+
214+ if not db_host or not db_user or not db_password:
215+ parser.error('DB Hostname, username and password are mandatory')
216+
217+ lp = lp_init()
218+ (db, cursor) = db_init(db_host, db_name, db_user, db_password, db_port)
219+ testers = get_isotesters(cursor, milestone_title)
220+ cursor.close()
221+ db.close()
222+
223+ employees = resolve_employees(testers)
224+ print_report(employees)
225+
226+if __name__ == "__main__":
227+ main()

Subscribers

People subscribed via source and target branches

to status/vote changes: