Merge lp:~krytarik/ubuntu-bots/bugtracker-output into lp:ubuntu-bots
- bugtracker-output
- Merge into devel
Status: | Needs review |
---|---|
Proposed branch: | lp:~krytarik/ubuntu-bots/bugtracker-output |
Merge into: | lp:ubuntu-bots |
Diff against target: |
662 lines (+169/-171) 1 file modified
Bugtracker/plugin.py (+169/-171) |
To merge this branch: | bzr merge lp:~krytarik/ubuntu-bots/bugtracker-output |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu IRC Bots | Pending | ||
Benjamin Rubin | Pending | ||
Review via email: mp+311899@code.launchpad.net |
Commit message
Description of the change
Bugtracker: Make sure output fits maximum length of IRC messages, improve its formatting.
- 321. By Krytarik Raido
-
Bugtracker: Strip any leading or trailing spaces off bug report title.
- 322. By Krytarik Raido
-
Bugtracker: Ensure consistent casing of bug severity and status.
- 323. By Krytarik Raido
-
Bugtracker: Improve formatting of duplicate bug reports.
- 324. By Krytarik Raido
-
Bugtracker: Improve handling of bug assignee and extended info.
- 325. By Krytarik Raido
-
Bugtracker: Backport from Git.
<https://git.launchpad. net/~krytarik/ ubuntu- bots/+git/ ubuntu- bots>
Unmerged revisions
- 325. By Krytarik Raido
-
Bugtracker: Backport from Git.
<https://git.launchpad. net/~krytarik/ ubuntu- bots/+git/ ubuntu- bots> - 324. By Krytarik Raido
-
Bugtracker: Improve handling of bug assignee and extended info.
- 323. By Krytarik Raido
-
Bugtracker: Improve formatting of duplicate bug reports.
- 322. By Krytarik Raido
-
Bugtracker: Ensure consistent casing of bug severity and status.
- 321. By Krytarik Raido
-
Bugtracker: Strip any leading or trailing spaces off bug report title.
- 320. By Krytarik Raido
-
Bugtracker: Make sure output fits maximum length
of IRC messages, improve its formatting.
Preview Diff
1 | === modified file 'Bugtracker/plugin.py' | |||
2 | --- Bugtracker/plugin.py 2014-08-12 16:47:38 +0000 | |||
3 | +++ Bugtracker/plugin.py 2018-05-13 02:56:20 +0000 | |||
4 | @@ -2,6 +2,7 @@ | |||
5 | 2 | ### | 2 | ### |
6 | 3 | # Copyright (c) 2005-2007 Dennis Kaarsemaker | 3 | # Copyright (c) 2005-2007 Dennis Kaarsemaker |
7 | 4 | # Copyright (c) 2008-2010 Terence Simpson | 4 | # Copyright (c) 2008-2010 Terence Simpson |
8 | 5 | # Copyright (c) 2017- Krytarik Raido | ||
9 | 5 | # | 6 | # |
10 | 6 | # This program is free software; you can redistribute it and/or modify | 7 | # This program is free software; you can redistribute it and/or modify |
11 | 7 | # it under the terms of version 2 of the GNU General Public License as | 8 | # it under the terms of version 2 of the GNU General Public License as |
12 | @@ -25,11 +26,11 @@ | |||
13 | 25 | import supybot.log as supylog | 26 | import supybot.log as supylog |
14 | 26 | 27 | ||
15 | 27 | #import imaplib | 28 | #import imaplib |
17 | 28 | import re, os, time, commands | 29 | import re, os, time, subprocess |
18 | 29 | import xml.dom.minidom as minidom | 30 | import xml.dom.minidom as minidom |
19 | 30 | from htmlentitydefs import entitydefs as entities | 31 | from htmlentitydefs import entitydefs as entities |
22 | 31 | import email.FeedParser | 32 | from email.parser import FeedParser |
23 | 32 | import SOAPpy | 33 | from SOAPpy.Client import SOAPProxy |
24 | 33 | 34 | ||
25 | 34 | # All the words below will be censored when reporting bug information | 35 | # All the words below will be censored when reporting bug information |
26 | 35 | bad_words = set(["fuck","fuk","fucking","fuking","fukin","fuckin","fucked","fuked","fucker","shit","cunt","bastard","nazi","nigger","nigga","cock","bitches","bitch"]) | 36 | bad_words = set(["fuck","fuk","fucking","fuking","fukin","fuckin","fucked","fuked","fucker","shit","cunt","bastard","nazi","nigger","nigga","cock","bitches","bitch"]) |
27 | @@ -52,7 +53,7 @@ | |||
28 | 52 | if description: | 53 | if description: |
29 | 53 | DESC.setValue(description) | 54 | DESC.setValue(description) |
30 | 54 | if trackertype: | 55 | if trackertype: |
32 | 55 | if defined_bugtrackers.has_key(trackertype.lower()): | 56 | if trackertype.lower() in defined_bugtrackers: |
33 | 56 | TRACKERTYPE.setValue(trackertype.lower()) | 57 | TRACKERTYPE.setValue(trackertype.lower()) |
34 | 57 | else: | 58 | else: |
35 | 58 | raise BugtrackerError("Unknown trackertype: %s" % trackertype) | 59 | raise BugtrackerError("Unknown trackertype: %s" % trackertype) |
36 | @@ -81,6 +82,19 @@ | |||
37 | 81 | val = entre.sub('?', val) | 82 | val = entre.sub('?', val) |
38 | 82 | return val | 83 | return val |
39 | 83 | 84 | ||
40 | 85 | def _getnodeattr(node, attr): | ||
41 | 86 | if node.hasAttribute(attr): | ||
42 | 87 | val = node.getAttribute(attr) | ||
43 | 88 | else: | ||
44 | 89 | raise ValueError, "No such attribute" | ||
45 | 90 | while entre.search(val): | ||
46 | 91 | entity = entre.search(val).group(1) | ||
47 | 92 | if entity in entities: | ||
48 | 93 | val = entre.sub(entities[entity], val) | ||
49 | 94 | else: | ||
50 | 95 | val = entre.sub('?', val) | ||
51 | 96 | return val | ||
52 | 97 | |||
53 | 84 | class BugtrackerError(Exception): | 98 | class BugtrackerError(Exception): |
54 | 85 | """A bugtracker error""" | 99 | """A bugtracker error""" |
55 | 86 | pass | 100 | pass |
56 | @@ -103,7 +117,7 @@ | |||
57 | 103 | for name in self.registryValue('bugtrackers'): | 117 | for name in self.registryValue('bugtrackers'): |
58 | 104 | registerBugtracker(name) | 118 | registerBugtracker(name) |
59 | 105 | group = self.registryValue('bugtrackers.%s' % name.replace('.','\\.'), value=False) | 119 | group = self.registryValue('bugtrackers.%s' % name.replace('.','\\.'), value=False) |
61 | 106 | if group.trackertype() in defined_bugtrackers.keys(): | 120 | if group.trackertype() in defined_bugtrackers: |
62 | 107 | self.db[name] = defined_bugtrackers[group.trackertype()](name, group.url(), group.description()) | 121 | self.db[name] = defined_bugtrackers[group.trackertype()](name, group.url(), group.description()) |
63 | 108 | else: | 122 | else: |
64 | 109 | self.log.warning("Bugtracker: Unknown trackertype: %s (%s)" % (group.trackertype(), name)) | 123 | self.log.warning("Bugtracker: Unknown trackertype: %s (%s)" % (group.trackertype(), name)) |
65 | @@ -171,7 +185,7 @@ | |||
66 | 171 | # # Read all new mail | 185 | # # Read all new mail |
67 | 172 | # for m in new_mail: | 186 | # for m in new_mail: |
68 | 173 | # msg = sc.fetch(m, 'RFC822')[1][0][1] | 187 | # msg = sc.fetch(m, 'RFC822')[1][0][1] |
70 | 174 | # fp = email.FeedParser.FeedParser() | 188 | # fp = FeedParser() |
71 | 175 | # sc.store(m, '+FLAGS', "(\Deleted)") # Mark message deleted so we don't have to process it again | 189 | # sc.store(m, '+FLAGS', "(\Deleted)") # Mark message deleted so we don't have to process it again |
72 | 176 | # fp.feed(msg) | 190 | # fp.feed(msg) |
73 | 177 | # bug = fp.close() | 191 | # bug = fp.close() |
74 | @@ -275,7 +289,7 @@ | |||
75 | 275 | self.shorthand = utils.abbrev(self.db.keys()) | 289 | self.shorthand = utils.abbrev(self.db.keys()) |
76 | 276 | irc.replySuccess() | 290 | irc.replySuccess() |
77 | 277 | except KeyError: | 291 | except KeyError: |
79 | 278 | s = self.registryValue('replyNoBugtracker', ircutils.isChannel(msg.args[0]) and msg.args[0] or None) | 292 | s = self.registryValue('replyNoBugtracker', msg.args[0] if ircutils.isChannel(msg.args[0]) else None) |
80 | 279 | irc.error(s % name) | 293 | irc.error(s % name) |
81 | 280 | remove = wrap(remove, [('checkCapability', 'admin'), 'text']) | 294 | remove = wrap(remove, [('checkCapability', 'admin'), 'text']) |
82 | 281 | 295 | ||
83 | @@ -297,7 +311,7 @@ | |||
84 | 297 | self.shorthand = utils.abbrev(self.db.keys()) | 311 | self.shorthand = utils.abbrev(self.db.keys()) |
85 | 298 | irc.replySuccess() | 312 | irc.replySuccess() |
86 | 299 | except KeyError: | 313 | except KeyError: |
88 | 300 | s = self.registryValue('replyNoBugtracker', ircutils.isChannel(msg.args[0]) and msg.args[0] or None) | 314 | s = self.registryValue('replyNoBugtracker', msg.args[0] if ircutils.isChannel(msg.args[0]) else None) |
89 | 301 | irc.error(s % name) | 315 | irc.error(s % name) |
90 | 302 | rename = wrap(rename, [('checkCapability', 'admin'), 'something','something', additional('text')]) | 316 | rename = wrap(rename, [('checkCapability', 'admin'), 'something','something', additional('text')]) |
91 | 303 | 317 | ||
92 | @@ -315,7 +329,7 @@ | |||
93 | 315 | self.db[name].__class__.__name__) | 329 | self.db[name].__class__.__name__) |
94 | 316 | irc.reply('%s: %s, %s [%s]' % (name, description, url, type)) | 330 | irc.reply('%s: %s, %s [%s]' % (name, description, url, type)) |
95 | 317 | except KeyError: | 331 | except KeyError: |
97 | 318 | s = self.registryValue('replyNoBugtracker', ircutils.isChannel(msg.args[0]) and msg.args[0] or None) | 332 | s = self.registryValue('replyNoBugtracker', msg.args[0] if ircutils.isChannel(msg.args[0]) else None) |
98 | 319 | irc.error(s % name) | 333 | irc.error(s % name) |
99 | 320 | else: | 334 | else: |
100 | 321 | if self.db: | 335 | if self.db: |
101 | @@ -328,7 +342,7 @@ | |||
102 | 328 | 342 | ||
103 | 329 | def bugSnarfer(self, irc, msg, match): | 343 | def bugSnarfer(self, irc, msg, match): |
104 | 330 | r"""\b(?P<bt>(([a-z0-9]+)?\s+bugs?|[a-z0-9]+)):?\s+#?(?P<bug>\d+(?!\d*[\-\.]\d+)((,|\s*(and|en|et|und|ir))\s*#?\d+(?!\d*[\-\.]\d+))*)""" | 344 | r"""\b(?P<bt>(([a-z0-9]+)?\s+bugs?|[a-z0-9]+)):?\s+#?(?P<bug>\d+(?!\d*[\-\.]\d+)((,|\s*(and|en|et|und|ir))\s*#?\d+(?!\d*[\-\.]\d+))*)""" |
106 | 331 | channel = ircutils.isChannel(msg.args[0]) and msg.args[0] or None | 345 | channel = msg.args[0] if ircutils.isChannel(msg.args[0]) else None |
107 | 332 | if not self.registryValue('bugSnarfer', channel): | 346 | if not self.registryValue('bugSnarfer', channel): |
108 | 333 | return | 347 | return |
109 | 334 | nbugs = msg.tagged('nbugs') | 348 | nbugs = msg.tagged('nbugs') |
110 | @@ -403,13 +417,14 @@ | |||
111 | 403 | for bugid in bugids: | 417 | for bugid in bugids: |
112 | 404 | bugid = int(bugid) | 418 | bugid = int(bugid) |
113 | 405 | try: | 419 | try: |
115 | 406 | report = self.get_bug(channel,tracker,bugid,self.registryValue('showassignee', channel), show_tracker=showTracker) | 420 | report = self.get_bug(channel or msg.nick, tracker, bugid, self.registryValue('showassignee', channel), |
116 | 421 | self.registryValue('extended', channel), do_tracker=showTracker) | ||
117 | 407 | except BugNotFoundError: | 422 | except BugNotFoundError: |
118 | 408 | if self.registryValue('replyWhenNotFound'): | 423 | if self.registryValue('replyWhenNotFound'): |
119 | 409 | irc.error("%s bug %d could not be found" % (tracker.description, bugid)) | 424 | irc.error("%s bug %d could not be found" % (tracker.description, bugid)) |
120 | 410 | except BugtrackerError, e: | 425 | except BugtrackerError, e: |
121 | 411 | # if 'private' in str(e): | 426 | # if 'private' in str(e): |
123 | 412 | # irc.reply("Bug %d on http://launchpad.net/bugs/%d is private" % (bugid, bugid)) | 427 | # irc.reply("Bug %d on https://launchpad.net/bugs/%d is private" % (bugid, bugid)) |
124 | 413 | # return | 428 | # return |
125 | 414 | if not sure_bug and bugid < 30: | 429 | if not sure_bug and bugid < 30: |
126 | 415 | return | 430 | return |
127 | @@ -420,7 +435,7 @@ | |||
128 | 420 | 435 | ||
129 | 421 | def turlSnarfer(self, irc, msg, match): | 436 | def turlSnarfer(self, irc, msg, match): |
130 | 422 | r"(?P<tracker>https?://\S*?)/(?:Bugs/0*|str.php\?L|show_bug.cgi\?id=|bugreport.cgi\?bug=|(?:bugs|\+bug)/|ticket/|tracker/|\S*aid=|bug=)?(?P<bug>\d+)(?P<sfurl>&group_id=\d+&at_id=\d+)?" | 437 | r"(?P<tracker>https?://\S*?)/(?:Bugs/0*|str.php\?L|show_bug.cgi\?id=|bugreport.cgi\?bug=|(?:bugs|\+bug)/|ticket/|tracker/|\S*aid=|bug=)?(?P<bug>\d+)(?P<sfurl>&group_id=\d+&at_id=\d+)?" |
132 | 423 | channel = ircutils.isChannel(msg.args[0]) and msg.args[0] or None | 438 | channel = msg.args[0] if ircutils.isChannel(msg.args[0]) else None |
133 | 424 | if not self.registryValue('bugSnarfer', channel): | 439 | if not self.registryValue('bugSnarfer', channel): |
134 | 425 | return | 440 | return |
135 | 426 | nbugs = msg.tagged('nbugs') | 441 | nbugs = msg.tagged('nbugs') |
136 | @@ -432,7 +447,8 @@ | |||
137 | 432 | tracker = self.get_tracker(match.group(0),match.group('sfurl')) | 447 | tracker = self.get_tracker(match.group(0),match.group('sfurl')) |
138 | 433 | if not tracker: | 448 | if not tracker: |
139 | 434 | return | 449 | return |
141 | 435 | report = self.get_bug(channel, tracker, int(match.group('bug')), self.registryValue('showassignee', channel), do_url = False) | 450 | report = self.get_bug(channel or msg.nick, tracker, int(match.group('bug')), self.registryValue('showassignee', channel), |
142 | 451 | self.registryValue('extended', channel), do_url=False) | ||
143 | 436 | except BugtrackerError, e: | 452 | except BugtrackerError, e: |
144 | 437 | irc.error(str(e)) | 453 | irc.error(str(e)) |
145 | 438 | except BugNotFoundError, e: | 454 | except BugNotFoundError, e: |
146 | @@ -444,32 +460,32 @@ | |||
147 | 444 | # Only useful for launchpad developers | 460 | # Only useful for launchpad developers |
148 | 445 | def oopsSnarfer(self, irc, msg, match): | 461 | def oopsSnarfer(self, irc, msg, match): |
149 | 446 | r"(?:https?://pad.lv/){0}?OOPS-(?P<oopsid>\d*[\dA-Z]{3,})" | 462 | r"(?:https?://pad.lv/){0}?OOPS-(?P<oopsid>\d*[\dA-Z]{3,})" |
151 | 447 | channel = ircutils.isChannel(msg.args[0]) and msg.args[0] or None | 463 | channel = msg.args[0] if ircutils.isChannel(msg.args[0]) else None |
152 | 448 | if not self.registryValue('bugSnarfer', channel) or not self.registryValue('oopsSnarfer', channel): | 464 | if not self.registryValue('bugSnarfer', channel) or not self.registryValue('oopsSnarfer', channel): |
153 | 449 | return | 465 | return |
154 | 450 | oopsid = match.group(1) | 466 | oopsid = match.group(1) |
155 | 451 | if oopsid.lower() == "tools": | 467 | if oopsid.lower() == "tools": |
156 | 452 | return | 468 | return |
158 | 453 | if not self.is_ok(channel, 'lpoops', oopsid): | 469 | if not self.is_ok(channel or msg.nick, 'lpoops', oopsid): |
159 | 454 | return | 470 | return |
161 | 455 | irc.reply('https://oops.canonical.com/?oopsid=OOPS-' + oopsid, prefixNick=False) | 471 | irc.reply('https://oops.canonical.com/?oopsid=OOPS-%s' % oopsid, prefixNick=False) |
162 | 456 | 472 | ||
163 | 457 | def cveSnarfer(self, irc, msg, match): | 473 | def cveSnarfer(self, irc, msg, match): |
164 | 458 | r"(cve[- ]\d{4}[- ]\d{4,})" | 474 | r"(cve[- ]\d{4}[- ]\d{4,})" |
166 | 459 | channel = ircutils.isChannel(msg.args[0]) and msg.args[0] or None | 475 | channel = msg.args[0] if ircutils.isChannel(msg.args[0]) else None |
167 | 460 | if not self.registryValue('bugSnarfer', channel) or not self.registryValue('cveSnarfer', channel): | 476 | if not self.registryValue('bugSnarfer', channel) or not self.registryValue('cveSnarfer', channel): |
168 | 461 | return | 477 | return |
169 | 462 | cve = match.group(1).replace(' ','-').upper() | 478 | cve = match.group(1).replace(' ','-').upper() |
171 | 463 | if not self.is_ok(channel, 'cve', cve): | 479 | if not self.is_ok(channel or msg.nick, 'cve', cve): |
172 | 464 | return | 480 | return |
174 | 465 | url = 'http://cve.mitre.org/cgi-bin/cvename.cgi?name=%s' % cve | 481 | url = 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=%s' % cve |
175 | 466 | cvedata = utils.web.getUrl(url) | 482 | cvedata = utils.web.getUrl(url) |
176 | 467 | m = cvere.search(cvedata) | 483 | m = cvere.search(cvedata) |
177 | 468 | if m: | 484 | if m: |
178 | 469 | cve = m.group(1).replace('\n', ' ') | 485 | cve = m.group(1).replace('\n', ' ') |
179 | 470 | if len(cve) > 380: | 486 | if len(cve) > 380: |
180 | 471 | cve = cve[:380] + '...' | 487 | cve = cve[:380] + '...' |
182 | 472 | irc.reply("%s (%s)" % (cve,url), prefixNick=False) | 488 | irc.reply("%s <%s>" % (cve, url), prefixNick=False) |
183 | 473 | 489 | ||
184 | 474 | #TODO: as we will depend on launchpadlib, we should consider using lazr.uri.URI to do URL parsing | 490 | #TODO: as we will depend on launchpadlib, we should consider using lazr.uri.URI to do URL parsing |
185 | 475 | def get_tracker(self, snarfurl, sfdata): | 491 | def get_tracker(self, snarfurl, sfdata): |
186 | @@ -529,39 +545,57 @@ | |||
187 | 529 | return tracker | 545 | return tracker |
188 | 530 | return None | 546 | return None |
189 | 531 | 547 | ||
191 | 532 | def get_bug(self, channel, tracker, id, do_assignee, do_url = True, show_tracker = True): | 548 | def get_bug(self, channel, tracker, id, do_assignee, do_extinfo, do_url=True, do_tracker=True): |
192 | 533 | reports = [] | 549 | reports = [] |
193 | 550 | message_max = 450 - len(channel) | ||
194 | 551 | |||
195 | 534 | if not self.is_ok(channel, tracker, id): | 552 | if not self.is_ok(channel, tracker, id): |
196 | 535 | return [] | 553 | return [] |
197 | 554 | |||
198 | 536 | for r in tracker.get_bug(id): | 555 | for r in tracker.get_bug(id): |
203 | 537 | showext = self.registryValue('extended', channel) | 556 | (bid, product, title, severity, status, assignee, url, extinfo, duplicate) = r |
204 | 538 | extinfo = '' | 557 | |
205 | 539 | if len(r) == 8: | 558 | if duplicate and not self.is_ok(channel, tracker, bid): |
206 | 540 | (bid, product, title, severity, status, assignee, url, extinfo) = r | 559 | continue |
207 | 560 | |||
208 | 561 | if do_tracker: | ||
209 | 562 | report = '%s bug %s' % (tracker.description, bid) | ||
210 | 541 | else: | 563 | else: |
212 | 542 | (bid, product, title, severity, status, assignee, url) = r | 564 | report = 'Bug %s' % bid |
213 | 543 | 565 | ||
214 | 544 | severity = severity[0].upper() + severity[1:].lower() | ||
215 | 545 | status = status[0].upper() + status[1:].lower() | ||
216 | 546 | tracker_name = tracker.description + ' ' | ||
217 | 547 | if not do_url: | ||
218 | 548 | url = '' | ||
219 | 549 | if not show_tracker: | ||
220 | 550 | tracker_name = '' | ||
221 | 551 | if product: | 566 | if product: |
233 | 552 | if showext: | 567 | report += ' in %s' % product |
234 | 553 | reports.append("%sbug %s in %s \"%s\" %s [%s,%s] %s" % (tracker_name, bid, product, | 568 | |
235 | 554 | title, extinfo, severity, status, url)) | 569 | report += ' "%s"' % title.replace('"', "'").strip() |
236 | 555 | else: | 570 | |
237 | 556 | reports.append("%sbug %s in %s \"%s\" [%s,%s] %s" % (tracker_name, bid, product, | 571 | if do_extinfo and extinfo: |
238 | 557 | title, severity, status, url)) | 572 | report += ' (%s)' % ', '.join(extinfo) |
239 | 558 | else: | 573 | |
229 | 559 | if showext: | ||
230 | 560 | reports.append("%sbug %s \"%s\" %s [%s,%s] %s" % (tracker_name, bid, title, extinfo, severity, status, url)) | ||
231 | 561 | else: | ||
232 | 562 | reports.append("%sbug %s \"%s\" [%s,%s] %s" % (tracker_name, bid, title, severity, status, url)) | ||
240 | 563 | if do_assignee and assignee: | 574 | if do_assignee and assignee: |
242 | 564 | reports[-1] = reports[-1] + (" - Assigned to %s" % assignee) | 575 | report += ' (assigned: %s)' % assignee |
243 | 576 | |||
244 | 577 | severity_status = [] | ||
245 | 578 | if severity: | ||
246 | 579 | severity_status.append(' '.join(word[0].upper() + word[1:].lower() for word in severity.split())) | ||
247 | 580 | severity_status.append(' '.join(word[0].upper() + word[1:].lower() for word in status.split())) | ||
248 | 581 | report += ' [%s]' % ', '.join(severity_status) | ||
249 | 582 | |||
250 | 583 | if duplicate: | ||
251 | 584 | report += ' [duplicate: %s]' % duplicate[0] | ||
252 | 585 | |||
253 | 586 | if do_url: | ||
254 | 587 | report += ' %s' % url | ||
255 | 588 | |||
256 | 589 | if len(report) > message_max: | ||
257 | 590 | report_parts = report.split('"') | ||
258 | 591 | report_start = report_parts[0] | ||
259 | 592 | report_end = report_parts[-1] | ||
260 | 593 | report_title = '"'.join(report_parts[1:-1]) | ||
261 | 594 | title_max = message_max - len(report_start) - len(report_end) - 5 | ||
262 | 595 | report_title_cut = report_title[:title_max].rsplit(None, 1)[0] + '...' | ||
263 | 596 | report = '%s"%s"%s' % (report_start, report_title_cut, report_end) | ||
264 | 597 | |||
265 | 598 | reports.append(report) | ||
266 | 565 | return reports | 599 | return reports |
267 | 566 | 600 | ||
268 | 567 | # Define all bugtrackers | 601 | # Define all bugtrackers |
269 | @@ -608,6 +642,7 @@ | |||
270 | 608 | return tracker | 642 | return tracker |
271 | 609 | except: | 643 | except: |
272 | 610 | return None | 644 | return None |
273 | 645 | |||
274 | 611 | def get_bug(self, id): | 646 | def get_bug(self, id): |
275 | 612 | url = "%s/show_bug.cgi?id=%d&ctype=xml" % (self.url,id) | 647 | url = "%s/show_bug.cgi?id=%d&ctype=xml" % (self.url,id) |
276 | 613 | try: | 648 | try: |
277 | @@ -630,49 +665,22 @@ | |||
278 | 630 | status = "%s: %s" % (status, _getnodetxt(bug_n.getElementsByTagName('resolution')[0])) | 665 | status = "%s: %s" % (status, _getnodetxt(bug_n.getElementsByTagName('resolution')[0])) |
279 | 631 | except: | 666 | except: |
280 | 632 | pass | 667 | pass |
282 | 633 | component = _getnodetxt(bug_n.getElementsByTagName('component')[0]) | 668 | product = _getnodetxt(bug_n.getElementsByTagName('product')[0]) |
283 | 634 | severity = _getnodetxt(bug_n.getElementsByTagName('bug_severity')[0]) | 669 | severity = _getnodetxt(bug_n.getElementsByTagName('bug_severity')[0]) |
284 | 635 | assignee = '(unavailable)' | ||
285 | 636 | try: | 670 | try: |
287 | 637 | assignee = _getnodetxt(bug_n.getElementsByTagName('assigned_to')[0]) | 671 | assignee = _getnodeattr(bug_n.getElementsByTagName('assigned_to')[0], 'name') |
288 | 638 | except: | 672 | except: |
290 | 639 | pass | 673 | try: |
291 | 674 | assignee = _getnodetxt(bug_n.getElementsByTagName('assigned_to')[0]) | ||
292 | 675 | except: | ||
293 | 676 | assignee = '' | ||
294 | 640 | except Exception, e: | 677 | except Exception, e: |
295 | 641 | s = 'Could not parse XML returned by %s bugzilla: %s (%s)' % (self.description, e, url) | 678 | s = 'Could not parse XML returned by %s bugzilla: %s (%s)' % (self.description, e, url) |
296 | 642 | raise BugtrackerError, s | 679 | raise BugtrackerError, s |
298 | 643 | return [(id, component, title, severity, status, assignee, "%s/show_bug.cgi?id=%d" % (self.url, id))] | 680 | return [(id, product, title, severity, status, assignee, "%s/show_bug.cgi?id=%d" % (self.url, id), [], [])] |
299 | 644 | 681 | ||
300 | 645 | class Issuezilla(Bugzilla): | 682 | class Issuezilla(Bugzilla): |
301 | 646 | pass | 683 | pass |
302 | 647 | #class Issuezilla(IBugtracker): | ||
303 | 648 | # def get_bug(self, id): | ||
304 | 649 | # url = "%s/show_bug.cgi?id=%d&ctype=xml" % (self.url,id) | ||
305 | 650 | # try: | ||
306 | 651 | # bugxml = utils.web.getUrl(url) | ||
307 | 652 | # zilladom = minidom.parseString(bugxml) | ||
308 | 653 | # except Exception, e: | ||
309 | 654 | # s = 'Could not parse XML returned by %s: %s (%s)' % (self.description, e, url) | ||
310 | 655 | # raise BugtrackerError, s | ||
311 | 656 | # bug_n = zilladom.getElementsByTagName('issue')[0] | ||
312 | 657 | # if not (bug_n.getAttribute('status_code') == '200'): | ||
313 | 658 | # if bug_n.getAttribute('status_message') == 'NotFound': | ||
314 | 659 | # raise BugNotFoundError | ||
315 | 660 | # s = 'Error getting %s bug #%s: %s' % (self.description, id, bug_n.getAttribute('status_message')) | ||
316 | 661 | # raise BugtrackerError, s | ||
317 | 662 | # try: | ||
318 | 663 | # title = _getnodetxt(bug_n.getElementsByTagName('short_desc')[0]) | ||
319 | 664 | # status = _getnodetxt(bug_n.getElementsByTagName('issue_status')[0]) | ||
320 | 665 | # try: | ||
321 | 666 | # status = "%s: %s" % (status, _getnodetxt(bug_n.getElementsByTagName('resolution')[0])) | ||
322 | 667 | # except: | ||
323 | 668 | # pass | ||
324 | 669 | # component = _getnodetxt(bug_n.getElementsByTagName('component')[0]) | ||
325 | 670 | # severity = _getnodetxt(bug_n.getElementsByTagName('issue_type')[0]) | ||
326 | 671 | # assignee = _getnodetxt(bug_n.getElementsByTagName('assigned_to')[0]) | ||
327 | 672 | # except Exception, e: | ||
328 | 673 | # s = 'Could not parse XML returned by %s bugzilla: %s (%s)' % (self.description, e, url) | ||
329 | 674 | # raise BugtrackerError, s | ||
330 | 675 | # return [(id, component, title, severity, status, assignee, "%s/show_bug.cgi?id=%d" % (self.url, id))] | ||
331 | 676 | 684 | ||
332 | 677 | class Launchpad(IBugtracker): | 685 | class Launchpad(IBugtracker): |
333 | 678 | statuses = ["Unknown", "Invalid", "Opinion", "Won't Fix", "Fix Released", "Fix Committed", "New", "Incomplete", "Confirmed", "Triaged", "In Progress"] | 686 | statuses = ["Unknown", "Invalid", "Opinion", "Won't Fix", "Fix Released", "Fix Committed", "New", "Incomplete", "Confirmed", "Triaged", "In Progress"] |
334 | @@ -705,7 +713,7 @@ | |||
335 | 705 | supylog.exception("Unknown exception while accessing the Launchpad API") | 713 | supylog.exception("Unknown exception while accessing the Launchpad API") |
336 | 706 | 714 | ||
337 | 707 | def _parse(self, task): #Depricated | 715 | def _parse(self, task): #Depricated |
339 | 708 | parser = email.FeedParser.FeedParser() | 716 | parser = FeedParser() |
340 | 709 | parser.feed(task) | 717 | parser.feed(task) |
341 | 710 | return parser.close() | 718 | return parser.close() |
342 | 711 | 719 | ||
343 | @@ -770,15 +778,15 @@ | |||
344 | 770 | bugdata = self.lp.bugs[id] | 778 | bugdata = self.lp.bugs[id] |
345 | 771 | if bugdata.private: | 779 | if bugdata.private: |
346 | 772 | raise BugtrackerError, "This bug is private" | 780 | raise BugtrackerError, "This bug is private" |
347 | 781 | duplicate = [] | ||
348 | 773 | dup = bugdata.duplicate_of | 782 | dup = bugdata.duplicate_of |
349 | 774 | summary_prefix = '' # Used to made dups easier | ||
350 | 775 | while dup: | 783 | while dup: |
352 | 776 | summary_prefix = 'duplicate for #%d ' % id | 784 | duplicate.append(str(bugdata.id)) |
353 | 777 | bugdata = dup | 785 | bugdata = dup |
354 | 778 | dup = bugdata.duplicate_of | 786 | dup = bugdata.duplicate_of |
355 | 779 | 787 | ||
358 | 780 | affected = bugdata.users_affected_count_with_dupes | 788 | extinfo = ['affected: %d' % bugdata.users_affected_count_with_dupes] |
359 | 781 | heat = bugdata.heat | 789 | extinfo.append('heat: %d' % bugdata.heat) |
360 | 782 | tasks = bugdata.bug_tasks | 790 | tasks = bugdata.bug_tasks |
361 | 783 | 791 | ||
362 | 784 | if tasks.total_size != 1: | 792 | if tasks.total_size != 1: |
363 | @@ -787,7 +795,7 @@ | |||
364 | 787 | tasks.sort(self._sort) | 795 | tasks.sort(self._sort) |
365 | 788 | taskdata = tasks[-1] | 796 | taskdata = tasks[-1] |
366 | 789 | except ValueError: | 797 | except ValueError: |
368 | 790 | tasks = [_ for _ in tasks if _.bug_target_name.endswith(u'(Ubuntu)')] | 798 | tasks = [_ for _ in tasks if _.bug_target_name.endswith('(Ubuntu)')] |
369 | 791 | if tasks: | 799 | if tasks: |
370 | 792 | if len(tasks) != 1: | 800 | if len(tasks) != 1: |
371 | 793 | try: | 801 | try: |
372 | @@ -802,18 +810,15 @@ | |||
373 | 802 | else: | 810 | else: |
374 | 803 | taskdata = tasks[0] | 811 | taskdata = tasks[0] |
375 | 804 | 812 | ||
381 | 805 | assignee = taskdata.assignee | 813 | if taskdata.assignee: |
382 | 806 | t = taskdata.bug_target_display_name #task name | 814 | assignee = taskdata.assignee.display_name |
378 | 807 | |||
379 | 808 | if assignee: # "Diaplay Name (Launchpad ID)" | ||
380 | 809 | assignee = u"%s (%s)" % (assignee.display_name, assignee.name) | ||
383 | 810 | else: | 815 | else: |
384 | 811 | assignee = '' | 816 | assignee = '' |
385 | 812 | 817 | ||
386 | 813 | except Exception, e: | 818 | except Exception, e: |
387 | 814 | if type(e).__name__ == 'HTTPError': # messy, but saves trying to import lazr.restfulclient.errors.HTPError | 819 | if type(e).__name__ == 'HTTPError': # messy, but saves trying to import lazr.restfulclient.errors.HTPError |
388 | 815 | if e.response.status == 404: | 820 | if e.response.status == 404: |
390 | 816 | bugNo = e.content.split(None)[-1][2:-1] # extract the real bug number | 821 | bugNo = e.content.split()[-1][2:-1] # extract the real bug number |
391 | 817 | if bugNo != str(id): # A duplicate of a private bug, at least we know it exists | 822 | if bugNo != str(id): # A duplicate of a private bug, at least we know it exists |
392 | 818 | raise BugtrackerError, 'Bug #%s is a duplicate of bug #%s, but it is private (%s/bugs/%s)' % (id, bugNo, self.url, bugNo) | 823 | raise BugtrackerError, 'Bug #%s is a duplicate of bug #%s, but it is private (%s/bugs/%s)' % (id, bugNo, self.url, bugNo) |
393 | 819 | raise BugtrackerError, "Bug #%s (%s/bugs/%d) is private or doesn't exist" % (id, self.url, id) # Could be private, could just not exist | 824 | raise BugtrackerError, "Bug #%s (%s/bugs/%d) is private or doesn't exist" % (id, self.url, id) # Could be private, could just not exist |
394 | @@ -825,58 +830,52 @@ | |||
395 | 825 | supylog.exception("Error gathering bug data for %s bug %d" % (self.description, id)) | 830 | supylog.exception("Error gathering bug data for %s bug %d" % (self.description, id)) |
396 | 826 | raise BugtrackerError, "Could not gather data from %s for bug #%s (%s/bugs/%s). The error has been logged" % (self.description, id, self.url, id) | 831 | raise BugtrackerError, "Could not gather data from %s for bug #%s (%s/bugs/%s). The error has been logged" % (self.description, id, self.url, id) |
397 | 827 | 832 | ||
404 | 828 | extinfo = "(affected: %d, heat: %d)" % (affected, heat) | 833 | return [(bugdata.id, taskdata.bug_target_display_name, bugdata.title, taskdata.importance, taskdata.status, |
405 | 829 | 834 | assignee, "%s/bugs/%s" % (self.url, bugdata.id), extinfo, duplicate)] | |
406 | 830 | return [(bugdata.id, t, summary_prefix + bugdata.title, taskdata.importance, taskdata.status, | 835 | |
407 | 831 | assignee, "%s/bugs/%s" % (self.url, bugdata.id), extinfo)] | 836 | def get_bug_old(self, id, duplicate=None): #Depricated |
402 | 832 | |||
403 | 833 | def get_bug_old(self, id): #Depricated | ||
408 | 834 | if id == 1: | 837 | if id == 1: |
409 | 835 | raise BugtrackerError, "https://bugs.launchpad.net/ubuntu/+bug/1 (Not reporting large bug)" | 838 | raise BugtrackerError, "https://bugs.launchpad.net/ubuntu/+bug/1 (Not reporting large bug)" |
410 | 836 | 839 | ||
411 | 837 | try: | 840 | try: |
413 | 838 | bugdata = utils.web.getUrl("%s/bugs/%d/+text" % (self.url,id)) | 841 | bugdata = utils.web.getUrl("%s/bugs/%d/+text" % (self.url, id)) |
414 | 839 | except Exception, e: | 842 | except Exception, e: |
415 | 840 | if '404' in str(e): | 843 | if '404' in str(e): |
417 | 841 | raise BugNotFoundError | 844 | if duplicate: |
418 | 845 | raise BugtrackerError, 'Bug #%s is a duplicate of bug #%s, but it is private (%s/bugs/%s)' % (duplicate, id, self.url, id) | ||
419 | 846 | else: | ||
420 | 847 | raise BugNotFoundError | ||
421 | 842 | s = 'Could not parse data returned by %s: %s (%s/bugs/%d)' % (self.description, e, self.url, id) | 848 | s = 'Could not parse data returned by %s: %s (%s/bugs/%d)' % (self.description, e, self.url, id) |
422 | 843 | raise BugtrackerError, s | 849 | raise BugtrackerError, s |
424 | 844 | summary = {} | 850 | |
425 | 845 | # Trap private bugs | 851 | # Trap private bugs |
426 | 846 | if "<!-- 4a. didn't try to log in last time: -->" in bugdata: | 852 | if "<!-- 4a. didn't try to log in last time: -->" in bugdata: |
427 | 847 | raise BugtrackerError, "This bug is private" | 853 | raise BugtrackerError, "This bug is private" |
428 | 848 | try: | 854 | try: |
429 | 849 | # Split bug data into separate pieces (bug data, task data) | 855 | # Split bug data into separate pieces (bug data, task data) |
440 | 850 | data = bugdata.split('\n\n') | 856 | data = bugdata.split('\n\nContent-Type:', 1)[0].split('\n\n') |
441 | 851 | bugdata = data[0] | 857 | bugdata = self._parse(data[0]) |
442 | 852 | taskdata = data[1:] | 858 | if not bugdata['duplicate-of']: |
443 | 853 | parser = email.FeedParser.FeedParser() | 859 | taskdata = map(self._parse, data[1:]) |
444 | 854 | parser.feed(bugdata) | 860 | taskdata.sort(self._old_sort) |
445 | 855 | bugdata = parser.close() | 861 | taskdata = taskdata[-1] |
446 | 856 | taskdata = map(self._parse, taskdata) | 862 | if taskdata['assignee']: |
447 | 857 | taskdata.sort(self._old_sort) | 863 | assignee = re.sub(r' \([^)]*\)$', '', taskdata['assignee']) |
448 | 858 | taskdata = taskdata[-1] | 864 | else: |
449 | 859 | 865 | assignee = '' | |
450 | 860 | except Exception, e: | 866 | except Exception, e: |
451 | 861 | s = 'Could not parse data returned by %s: %s (%s/bugs/%d)' % (self.description, e, self.url, id) | 867 | s = 'Could not parse data returned by %s: %s (%s/bugs/%d)' % (self.description, e, self.url, id) |
452 | 862 | raise BugtrackerError, s | 868 | raise BugtrackerError, s |
453 | 869 | |||
454 | 863 | # Try and find duplicates | 870 | # Try and find duplicates |
471 | 864 | t = taskdata['task'] | 871 | if bugdata['duplicate-of']: |
472 | 865 | if '(' in t: | 872 | data = self.get_bug_old(int(bugdata['duplicate-of']), duplicate or id)[0] |
473 | 866 | t = t[:t.rfind('(') -1] | 873 | data[8].append(bugdata['bug']) |
474 | 867 | if bugdata['duplicate-of']: # This will suck if for dup of dups..., but +text is pure suck anyway | 874 | return [data] |
475 | 868 | bugNo = bugdata['duplicate-of'] | 875 | |
476 | 869 | try: | 876 | return [(id, taskdata['task'], bugdata['title'], taskdata['importance'], taskdata['status'], |
477 | 870 | data = self.get_bug(int(bugdata['duplicate-of'])) | 877 | assignee, "%s/bugs/%s" % (self.url, id), [], [])] |
478 | 871 | except Exception, e: | 878 | |
463 | 872 | if '404' in str(e): | ||
464 | 873 | raise BugtrackerError, 'Bug #%s is a duplicate of Bug #%s, but it is private. (%s/bugs/%s)' % (id, bugNo, self.url, bugNo) | ||
465 | 874 | data = list(data[0]) | ||
466 | 875 | data[2] = ('duplicate for #%d ' % id) + data[2] | ||
467 | 876 | return [tuple(data)] | ||
468 | 877 | return [(id, t, bugdata['title'], taskdata['importance'], | ||
469 | 878 | taskdata['status'], taskdata['assignee'], "%s/bugs/%s" % (self.url, id))] | ||
470 | 879 | |||
479 | 880 | # <rant> | 879 | # <rant> |
480 | 881 | # Debbugs sucks donkeyballs | 880 | # Debbugs sucks donkeyballs |
481 | 882 | # * HTML pages are inconsistent | 881 | # * HTML pages are inconsistent |
482 | @@ -890,11 +889,10 @@ | |||
483 | 890 | class Debbugs(IBugtracker): | 889 | class Debbugs(IBugtracker): |
484 | 891 | def __init__(self, *args, **kwargs): | 890 | def __init__(self, *args, **kwargs): |
485 | 892 | IBugtracker.__init__(self, *args, **kwargs) | 891 | IBugtracker.__init__(self, *args, **kwargs) |
488 | 893 | self.soap_proxy = SOAPpy.SOAPProxy("bugs.debian.org/cgi-bin/soap.cgi", "Debbugs/SOAP/Status") | 892 | self.soap_proxy = SOAPProxy("%s/cgi-bin/soap.cgi" % self.url, namespace="Debbugs/SOAP") |
487 | 894 | self.soap_proxy.soapaction = "Debbugs/SOAP/Status#get_status" | ||
489 | 895 | 893 | ||
490 | 896 | def get_bug(self, id): | 894 | def get_bug(self, id): |
492 | 897 | bug_url = "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%d" % id | 895 | bug_url = "%s/cgi-bin/bugreport.cgi?bug=%d" % (self.url, id) |
493 | 898 | try: | 896 | try: |
494 | 899 | raw = self.soap_proxy.get_status(id) | 897 | raw = self.soap_proxy.get_status(id) |
495 | 900 | except Exception, e: | 898 | except Exception, e: |
496 | @@ -902,13 +900,13 @@ | |||
497 | 902 | raise BugtrackerError, s | 900 | raise BugtrackerError, s |
498 | 903 | if not raw: | 901 | if not raw: |
499 | 904 | raise BugNotFoundError | 902 | raise BugNotFoundError |
500 | 905 | raw = raw['item']['value'] | ||
501 | 906 | try: | 903 | try: |
503 | 907 | if len(raw['fixed_versions']): | 904 | raw = raw['item']['value'] |
504 | 905 | if raw['fixed_versions']: | ||
505 | 908 | status = 'Fixed' | 906 | status = 'Fixed' |
506 | 909 | else: | 907 | else: |
507 | 910 | status = 'Open' | 908 | status = 'Open' |
509 | 911 | return [(id, raw['package'], raw['subject'], raw['severity'], status, '', "%s/%s" % (self.url, id))] | 909 | return [(id, raw['package'], raw['subject'], raw['severity'], status, '', "%s/%s" % (self.url, id), [], [])] |
510 | 912 | except Exception, e: | 910 | except Exception, e: |
511 | 913 | s = 'Could not parse data returned by %s bugtracker: %s (%s)' % (self.description, e, bug_url) | 911 | s = 'Could not parse data returned by %s bugtracker: %s (%s)' % (self.description, e, bug_url) |
512 | 914 | raise BugtrackerError, s | 912 | raise BugtrackerError, s |
513 | @@ -916,11 +914,10 @@ | |||
514 | 916 | class Mantis(IBugtracker): | 914 | class Mantis(IBugtracker): |
515 | 917 | def __init__(self, *args, **kwargs): | 915 | def __init__(self, *args, **kwargs): |
516 | 918 | IBugtracker.__init__(self, *args, **kwargs) | 916 | IBugtracker.__init__(self, *args, **kwargs) |
519 | 919 | self.soap_proxy = SOAPpy.SOAPProxy(self.url + "/api/soap/mantisconnect.php", "http://futureware.biz/mantisconnect") | 917 | self.soap_proxy = SOAPProxy("%s/api/soap/mantisconnect.php" % self.url, namespace="http://futureware.biz/mantisconnect") |
518 | 920 | self.soap_proxy.soapaction = "http://futureware.biz/mantisconnect#mc_issue_get" | ||
520 | 921 | 918 | ||
521 | 922 | def get_bug(self, id): | 919 | def get_bug(self, id): |
523 | 923 | url = self.url + "/view.php?id=%i" % id | 920 | url = "%s/view.php?id=%d" % (self.url, id) |
524 | 924 | try: | 921 | try: |
525 | 925 | raw = self.soap_proxy.mc_issue_get('', "", id) | 922 | raw = self.soap_proxy.mc_issue_get('', "", id) |
526 | 926 | except Exception, e: | 923 | except Exception, e: |
527 | @@ -929,7 +926,7 @@ | |||
528 | 929 | if not raw: | 926 | if not raw: |
529 | 930 | raise BugNotFoundError | 927 | raise BugNotFoundError |
530 | 931 | try: | 928 | try: |
532 | 932 | return [(id, raw['project']['name'], raw['summary'], raw['priority']['name'], raw['resolution']['name'], '', url)] | 929 | return [(id, raw['project']['name'], raw['summary'], raw['severity']['name'], raw['resolution']['name'], '', url, [], [])] |
533 | 933 | except Exception, e: | 930 | except Exception, e: |
534 | 934 | s = 'Could not parse data returned by %s bugtracker: %s (%s)' % (self.description, e, url) | 931 | s = 'Could not parse data returned by %s bugtracker: %s (%s)' % (self.description, e, url) |
535 | 935 | raise BugtrackerError, s | 932 | raise BugtrackerError, s |
536 | @@ -952,7 +949,8 @@ | |||
537 | 952 | (headers, rest) = raw.split('\n', 1) | 949 | (headers, rest) = raw.split('\n', 1) |
538 | 953 | headers = headers.strip().split('\t') | 950 | headers = headers.strip().split('\t') |
539 | 954 | rest = rest.strip().split('\t') | 951 | rest = rest.strip().split('\t') |
541 | 955 | title = status = package = severity = assignee = "Unknown" | 952 | |
542 | 953 | title = status = package = severity = assignee = "" | ||
543 | 956 | if "summary" in headers: | 954 | if "summary" in headers: |
544 | 957 | title = rest[headers.index("summary")] | 955 | title = rest[headers.index("summary")] |
545 | 958 | if "status" in headers: | 956 | if "status" in headers: |
546 | @@ -961,13 +959,12 @@ | |||
547 | 961 | package = rest[headers.index("component")] | 959 | package = rest[headers.index("component")] |
548 | 962 | if "severity" in headers: | 960 | if "severity" in headers: |
549 | 963 | severity = rest[headers.index("severity")] | 961 | severity = rest[headers.index("severity")] |
550 | 962 | elif "priority" in headers: | ||
551 | 963 | severity = rest[headers.index("priority")] | ||
552 | 964 | if "owner" in headers: | 964 | if "owner" in headers: |
556 | 965 | assingee = rest[headers.index("owner")] | 965 | assignee = rest[headers.index("owner")] |
557 | 966 | if severity == "Unknown" and "priority" in headers: | 966 | return [(id, package, title, severity, status, assignee, bug_url, [], [])] |
555 | 967 | severity = rest[headers.index("priority")] | ||
558 | 968 | 967 | ||
559 | 969 | return [(id, package, title, severity, status, assignee, bug_url)] | ||
560 | 970 | |||
561 | 971 | class WikiForms(IBugtracker): | 968 | class WikiForms(IBugtracker): |
562 | 972 | def get_bug(self, id): | 969 | def get_bug(self, id): |
563 | 973 | def strip_tags(s): | 970 | def strip_tags(s): |
564 | @@ -986,14 +983,14 @@ | |||
565 | 986 | for l in bugdata.split("\n"): | 983 | for l in bugdata.split("\n"): |
566 | 987 | l2 = l.lower() | 984 | l2 = l.lower() |
567 | 988 | if '<dt>importance</dt>' in l2: | 985 | if '<dt>importance</dt>' in l2: |
569 | 989 | severity = 'Importance ' + strip_tags(l[l.find('<dd>')+4:]) | 986 | severity = strip_tags(l[l.find('<dd>')+4:]) |
570 | 990 | if '<dt>summary</dt>' in l2: | 987 | if '<dt>summary</dt>' in l2: |
571 | 991 | title = strip_tags(l[l.find('<dd>')+4:]) | 988 | title = strip_tags(l[l.find('<dd>')+4:]) |
572 | 992 | if '<dt>status</dt>' in l2: | 989 | if '<dt>status</dt>' in l2: |
573 | 993 | status = strip_tags(l[l.find('<dd>')+4:]) | 990 | status = strip_tags(l[l.find('<dd>')+4:]) |
574 | 994 | if '<dt>category</dt>' in l2: | 991 | if '<dt>category</dt>' in l2: |
575 | 995 | package = strip_tags(l[l.find('<dd>')+4:]) | 992 | package = strip_tags(l[l.find('<dd>')+4:]) |
577 | 996 | return [(id, package, title, severity, status, '', "%s/%05d" % (self.url, id))] | 993 | return [(id, package, title, severity, status, '', "%s/%05d" % (self.url, id), [], [])] |
578 | 997 | 994 | ||
579 | 998 | class Str(IBugtracker): | 995 | class Str(IBugtracker): |
580 | 999 | def get_bug(self, id): | 996 | def get_bug(self, id): |
581 | @@ -1010,7 +1007,7 @@ | |||
582 | 1010 | for l in bugdata.split("\n"): | 1007 | for l in bugdata.split("\n"): |
583 | 1011 | l2 = l.lower() | 1008 | l2 = l.lower() |
584 | 1012 | if 'nowrap>priority:</th>' in l2: | 1009 | if 'nowrap>priority:</th>' in l2: |
586 | 1013 | severity = 'Priority ' + l[l.find(' - ')+3:min(l.find(','),l.find('</td>'))] | 1010 | severity = l[l.find(' - ')+3:min(l.find(','),l.find('</td>'))] |
587 | 1014 | if '>application:</th>' in l2: | 1011 | if '>application:</th>' in l2: |
588 | 1015 | package = l[l.find('<td>')+4:l.find('</td>')] | 1012 | package = l[l.find('<td>')+4:l.find('</td>')] |
589 | 1016 | if 'nowrap>status:</th>' in l2: | 1013 | if 'nowrap>status:</th>' in l2: |
590 | @@ -1020,9 +1017,8 @@ | |||
591 | 1020 | if 'nowrap>assigned to:</th>' in l2: | 1017 | if 'nowrap>assigned to:</th>' in l2: |
592 | 1021 | assignee = strip_tags(l[l.find('<td>')+4:l.find('</td>')]) | 1018 | assignee = strip_tags(l[l.find('<td>')+4:l.find('</td>')]) |
593 | 1022 | if assignee == 'Unassigned': | 1019 | if assignee == 'Unassigned': |
597 | 1023 | assignee = 'nobody' | 1020 | assignee = '' |
598 | 1024 | return [(id, package, title, severity, status, assignee, "%s?L%d" % (self.url, id))] | 1021 | return [(id, package, title, severity, status, assignee, "%s?L%d" % (self.url, id), [], [])] |
596 | 1025 | |||
599 | 1026 | 1022 | ||
600 | 1027 | sfre = re.compile(r""" | 1023 | sfre = re.compile(r""" |
601 | 1028 | .*? | 1024 | .*? |
602 | @@ -1051,9 +1047,12 @@ | |||
603 | 1051 | reo = sfre.search(bugdata) | 1047 | reo = sfre.search(bugdata) |
604 | 1052 | status = reo.group('status') | 1048 | status = reo.group('status') |
605 | 1053 | resolution = reo.group('resolution') | 1049 | resolution = reo.group('resolution') |
609 | 1054 | if not (resolution.lower() == 'none'): | 1050 | if resolution.lower() != 'none': |
610 | 1055 | status += ' ' + resolution | 1051 | status += ': %s' % resolution |
611 | 1056 | return [(id, None, reo.group('title'), "Pri: %s" % reo.group('priority'), status, reo.group('assignee'),self._sf_url % id)] | 1052 | assignee = reo.group('assignee') |
612 | 1053 | if assignee.lower() == 'nobody': | ||
613 | 1054 | assignee = '' | ||
614 | 1055 | return [(id, '', reo.group('title'), "Pri: %s" % reo.group('priority'), status, assignee, self._sf_url % id, [], [])] | ||
615 | 1057 | except: | 1056 | except: |
616 | 1058 | raise BugNotFoundError | 1057 | raise BugNotFoundError |
617 | 1059 | 1058 | ||
618 | @@ -1064,26 +1063,25 @@ | |||
619 | 1064 | if type(v[k]) == type(IBugtracker) and issubclass(v[k], IBugtracker) and not (v[k] == IBugtracker): | 1063 | if type(v[k]) == type(IBugtracker) and issubclass(v[k], IBugtracker) and not (v[k] == IBugtracker): |
620 | 1065 | defined_bugtrackers[k.lower()] = v[k] | 1064 | defined_bugtrackers[k.lower()] = v[k] |
621 | 1066 | 1065 | ||
623 | 1067 | registerBugtracker('mozilla', 'http://bugzilla.mozilla.org', 'Mozilla', 'bugzilla') | 1066 | registerBugtracker('mozilla', 'https://bugzilla.mozilla.org', 'Mozilla', 'bugzilla') |
624 | 1067 | registerBugtracker('gnome', 'https://bugzilla.gnome.org', 'Gnome', 'bugzilla') | ||
625 | 1068 | registerBugtracker('gnome2', 'https://bugs.gnome.org', 'Gnome', 'bugzilla') | ||
626 | 1069 | registerBugtracker('kde', 'https://bugs.kde.org', 'KDE', 'bugzilla') | ||
627 | 1070 | registerBugtracker('xfce', 'https://bugzilla.xfce.org', 'Xfce', 'bugzilla') | ||
628 | 1071 | registerBugtracker('freedesktop', 'https://bugzilla.freedesktop.org', 'Freedesktop', 'bugzilla') | ||
629 | 1072 | registerBugtracker('freedesktop2', 'https://bugs.freedesktop.org', 'Freedesktop', 'bugzilla') | ||
630 | 1073 | registerBugtracker('openoffice', 'https://bz.apache.org/ooo', 'OpenOffice', 'bugzilla') | ||
631 | 1068 | registerBugtracker('ubuntu', 'https://launchpad.net', 'Ubuntu', 'launchpad') | 1074 | registerBugtracker('ubuntu', 'https://launchpad.net', 'Ubuntu', 'launchpad') |
639 | 1069 | registerBugtracker('gnome', 'http://bugzilla.gnome.org', 'Gnome', 'bugzilla') | 1075 | registerBugtracker('ubottu', 'https://launchpad.net', 'Ubottu', 'launchpad') |
633 | 1070 | registerBugtracker('gnome2', 'http://bugs.gnome.org', 'Gnome', 'bugzilla') | ||
634 | 1071 | registerBugtracker('kde', 'http://bugs.kde.org', 'KDE', 'bugzilla') | ||
635 | 1072 | registerBugtracker('ximian', 'http://bugzilla.ximian.com', 'Ximian', 'bugzilla') | ||
636 | 1073 | registerBugtracker('freedesktop', 'http://bugzilla.freedesktop.org', 'Freedesktop', 'bugzilla') | ||
637 | 1074 | registerBugtracker('freedesktop2', 'http://bugs.freedesktop.org', 'Freedesktop', 'bugzilla') | ||
638 | 1075 | registerBugtracker('openoffice', 'http://openoffice.org/issues', 'OpenOffice.org', 'issuezilla') | ||
640 | 1076 | registerBugtracker('launchpad', 'https://launchpad.net', 'Launchpad', 'launchpad') | 1076 | registerBugtracker('launchpad', 'https://launchpad.net', 'Launchpad', 'launchpad') |
641 | 1077 | registerBugtracker('lp', 'https://launchpad.net', 'Launchpad', 'launchpad') | 1077 | registerBugtracker('lp', 'https://launchpad.net', 'Launchpad', 'launchpad') |
653 | 1078 | registerBugtracker('malone', 'https://launchpad.net', 'Launchpad', 'launchpad') | 1078 | registerBugtracker('debian', 'https://bugs.debian.org', 'Debian', 'debbugs') |
654 | 1079 | registerBugtracker('debian', 'http://bugs.debian.org', 'Debian', 'debbugs') | 1079 | registerBugtracker('mantis', 'https://www.mantisbt.org/bugs', 'Mantis', 'mantis') |
655 | 1080 | registerBugtracker('trac', 'http://trac.edgewall.org/ticket', 'Trac', 'trac') | 1080 | registerBugtracker('trac', 'https://trac.edgewall.org/ticket', 'Trac', 'trac') |
656 | 1081 | registerBugtracker('django', 'http://code.djangoproject.com/ticket', 'Django', 'trac') | 1081 | registerBugtracker('django', 'https://code.djangoproject.com/ticket', 'Django', 'trac') |
657 | 1082 | registerBugtracker('cups', 'http://www.cups.org/str.php', 'CUPS', 'str') | 1082 | # Outdated |
658 | 1083 | registerBugtracker('gnewsense', 'http://bugs.gnewsense.org/Bugs', 'gNewSense', 'wikiforms') | 1083 | #registerBugtracker('cups', 'http://www.cups.org/str.php', 'CUPS', 'str') |
659 | 1084 | registerBugtracker('supybot', 'http://sourceforge.net/tracker/?group_id=58965&atid=489447', 'Supybot', 'sourceforge') | 1084 | #registerBugtracker('gnewsense', 'http://bugs.gnewsense.org/Bugs', 'gNewSense', 'wikiforms') |
660 | 1085 | registerBugtracker('mantis', "http://www.mantisbt.org/bugs", "Mantis", 'mantis') | 1085 | #registerBugtracker('sourceforge', 'http://sourceforge.net/tracker/', 'Sourceforge', 'sourceforge') |
661 | 1086 | registerBugtracker('ubottu', 'https://launchpad.net', 'Ubottu', 'launchpad') | 1086 | #registerBugtracker('supybot', 'http://sourceforge.net/tracker/?group_id=58965&atid=489447', 'Supybot', 'sourceforge') |
651 | 1087 | # Don't delete this one | ||
652 | 1088 | registerBugtracker('sourceforge', 'http://sourceforge.net/tracker/', 'Sourceforge', 'sourceforge') | ||
662 | 1089 | Class = Bugtracker | 1087 | Class = Bugtracker |