2 # Small event handler to automatically open URLs and file
3 # bug reports at a bugzilla of your choiche
5 # This class requires python2.4 because of the urllib2 usage
8 def seppuku_spliturl(url):
10 Split GET URL to return the host base and the query
14 (uri,query) = urllib.splitquery(url)
16 for par in query.split("&"):
17 (key,value) = urllib.splitvalue(par)
18 key = urllib.unquote(key)
19 value = urllib.unquote(value)
26 def seppuku_login(opener, login, user, password):
28 We need to post to query.cgi with the parameters
29 Bugzilla_login and Bugzilla_password and will scan
30 the resulting page then
32 @param opened = cookie enabled urllib2 opener
33 @param login = http://bugzilla.openmoko.org/cgi-bin/bugzilla/query.cgi?
34 @param user = Your username
35 @param password = Your password
38 param = urllib.urlencode( {"GoAheadAndLogIn" : 1, "Bugzilla_login" : user, "Bugzilla_password" : password } )
39 result = opener.open(login + param)
41 if result.code != 200:
44 if not '<a href="relogin.cgi">Log out</a>' in txt:
49 def seppuku_find_bug_report_old():
50 from HTMLParser import HTMLParser
52 class BugQueryExtractor(HTMLParser):
55 STATE_FOUND_NUMBER = 2
59 STATE_FOUND_PLATFORM = 6
60 STATE_FOUND_STATUS = 7
61 STATE_FOUND_WHATEVER = 8 # I don't know this field
62 STATE_FOUND_DESCRIPTION =9
65 HTMLParser.__init__(self)
66 self.state = self.STATE_NONE
69 def handle_starttag(self, tag, attr):
70 if self.state == self.STATE_NONE and tag.lower() == "tr":
71 if len(attr) == 1 and attr[0] == ('class', 'bz_normal bz_P2 '):
72 self.state = self.STATE_FOUND_TR
73 elif self.state == self.STATE_FOUND_TR and tag.lower() == "td":
76 def handle_endtag(self, tag):
77 if tag.lower() == "tr":
78 if self.state != self.STATE_NONE:
79 self.bugs.append( (self.bug,self.status) )
80 self.state = self.STATE_NONE
81 if self.state > 1 and tag.lower() == "td":
84 def handle_data(self,data):
91 if self.state == self.STATE_FOUND_NUMBER:
93 elif self.state == self.STATE_FOUND_STATUS:
99 return BugQueryExtractor()
103 def seppuku_find_bug_report(opener, query, product, component, bugname):
105 Find a bug report with the sane name and return the bug id
108 @param opener = urllib2 opener
109 @param query = e.g. https://bugzilla.openmoko.org/cgi-bin/bugzilla/query.cgi?
110 @param product = search for this product
111 @param component = search for this component
112 @param bugname = the bug to search for
114 https://bugzilla.openmoko.org/cgi-bin/bugzilla/buglist.cgi?short_desc_type=substring&short_desc=manual+test+bug&product=OpenMoko&emailreporter2=1&emailtype2=substring&email2=freyther%40yahoo.com
115 but it does not support ctype=csv...
117 result = opener.open("%(query)s?product=%(product)s&component=%(component)s&short_desc_type=substring&short_desc=%(bugname)s" % vars())
118 if result.code != 200:
119 raise "Can not query the bugzilla at all"
121 scanner = seppuku_find_bug_report_old()
123 if len(scanner.result()) == 0:
125 else: # silently pick the first result
126 (number,status) = scanner.result()[0]
127 return (not status in ["CLOS", "RESO", "VERI"],number)
129 def seppuku_reopen_bug(poster, file, product, component, bug_number, bugname, text):
131 Reopen a bug report and append to the comment
133 Same as with opening a new report, some bits need to be inside the url
135 http://bugzilla.openmoko.org/cgi-bin/bugzilla/process_bug.cgi?id=239&bug_file_loc=http%3A%2F%2F&version=2007&longdesclength=2&product=OpenMoko&component=autobuilds&comment=bla&priority=P2&bug_severity=normal&op_sys=Linux&rep_platform=Neo1973&knob=reopen&target_milestone=Phase+0&short_desc=foo
139 (uri, param) = seppuku_spliturl( file )
142 param["product"] = product
143 param["component"] = component
144 param["longdesclength"] = 2
145 param["short_desc"] = bugname
146 param["knob"] = "reopen"
147 param["id"] = bug_number
148 param["comment"] = text
151 result = poster.open( uri, param )
152 except urllib2.HTTPError, e:
160 if result.code != 200:
165 def seppuku_file_bug(poster, file, product, component, bugname, text):
167 Create a completely new bug report
170 http://bugzilla.openmoko.org/cgi-bin/bugzilla/post_bug.cgi?bug_file_loc=http%3A%2F%2F&version=2007&product=OpenMoko&component=autobuilds&short_desc=foo&comment=bla&priority=P2&bug_severity=normal&op_sys=Linux&rep_platform=Neo1973
172 You are forced to add some default values to the bugzilla query and stop with '&'
174 @param opener urllib2 opener
175 @param file The url used to file a bug report
176 @param product Product
177 @param component Component
178 @param bugname Name of the to be created bug
183 (uri, param) = seppuku_spliturl( file )
184 param["product"] = product
185 param["component"] = component
186 param["short_desc"] = bugname
187 param["comment"] = text
190 result = poster.open( uri, param )
191 except urllib2.HTTPError, e:
199 if result.code != 200:
204 def seppuku_create_attachment(poster, attach_query, product, component, bug_number, text, file):
207 Create a new attachment for the failed report
212 bb.note("Can't create an attachment, the bug is not present")
216 param = { "bugid" : bug_number, "action" : "insert", "data" : file, "description" : "Build log", "ispatch" : "0", "contenttypemethod" : "list", "contenttypeselection" : "text/plain", "comment" : text }
219 result = poster.open( attach_query, param )
220 except urllib2.HTTPError, e:
229 if result.code != 200:
235 addhandler seppuku_eventhandler
236 python seppuku_eventhandler() {
238 Report task failures to the bugzilla
239 and succeeded builds to the box
241 from bb.event import NotHandled, getName
242 from bb import data, mkdirhier, build
245 # Try to load our exotic libraries
247 import MultipartPostHandler
249 bb.note("You need to put the MultipartPostHandler into your PYTHONPATH. Download it from http://pipe.scs.fsu.edu/PostHandler/MultipartPostHandler.py")
253 import urllib2, cookielib
255 bb.note("Failed to import the cookielib and urllib2, make sure to use python2.4")
260 name = getName(event)
261 if name == "PkgFailed":
262 if not bb.data.getVar('SEPPUKU_AUTOBUILD', data, True) == "0":
263 build.exec_task('do_clean', data)
264 elif name == "TaskFailed" or name == "NoProvider":
265 cj = cookielib.CookieJar()
266 opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
267 poster = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj),MultipartPostHandler.MultipartPostHandler)
268 login = bb.data.getVar("SEPPUKU_LOGIN", data, True)
269 query = bb.data.getVar("SEPPUKU_QUERY", data, True)
270 newbug = bb.data.getVar("SEPPUKU_NEWREPORT", data, True)
271 reopen = bb.data.getVar("SEPPUKU_ADDCOMMENT", data, True)
272 attach = bb.data.getVar("SEPPUKU_ATTACHMENT", data, True)
273 user = bb.data.getVar("SEPPUKU_USER", data, True)
274 passw = bb.data.getVar("SEPPUKU_PASS", data, True)
275 product = bb.data.getVar("SEPPUKU_PRODUCT", data, True)
276 component = bb.data.getVar("SEPPUKU_COMPONENT", data, True)
278 if not seppuku_login(opener, login, user, passw):
279 bb.note("Login to bugzilla failed")
282 print "Logged into the box"
284 if name == "TaskFailed":
285 bugname = "%(package)s-%(pv)s-%(pr)s-%(task)s" % { "package" : bb.data.getVar("PN", data, True),
286 "pv" : bb.data.getVar("PV", data, True),
287 "pr" : bb.data.getVar("PR", data, True),
289 log_file = glob.glob("%s/log.%s.*" % (bb.data.getVar('T', event.data, True), event.task))
290 text = "The package failed to build at %s" % bb.data.getVar('DATETIME', data, True)
291 file = open(log_file[0], 'r')
292 elif name == "NoProvider":
293 bugname = "noprovider for %s runtime: %s" % (event.getItem, event.getisRuntime)
294 text = "Please fix it"
299 (bug_open, bug_number) = seppuku_find_bug_report(opener, query, product, component, bugname)
301 bb.note("Bug is open: %s and bug number: %s" % (bug_open, bug_number))
303 # The bug is present and still open, no need to attach an error log
304 if bug_number and bug_open:
305 bb.note("The bug is known as '%s'" % bug_number)
308 if bug_number and not bug_open:
309 if not seppuku_reopen_bug(poster, reopen, product, component, bug_number, bugname, text):
310 bb.note("Failed to reopen the bug report")
311 elif not seppuku_file_bug(poster, newbug, product, component, bugname, text):
312 bb.note("Filing a bugreport failed")
314 # get the new bug number and create an attachment
315 (bug_open, bug_number) = seppuku_find_bug_report(opener, query, product, component, bugname)
318 if not seppuku_create_attachment(poster, attach, product, component, bug_number, text, file):
319 bb.note("Failed to attach the build log")