diff options
author | Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 2011-09-16 10:55:17 +0400 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2011-09-16 18:07:26 +0100 |
commit | 6be481711aa0a3782522fdd6de2e1ec52f4deed5 (patch) | |
tree | e68583d28b475e3fd9a93bd812fdc7d30bc30bdf /meta | |
parent | 849bf66e2871d227d1028ead60d7bc76bdf7aadb (diff) | |
download | poky-6be481711aa0a3782522fdd6de2e1ec52f4deed5.tar.gz |
bugzilla.bbclass: add a class to report build problems to bugzilla
Add a class to report build errors to bugzilla. Idea largely based on
sepukku.bbclass, however it's rewritten nearly fully to use XML-RPC
interface of bugzilla. Tested with bugzilla 4.0, other version might
require some sort of adaptation.
(From OE-Core rev: 20529035a4c0befb3c6bdbcb289a2de930fb143d)
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta')
-rw-r--r-- | meta/classes/bugzilla.bbclass | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/meta/classes/bugzilla.bbclass b/meta/classes/bugzilla.bbclass new file mode 100644 index 0000000000..801bd66d2f --- /dev/null +++ b/meta/classes/bugzilla.bbclass | |||
@@ -0,0 +1,186 @@ | |||
1 | # | ||
2 | # Small event handler to automatically open URLs and file | ||
3 | # bug reports at a bugzilla of your choiche | ||
4 | # it uses XML-RPC interface, so you must have it enabled | ||
5 | # | ||
6 | # Before using you must define BUGZILLA_USER, BUGZILLA_PASS credentials, | ||
7 | # BUGZILLA_XMLRPC - uri of xmlrpc.cgi, | ||
8 | # BUGZILLA_PRODUCT, BUGZILLA_COMPONENT - a place in BTS for build bugs | ||
9 | # BUGZILLA_VERSION - version against which to report new bugs | ||
10 | # | ||
11 | |||
12 | def bugzilla_find_bug_report(debug_file, server, args, bugname): | ||
13 | args['summary'] = bugname | ||
14 | bugs = server.Bug.search(args) | ||
15 | if len(bugs['bugs']) == 0: | ||
16 | print >> debug_file, "Bugs not found" | ||
17 | return (False,None) | ||
18 | else: # silently pick the first result | ||
19 | print >> debug_file, "Result of bug search is " | ||
20 | print >> debug_file, bugs | ||
21 | status = bugs['bugs'][0]['status'] | ||
22 | id = bugs['bugs'][0]['id'] | ||
23 | return (not status in ["CLOSED", "RESOLVED", "VERIFIED"],id) | ||
24 | |||
25 | def bugzilla_file_bug(debug_file, server, args, name, text, version): | ||
26 | args['summary'] = name | ||
27 | args['comment'] = text | ||
28 | args['version'] = version | ||
29 | args['op_sys'] = 'Linux' | ||
30 | args['platform'] = 'Other' | ||
31 | args['severity'] = 'normal' | ||
32 | args['priority'] = 'Normal' | ||
33 | try: | ||
34 | return server.Bug.create(args)['id'] | ||
35 | except Exception, e: | ||
36 | print >> debug_file, repr(e) | ||
37 | return None | ||
38 | |||
39 | def bugzilla_reopen_bug(debug_file, server, args, bug_number): | ||
40 | args['ids'] = [bug_number] | ||
41 | args['status'] = "CONFIRMED" | ||
42 | try: | ||
43 | server.Bug.update(args) | ||
44 | return True | ||
45 | except Exception, e: | ||
46 | print >> debug_file, repr(e) | ||
47 | return False | ||
48 | |||
49 | def bugzilla_create_attachment(debug_file, server, args, bug_number, text, file_name, log, logdescription): | ||
50 | args['ids'] = [bug_number] | ||
51 | args['file_name'] = file_name | ||
52 | args['summary'] = logdescription | ||
53 | args['content_type'] = "text/plain" | ||
54 | args['data'] = log | ||
55 | args['comment'] = text | ||
56 | try: | ||
57 | server.Bug.add_attachment(args) | ||
58 | return True | ||
59 | except Exception, e: | ||
60 | print >> debug_file, repr(e) | ||
61 | return False | ||
62 | |||
63 | def bugzilla_add_comment(debug_file, server, args, bug_number, text): | ||
64 | args['id'] = bug_number | ||
65 | args['comment'] = text | ||
66 | try: | ||
67 | server.Bug.add_comment(args) | ||
68 | return True | ||
69 | except Exception, e: | ||
70 | print >> debug_file, repr(e) | ||
71 | return False | ||
72 | |||
73 | addhandler bugzilla_eventhandler | ||
74 | python bugzilla_eventhandler() { | ||
75 | import bb, os, glob | ||
76 | import xmlrpclib, httplib | ||
77 | |||
78 | class ProxiedTransport(xmlrpclib.Transport): | ||
79 | def __init__(self, proxy, use_datetime = 0): | ||
80 | xmlrpclib.Transport.__init__(self, use_datetime) | ||
81 | self.proxy = proxy | ||
82 | self.user = None | ||
83 | self.password = None | ||
84 | |||
85 | def set_user(self, user): | ||
86 | self.user = user | ||
87 | |||
88 | def set_password(self, password): | ||
89 | self.password = password | ||
90 | |||
91 | def make_connection(self, host): | ||
92 | self.realhost = host | ||
93 | return httplib.HTTP(self.proxy) | ||
94 | |||
95 | def send_request(self, connection, handler, request_body): | ||
96 | connection.putrequest("POST", 'http://%s%s' % (self.realhost, handler)) | ||
97 | if self.user != None: | ||
98 | if self.password != None: | ||
99 | auth = "%s:%s" % (self.user, self.password) | ||
100 | else: | ||
101 | auth = self.user | ||
102 | connection.putheader("Proxy-authorization", "Basic " + base64.encodestring(auth)) | ||
103 | |||
104 | event = e | ||
105 | data = e.data | ||
106 | name = bb.event.getName(event) | ||
107 | if name == "MsgNote": | ||
108 | # avoid recursion | ||
109 | return | ||
110 | |||
111 | if name == "TaskFailed": | ||
112 | xmlrpc = bb.data.getVar("BUGZILLA_XMLRPC", data, True) | ||
113 | user = bb.data.getVar("BUGZILLA_USER", data, True) | ||
114 | passw = bb.data.getVar("BUGZILLA_PASS", data, True) | ||
115 | product = bb.data.getVar("BUGZILLA_PRODUCT", data, True) | ||
116 | compon = bb.data.getVar("BUGZILLA_COMPONENT", data, True) | ||
117 | version = bb.data.getVar("BUGZILLA_VERSION", data, True) | ||
118 | |||
119 | proxy = bb.data.getVar('http_proxy', data, True ) | ||
120 | if (proxy): | ||
121 | import urllib2 | ||
122 | s, u, p, hostport = urllib2._parse_proxy(proxy) | ||
123 | transport = ProxiedTransport(hostport) | ||
124 | else: | ||
125 | transport = None | ||
126 | |||
127 | server = xmlrpclib.ServerProxy(xmlrpc, transport=transport, verbose=0) | ||
128 | args = { | ||
129 | 'Bugzilla_login': user, | ||
130 | 'Bugzilla_password': passw, | ||
131 | 'product': product, | ||
132 | 'component': compon} | ||
133 | |||
134 | # evil hack to figure out what is going on | ||
135 | debug_file = open(os.path.join(bb.data.getVar("TMPDIR", data, True),"..","bugzilla-log"),"a") | ||
136 | |||
137 | file = None | ||
138 | bugname = "%(package)s-%(pv)s-autobuild" % { "package" : bb.data.getVar("PN", data, True), | ||
139 | "pv" : bb.data.getVar("PV", data, True), | ||
140 | } | ||
141 | log_file = glob.glob("%s/log.%s.*" % (bb.data.getVar('T', event.data, True), event.task)) | ||
142 | text = "The %s step in %s failed at %s for machine %s" % (e.task, bb.data.getVar("PN", data, True), bb.data.getVar('DATETIME', data, True), bb.data.getVar( 'MACHINE', data, True ) ) | ||
143 | if len(log_file) != 0: | ||
144 | print >> debug_file, "Adding log file %s" % log_file[0] | ||
145 | file = open(log_file[0], 'r') | ||
146 | log = file.read() | ||
147 | file.close(); | ||
148 | else: | ||
149 | print >> debug_file, "No log file found for the glob" | ||
150 | log = None | ||
151 | |||
152 | (bug_open, bug_number) = bugzilla_find_bug_report(debug_file, server, args.copy(), bugname) | ||
153 | print >> debug_file, "Bug is open: %s and bug number: %s" % (bug_open, bug_number) | ||
154 | |||
155 | # The bug is present and still open, attach an error log | ||
156 | if not bug_number: | ||
157 | bug_number = bugzilla_file_bug(debug_file, server, args.copy(), bugname, text, version) | ||
158 | if not bug_number: | ||
159 | print >> debug_file, "Couldn't acquire a new bug_numer, filing a bugreport failed" | ||
160 | else: | ||
161 | print >> debug_file, "The new bug_number: '%s'" % bug_number | ||
162 | elif not bug_open: | ||
163 | if not bugzilla_reopen_bug(debug_file, server, args.copy(), bug_number): | ||
164 | print >> debug_file, "Failed to reopen the bug #%s" % bug_number | ||
165 | else: | ||
166 | print >> debug_file, "Reopened the bug #%s" % bug_number | ||
167 | |||
168 | if bug_number and log: | ||
169 | print >> debug_file, "The bug is known as '%s'" % bug_number | ||
170 | desc = "Build log for machine %s" % (bb.data.getVar('MACHINE', data, True)) | ||
171 | if not bugzilla_create_attachment(debug_file, server, args.copy(), bug_number, text, log_file[0], log, desc): | ||
172 | print >> debug_file, "Failed to attach the build log for bug #%s" % bug_number | ||
173 | else: | ||
174 | print >> debug_file, "Created an attachment for '%s' '%s' '%s'" % (product, compon, bug_number) | ||
175 | else: | ||
176 | print >> debug_file, "Not trying to create an attachment for bug #%s" % bug_number | ||
177 | if not bugzilla_add_comment(debug_file, server, args.copy(), bug_number, text, ): | ||
178 | print >> debug_file, "Failed to create a comment the build log for bug #%s" % bug_number | ||
179 | else: | ||
180 | print >> debug_file, "Created an attachment for '%s' '%s' '%s'" % (product, compon, bug_number) | ||
181 | |||
182 | # store bug number for oestats-client | ||
183 | if bug_number: | ||
184 | bb.data.setVar('OESTATS_BUG_NUMBER', bug_number, data) | ||
185 | } | ||
186 | |||