/[gentoo]/src/gwn/gmn_bugzie.py
Gentoo

Contents of /src/gwn/gmn_bugzie.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.15 - (show annotations) (download) (as text)
Mon Sep 1 20:02:04 2014 UTC (4 years, 3 months ago) by hwoarang
Branch: MAIN
CVS Tags: HEAD
Changes since 1.14: +4 -5 lines
File MIME type: text/x-python
gmn_bugzie.py: Argument handling fix up

1 #!/usr/bin/python
2
3 import httplib, string, time, sys, os
4 import urllib2
5
6 def strip(x):
7 '''Removes quotation marks
8 from beginning and end of fields'''
9 if len(x):
10 if x[0]=='\"':
11 x=x[1:]
12 if x[-1]=='\"':
13 x=x[0:-1]
14
15 return x
16
17 def get_page(site, uri, header):
18 '''Given a site, the name of the resource to get,
19 and a dictionary of header values, returns the
20 requested resource. Will return an empty string
21 if something goes wrong.'''
22 conn = urllib2.Request("https://"+site+uri, None, header)
23 response = urllib2.urlopen(conn)
24 page = response.read()
25 return page
26
27 def group_results(result, group_by, details):
28 '''Given a column to group by, will accumulate a count
29 of rows sharing the same value in the grouped column.
30 By default, this function returns a list of lists, each of which
31 have the group_by value in position 0, and the count in position 1.
32
33 There is also a sort of poor aggregation mechanism that works sort of
34 like sql group by. With an empty details parameter, this function works
35 like 'select group_by, count(*) bug_count from bugzilla group by group_by'. Adding
36 values to the details list (for instance [assigned_to_realname]) will make
37 the result more like 'select group_by, count(*), [column for column in details]
38 from bugzilla group by group_by, [column for column in details]'.'''
39
40
41 lines = result.split("\n")
42
43 field_names = string.split(lines[0],',')
44
45 by_group = {}
46 detailDict = {}
47 for line in lines[1:]:
48 b = dict(map((lambda k,v: (k,v)), field_names, string.split(line,',')))
49 by_group[b[group_by]] = by_group.get(b[group_by],0) + 1
50 #capture the first result for each unique group_by
51 if (by_group[b[group_by]] == 1):
52 detailDict[b[group_by]] = b
53
54
55 count_by_group = [[bug_count, group] for group, bug_count in by_group.items()]
56 count_by_group.sort()
57 count_by_group.reverse()
58 count_by_group = [[group, bug_count, [detailDict[group][detailKey] for detailKey in details]] for bug_count, group in count_by_group]
59 return count_by_group
60
61 def sum_results(result):
62 '''Given a CSV generated from reports.cgi will return a dictionary
63 with the sum for each row. The grand total will also be added
64 to the 'Total' entry.'''
65
66 lines = result.split("\n")
67
68 result_dict = {}
69 total = 0
70
71 for line in lines[1:]:
72 split_list = line.split(',')
73 summed = sum(map(lambda x: int(x), split_list[1:]))
74 total += summed
75 result_dict[split_list[0]] = summed
76 result_dict['Total'] = total
77
78 return result_dict
79
80 # get dates from command line, else use now (time.time())
81 starttime = time.gmtime(time.time() - (60 * 60 * 24 * 31))
82 endtime = time.gmtime(time.time() - (60 * 60 * 24 * 1))
83
84 if len(sys.argv) > 1:
85 if len(sys.argv) >= 2:
86 starttime = time.strptime(str(int(sys.argv[1])), "%Y%m%d")
87 if len(sys.argv) == 3:
88 endtime = time.strptime(str(int(sys.argv[2])), "%Y%m%d")
89 else:
90 print "Usage: " + os.path.basename(sys.argv[0]) + " [start-date] [end-date]"
91 print "dates must be passed in 'yyyymmdd' format"
92 print "if no dates are specified then it defaults to a date range of the last 30 days"
93
94 dateimg = time.strftime("%Y-%m",endtime)
95 datefor = time.strftime("%Y/%m",endtime)
96
97 #1. Set up the dates we care about...a 30 day window that ends yesterday
98 date_to = time.strftime("%Y-%m-%d", endtime)
99 date_to_display = time.strftime("%d %B %Y", endtime)
100 date_from = time.strftime("%Y-%m-%d", starttime)
101 date_from_display = time.strftime("%d %B %Y", starttime)
102
103 #2. Setup a cookie to tell bugzilla the columns we care about
104 header = {"Cookie" : "COLUMNLIST=bug_severity assigned_to assigned_to_realname bug_status"}
105
106 #3. Pass off the queries we care about to bugzilla
107 closed_report = get_page("bugs.gentoo.org", "/buglist.cgi?bug_status=RESOLVED&bug_status=CLOSED&chfield=bug_status&resolution=FIXED&ctype=csv&chfieldfrom=%s&chfieldto=%s" % (date_from, date_to), header)
108 closed_nofix_report = get_page("bugs.gentoo.org", "/buglist.cgi?bug_status=RESOLVED&bug_status=CLOSED&chfield=bug_status&resolution=NEEDINFO&resolution=WONTFIX&resolution=CANTFIX&resolution=INVALID&resolution=UPSTREAM&ctype=csv&chfieldfrom=%s&chfieldto=%s" % (date_from, date_to), header)
109 duplicate_report = get_page("bugs.gentoo.org", "/buglist.cgi?bug_status=RESOLVED&bug_status=CLOSED&chfield=bug_status&resolution=DUPLICATE&ctype=csv&chfieldfrom=%s&chfieldto=%s" % (date_from, date_to), header)
110 opened_report = get_page("bugs.gentoo.org", "/buglist.cgi?bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&chfield=[Bug+creation]&ctype=csv&chfieldfrom=%s&chfieldto=%s" % (date_from, date_to), header)
111 new_report = get_page("bugs.gentoo.org", "/buglist.cgi?chfield=[Bug+creation]&chfieldfrom=%s&chfieldto=%s&ctype=csv" % (date_from, date_to), header)
112 total_opened_report = get_page("bugs.gentoo.org", "/report.cgi?x_axis_field=bug_status&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&format=table&action=wrap&ctype=csv", header)
113 severities_report = get_page("bugs.gentoo.org", "/report.cgi?x_axis_field=bug_status&y_axis_field=bug_severity&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_severity=blocker&bug_severity=critical&bug_severity=major&format=table&action=wrap&ctype=csv", header)
114
115 #4. In a few cases, we want more than just counts. So, we group
116 # opened and closed bugs by assigned to.
117 groups_that_closed_most = group_results(closed_report, "\"assigned_to\"", ["\"assigned_to_realname\""])
118 groups_that_opened_most = group_results(opened_report, "\"assigned_to\"", ["\"assigned_to_realname\""])
119
120 #5. For bug counts, just counting the lines that were returned is sufficient
121 new_bug_count = len(new_report.split("\n")) - 1
122 closed_bug_count = len(closed_report.split("\n")) - 1
123 duplicate_bug_count = len(duplicate_report.split("\n")) - 1
124 closed_nofix_bug_count = len(closed_nofix_report.split("\n")) - 1
125
126 #6. For the total open bugs and severities we need to sum the results
127 # generated from reports.cgi
128 total_open_bug_count = sum_results(total_opened_report).get('Total', 0)
129 severities = sum_results(severities_report)
130
131 # Calculate remaining closed/opened
132 total_closed = 0
133 total_opened = 0
134 for i in range(0, len(groups_that_closed_most) - 1):
135 total_closed += groups_that_closed_most[i][1]
136 for i in range(0, len(groups_that_opened_most) - 1):
137 total_opened += groups_that_opened_most[i][1]
138
139 #7. We have every value we need, now build the report
140
141 print "<h1>Bugzilla</h1>"
142
143 print "The Gentoo community uses <a href=\"https://bugs.gentoo.org\">Bugzilla</a> to record and " + \
144 "track bugs, notifications, suggestions and other interactions with the " + \
145 "development team."
146
147 print "<h2>Activity</h2>"
148 print"The following tables and charts summarize the " + \
149 "activity on Bugzilla between <strong>%s</strong> and <strong>%s</strong>. Not fixed means bugs that were " % (date_from_display, date_to_display) + \
150 "resolved as NEEDINFO, WONTFIX, CANTFIX, INVALID or UPSTREAM. "
151
152 print """<a
153 href="http://blogs.gentoo.org/news/files/%s/gmn-activity-%s.png"><img
154 class="size-full wp-image-219 aligncenter" alt="gmn-activity-%s"
155 src="http://blogs.gentoo.org/news/files/%s/gmn-activity-%s.png"
156 width="500" height="300" /></a>""" % (datefor,dateimg,dateimg,datefor,dateimg)
157 print "[table]"
158 print "Bug Activity, Number"
159 print "New, %d" % new_bug_count
160 print "Closed, %d" % closed_bug_count
161 print "Not fixed, %d" % closed_nofix_bug_count
162 print "Duplicates, %d" % duplicate_bug_count
163 print "Total, %d" % total_open_bug_count
164 print "Blocker, %d" % severities.get('"blocker"',0)
165 print "Critical, %d" % severities.get('"critical"',0)
166 print "Major, %d" % severities.get('"major"',0)
167 print "[/table]"
168
169 cleft = 0
170 #8. Closed Bugs
171 print "\n<h2>Closed bug ranking</h2>\n"
172 print "The following table outlines the teams and developers with the most bugs resolved during this period"
173 print "[table]"
174 print "Rank, Team/Developer, Bug Count"
175 for i in range(0,9):
176 print "%d, %s, %d" % (i+1, strip(groups_that_closed_most[i][2][0]), int(groups_that_closed_most[i][1]))
177 cleft += groups_that_closed_most[i][1]
178 print "10, Others, %s" % (total_closed - cleft)
179 print "[/table]"
180
181 print """<a
182 href="http://blogs.gentoo.org/news/files/%s/gmn-closed-%s.png"><img
183 class="aligncenter size-full wp-image-220" alt="gmn-closed-%s"
184 src="http://blogs.gentoo.org/news/files/%s/gmn-closed-%s.png"
185 width="500" height="250" /></a>""" % (datefor,dateimg,dateimg,datefor,dateimg)
186 #9. Open Bugs
187 #print "\n\n==Open Bugs==\n"
188 oleft = 0
189 print "\n<h2>Assigned bug ranking</h2>\n"
190 print "The developers and teams who have been assigned the most bugs during this period are as follows.\n"
191 print "[table]"
192 print "Rank, Team/Developer, Bug Count"
193 for i in range(0,9):
194 print "%d, %s, %s" % (i+1, strip(groups_that_opened_most[i][2][0]), str(groups_that_opened_most[i][1]))
195 oleft += groups_that_opened_most[i][1]
196 print "10, Others, %s" % (total_opened - oleft)
197 print "[/table]"
198 print """<a
199 href="http://blogs.gentoo.org/news/files/%s/gmn-opened-%s.png"><img
200 class="aligncenter size-full wp-image-220" alt="gmn-opened-%s"
201 src="http://blogs.gentoo.org/news/files/%s/gmn-opened-%s.png" width="500"
202 height="250" /></a> """ % (datefor,dateimg,dateimg,datefor,dateimg)

  ViewVC Help
Powered by ViewVC 1.1.20