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

Subscribers

People subscribed via source and target branches

to status/vote changes: