|
1
by Dennis Kaarsemaker
Initial checkin |
1 |
###
|
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
2 |
# Copyright (c) 2005-2007 Dennis Kaarsemaker
|
|
149
by Jonathan Davies
Implemented anonymous bug reporting support to Bugtracker via the Launchpad |
3 |
# Copyright (C) 2010 Jonathan Davies
|
|
1
by Dennis Kaarsemaker
Initial checkin |
4 |
#
|
5 |
# This program is free software; you can redistribute it and/or modify
|
|
6 |
# it under the terms of version 2 of the GNU General Public License as
|
|
7 |
# published by the Free Software Foundation.
|
|
8 |
#
|
|
9 |
# This program is distributed in the hope that it will be useful,
|
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12 |
# GNU General Public License for more details.
|
|
13 |
#
|
|
14 |
###
|
|
15 |
||
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
16 |
from supybot.commands import * |
|
1
by Dennis Kaarsemaker
Initial checkin |
17 |
import supybot.utils as utils |
|
21
by Dennis Kaarsemaker
* Completely rewritten encyclopedia plugin |
18 |
import supybot.ircmsgs as ircmsgs |
|
1
by Dennis Kaarsemaker
Initial checkin |
19 |
import supybot.ircutils as ircutils |
20 |
import supybot.callbacks as callbacks |
|
21 |
import supybot.conf as conf |
|
22 |
import supybot.registry as registry |
|
|
21
by Dennis Kaarsemaker
* Completely rewritten encyclopedia plugin |
23 |
import supybot.schedule as schedule |
24 |
||
|
165
by Jonathan Davies
Bugtracker/plugin.py: Don't import commands - not used. |
25 |
import re, os, time, imaplib |
|
1
by Dennis Kaarsemaker
Initial checkin |
26 |
import xml.dom.minidom as minidom |
27 |
from htmlentitydefs import entitydefs as entities |
|
28 |
import email.FeedParser |
|
|
53
by Dennis Kaarsemaker
Use the SOAP interface at bugs.donarmstrong.com for debbugs |
29 |
import SOAPpy |
|
1
by Dennis Kaarsemaker
Initial checkin |
30 |
|
|
151
by Jonathan Davies
Directly import Launchpad API bindings, let supybot report errors. |
31 |
# Launchpad bindings.
|
32 |
from launchpadlib.launchpad import Launchpad |
|
33 |
cachedir = os.path.expanduser("~/.launchpadlib/cache/") |
|
|
166
by Jonathan Davies
Fall back to auth'ed API login if login_anonymously is not available. |
34 |
|
35 |
try: |
|
36 |
launchpad = Launchpad.login_anonymously('Supybot: Bugtracker plugin', 'edge', |
|
37 |
cachedir) |
|
|
167
by Jonathan Davies
Catch AttributeError instead. |
38 |
except AttributeError: |
|
166
by Jonathan Davies
Fall back to auth'ed API login if login_anonymously is not available. |
39 |
launchpad = Launchpad.login_with('Supybot: Bugtracker plugin', 'edge', |
40 |
cachedir) |
|
|
149
by Jonathan Davies
Implemented anonymous bug reporting support to Bugtracker via the Launchpad |
41 |
|
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
42 |
bad_words = ["fuck","fuk","fucking","fuking","fukin","fuckin","fucked","fuked","fucker","shit","cunt","bastard","nazi","nigger","nigga","cock","bitches","bitch"] |
43 |
||
44 |
def makeClean(s): |
|
45 |
words = s.split() |
|
46 |
for word in words: |
|
47 |
if word.lower() in bad_words: |
|
48 |
words[words.index(word)] = "<censored>" |
|
49 |
return " ".join(words) |
|
50 |
||
|
1
by Dennis Kaarsemaker
Initial checkin |
51 |
def registerBugtracker(name, url='', description='', trackertype=''): |
52 |
conf.supybot.plugins.Bugtracker.bugtrackers().add(name) |
|
53 |
group = conf.registerGroup(conf.supybot.plugins.Bugtracker.bugtrackers, name) |
|
54 |
URL = conf.registerGlobalValue(group, 'url', registry.String(url, '')) |
|
55 |
DESC = conf.registerGlobalValue(group, 'description', registry.String(description, '')) |
|
56 |
TRACKERTYPE = conf.registerGlobalValue(group, 'trackertype', registry.String(trackertype, '')) |
|
57 |
if url: |
|
58 |
URL.setValue(url) |
|
59 |
if description: |
|
60 |
DESC.setValue(description) |
|
61 |
if trackertype: |
|
62 |
if defined_bugtrackers.has_key(trackertype.lower()): |
|
63 |
TRACKERTYPE.setValue(trackertype.lower()) |
|
64 |
else: |
|
65 |
raise BugtrackerError("Unknown trackertype: %s" % trackertype) |
|
66 |
||
67 |
entre = re.compile('&(\S*?);') |
|
68 |
def _getnodetxt(node): |
|
69 |
L = [] |
|
70 |
for childnode in node.childNodes: |
|
71 |
if childnode.nodeType == childnode.TEXT_NODE: |
|
72 |
L.append(childnode.data) |
|
73 |
val = ''.join(L) |
|
74 |
if node.hasAttribute('encoding'): |
|
75 |
encoding = node.getAttribute('encoding') |
|
76 |
if encoding == 'base64': |
|
77 |
try: |
|
78 |
val = val.decode('base64') |
|
79 |
except: |
|
80 |
val = 'Cannot convert bug data from base64.' |
|
81 |
while entre.search(val): |
|
82 |
entity = entre.search(val).group(1) |
|
83 |
if entity in entities: |
|
84 |
val = entre.sub(entities[entity], val) |
|
85 |
else: |
|
86 |
val = entre.sub('?', val) |
|
87 |
return val |
|
88 |
||
89 |
class BugtrackerError(Exception): |
|
90 |
"""A bugtracker error"""
|
|
91 |
pass
|
|
92 |
||
93 |
class BugNotFoundError(Exception): |
|
94 |
"""Pity, bug isn't there"""
|
|
95 |
pass
|
|
96 |
||
|
61
by Dennis Kaarsemaker
Fix CVE snarfer for new layout of CVE website |
97 |
cvere = re.compile(r'<th.*?Description.*?<td.*?>(.*?)\s*</td>', re.I | re.DOTALL) |
|
1
by Dennis Kaarsemaker
Initial checkin |
98 |
class Bugtracker(callbacks.PluginRegexp): |
99 |
"""Show a link to a bug report with a brief description"""
|
|
100 |
threaded = True |
|
101 |
callBefore = ['URL'] |
|
|
51
by Dennis Kaarsemaker
Misc fixes |
102 |
regexps = ['turlSnarfer', 'bugSnarfer', 'oopsSnarfer', 'cveSnarfer'] |
|
1
by Dennis Kaarsemaker
Initial checkin |
103 |
|
104 |
def __init__(self, irc): |
|
105 |
callbacks.PluginRegexp.__init__(self, irc) |
|
106 |
self.db = ircutils.IrcDict() |
|
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
107 |
events = [] |
|
1
by Dennis Kaarsemaker
Initial checkin |
108 |
for name in self.registryValue('bugtrackers'): |
109 |
registerBugtracker(name) |
|
110 |
group = self.registryValue('bugtrackers.%s' % name.replace('.','\\.'), value=False) |
|
111 |
if group.trackertype() in defined_bugtrackers.keys(): |
|
112 |
self.db[name] = defined_bugtrackers[group.trackertype()](name, group.url(), group.description()) |
|
113 |
else: |
|
|
136
by Terence Simpson
* Fix a couple more typos/strange supybot errors. |
114 |
# raise BugtrackerError("Unknown trackertype: %s (%s)" % (group.trackertype(), name))
|
115 |
self.log.warning("Unknown trackertype: %s (%s)" % (group.trackertype(), name)) |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
116 |
self.shorthand = utils.abbrev(self.db.keys()) |
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
117 |
|
118 |
# Schedule bug reporting
|
|
|
134
by Terence Simpson
Fix a couple of typos |
119 |
self.shown = {} |
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
120 |
if self.registryValue('imap_server') and self.registryValue('reportercache'): |
121 |
try: |
|
122 |
schedule.removeEvent(self.name() + '.bugreporter') |
|
123 |
except: |
|
124 |
pass
|
|
125 |
schedule.addPeriodicEvent(lambda: self.reportnewbugs(irc), 60, name=self.name() + '.bugreporter') |
|
|
87
by Terence Simpson
Made the IMAP code as generic as possible |
126 |
self.events += [self.name() + '.bugreporter'] |
127 |
self.log.info('Adding scheduled event "%s.bugreporter"' % self.name()) |
|
|
21
by Dennis Kaarsemaker
* Completely rewritten encyclopedia plugin |
128 |
|
|
35
by Dennis Kaarsemaker
adkfasdyfb |
129 |
def die(self): |
130 |
try: |
|
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
131 |
for event in self.events: |
|
87
by Terence Simpson
Made the IMAP code as generic as possible |
132 |
self.log.info('Removing scheduled event "%s"' % event) |
133 |
schedule.removeEvent(event) |
|
|
135
by Terence Simpson
More typos |
134 |
schedule.removeEvent(self.name()) |
|
35
by Dennis Kaarsemaker
adkfasdyfb |
135 |
except: |
136 |
pass
|
|
137 |
||
|
21
by Dennis Kaarsemaker
* Completely rewritten encyclopedia plugin |
138 |
def is_ok(self, channel, tracker, bug): |
139 |
now = time.time() |
|
140 |
for k in self.shown.keys(): |
|
|
35
by Dennis Kaarsemaker
adkfasdyfb |
141 |
if self.shown[k] < now - self.registryValue('repeatdelay', channel): |
|
21
by Dennis Kaarsemaker
* Completely rewritten encyclopedia plugin |
142 |
self.shown.pop(k) |
143 |
if (channel, tracker, bug) not in self.shown: |
|
144 |
self.shown[(channel, tracker, bug)] = now |
|
145 |
return True |
|
146 |
return False |
|
147 |
||
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
148 |
def is_new(self, tracker, tag, id): |
149 |
bugreporter_base = self.registryValue('reportercache') |
|
150 |
if not os.path.exists(os.path.join(bugreporter_base,tag,tracker.name,str(int(id/1000)),str(id))): |
|
151 |
try: |
|
152 |
os.makedirs(os.path.join(bugreporter_base,tag,tracker.name,str(int(id/1000)))) |
|
153 |
except: |
|
154 |
pass
|
|
155 |
fd = open(os.path.join(bugreporter_base,tag,tracker.name,str(int(id/1000)),str(id)),'w') |
|
156 |
fd.close() |
|
157 |
return True |
|
158 |
return False |
|
159 |
||
|
21
by Dennis Kaarsemaker
* Completely rewritten encyclopedia plugin |
160 |
def reportnewbugs(self,irc): |
161 |
# Compile list of bugs
|
|
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
162 |
self.log.info("Checking for new bugs") |
|
21
by Dennis Kaarsemaker
* Completely rewritten encyclopedia plugin |
163 |
bugs = {} |
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
164 |
if self.registryValue('imap_ssl'): |
165 |
sc = imaplib.IMAP4_SSL(self.registryValue('imap_server')) |
|
166 |
else: |
|
167 |
sc = imaplib.IMAP4(self.registryValue('imap_server')) |
|
168 |
sc.login(self.registryValue('imap_user'), self.registryValue('imap_password')) |
|
|
35
by Dennis Kaarsemaker
adkfasdyfb |
169 |
sc.select('INBOX') |
170 |
new_mail = sc.search(None, '(UNSEEN)')[1][0].split()[:20] |
|
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
171 |
|
172 |
# Read all new mail
|
|
|
35
by Dennis Kaarsemaker
adkfasdyfb |
173 |
for m in new_mail: |
174 |
msg = sc.fetch(m, 'RFC822')[1][0][1] |
|
175 |
fp = email.FeedParser.FeedParser() |
|
|
87
by Terence Simpson
Made the IMAP code as generic as possible |
176 |
sc.store(m, '+FLAGS', "(\Deleted)") # Mark message deleted so we don't have to process it again |
|
35
by Dennis Kaarsemaker
adkfasdyfb |
177 |
fp.feed(msg) |
178 |
bug = fp.close() |
|
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
179 |
tag = None |
|
87
by Terence Simpson
Made the IMAP code as generic as possible |
180 |
|
181 |
if 'X-Launchpad-Bug' not in bug.keys(): |
|
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
182 |
self.log.info('Ignoring e-mail with no detectable bug (Not from Launchpad)') |
|
35
by Dennis Kaarsemaker
adkfasdyfb |
183 |
continue
|
|
87
by Terence Simpson
Made the IMAP code as generic as possible |
184 |
else: |
185 |
tag = bug['X-Launchpad-Bug'] |
|
186 |
if 'distribution=' not in tag and 'product=' not in tag: |
|
187 |
self.log.info('Ignoring e-mail with no detectable bug (no distro/product)') |
|
188 |
continue
|
|
189 |
else: |
|
190 |
tag = tag.split(';')[0].strip().replace("product=",'').replace("distribution=","") |
|
191 |
||
192 |
if not tag: |
|
193 |
self.log.info('Ignoring e-mail with no detectible bug (bad tag)') |
|
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
194 |
|
195 |
tag = tag[tag.find('+')+1:tag.find('@')] |
|
|
35
by Dennis Kaarsemaker
adkfasdyfb |
196 |
if tag not in bugs: |
197 |
bugs[tag] = {} |
|
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
198 |
|
|
51
by Dennis Kaarsemaker
Misc fixes |
199 |
# Determine bugtracker type (currently only Launchpad is supported anyway)
|
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
200 |
if bug['X-Launchpad-Bug']: |
|
51
by Dennis Kaarsemaker
Misc fixes |
201 |
tracker = self.db['launchpad'] |
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
202 |
id = int(bug['Reply-To'].split()[1]) |
|
87
by Terence Simpson
Made the IMAP code as generic as possible |
203 |
subj = bug['Subject']; |
204 |
if '[NEW]' not in subj: #Not a new bug |
|
205 |
continue
|
|
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
206 |
if self.is_new(tracker, tag, id): |
207 |
component = bug['X-Launchpad-Bug'] |
|
208 |
if 'component' in component: |
|
209 |
component = component[component.find('component=')+10:] |
|
210 |
component = component[:component.find(';')].replace('None','') |
|
211 |
else: |
|
212 |
component = '' |
|
|
35
by Dennis Kaarsemaker
adkfasdyfb |
213 |
try: |
214 |
if component: |
|
|
48
by Dennis Kaarsemaker
Fixes in the bugtracker plugin, first attempt at not disturbing a meeting |
215 |
bugs[tag][id] = self.get_bug('',tracker, id, False)[0].replace('"','(%s) "' % component, 1) |
|
35
by Dennis Kaarsemaker
adkfasdyfb |
216 |
else: |
|
48
by Dennis Kaarsemaker
Fixes in the bugtracker plugin, first attempt at not disturbing a meeting |
217 |
bugs[tag][id] = self.get_bug('',tracker, id, False)[0] |
|
51
by Dennis Kaarsemaker
Misc fixes |
218 |
if '[apport]' in bugs[tag][id]: |
219 |
bugs[tag].pop(id) |
|
|
35
by Dennis Kaarsemaker
adkfasdyfb |
220 |
except: |
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
221 |
self.log.info("Unable to get new bug %d" % id) |
|
39
by Dennis Kaarsemaker
Made bantracker releaseable |
222 |
pass
|
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
223 |
else: |
224 |
self.log.info('Ignoring e-mail with no detectable bug') |
|
|
87
by Terence Simpson
Made the IMAP code as generic as possible |
225 |
|
226 |
reported_bugs = 0 |
|
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
227 |
|
|
21
by Dennis Kaarsemaker
* Completely rewritten encyclopedia plugin |
228 |
for c in irc.state.channels: |
|
87
by Terence Simpson
Made the IMAP code as generic as possible |
229 |
tags = self.registryValue('bugReporter', channel=c) |
230 |
if not tags: |
|
231 |
continue
|
|
232 |
for tag in tags.split(','): |
|
233 |
if not tag or tag not in bugs.keys(): |
|
234 |
continue
|
|
235 |
for b in sorted(bugs[tag].keys()): |
|
236 |
irc.queueMsg(ircmsgs.privmsg(c,'New bug: #%s' % bugs[tag][b][bugs[tag][b].find('bug ')+4:])) |
|
237 |
reported_bugs = reported_bugs+1 |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
238 |
|
239 |
def add(self, irc, msg, args, name, trackertype, url, description): |
|
240 |
"""<name> <type> <url> [<description>]
|
|
241 |
||
242 |
Add a bugtracker <url> to the list of defined bugtrackers. <type> is the
|
|
|
51
by Dennis Kaarsemaker
Misc fixes |
243 |
type of the tracker (currently only Launchpad, Debbugs, Bugzilla,
|
|
95
by Terence Simpson
Big-Old-Update Edition |
244 |
Issuezilla, Mantis and Trac are known). <name> is the name that will be used to
|
|
1
by Dennis Kaarsemaker
Initial checkin |
245 |
reference the bugzilla in all commands. Unambiguous abbreviations of
|
246 |
<name> will be accepted also. <description> is the common name for the
|
|
247 |
bugzilla and will be listed with the bugzilla query; if not given, it
|
|
248 |
defaults to <name>.
|
|
249 |
"""
|
|
250 |
name = name.lower() |
|
251 |
if not description: |
|
252 |
description = name |
|
253 |
if url[-1] == '/': |
|
254 |
url = url[:-1] |
|
255 |
trackertype = trackertype.lower() |
|
256 |
if trackertype in defined_bugtrackers: |
|
257 |
self.db[name] = defined_bugtrackers[trackertype](name,url,description) |
|
258 |
else: |
|
259 |
irc.error("Bugtrackers of type '%s' are not understood" % trackertype) |
|
260 |
return
|
|
261 |
registerBugtracker(name, url, description, trackertype) |
|
262 |
self.shorthand = utils.abbrev(self.db.keys()) |
|
263 |
irc.replySuccess() |
|
|
126
by Terence Simpson
Update code from working branch and fix a couple of bugs |
264 |
add = wrap(add, [('checkCapability', 'admin'), 'something', 'something', 'url', additional('text')]) |
|
1
by Dennis Kaarsemaker
Initial checkin |
265 |
|
266 |
def remove(self, irc, msg, args, name): |
|
267 |
"""<abbreviation>
|
|
268 |
||
269 |
Remove the bugtracker associated with <abbreviation> from the list of
|
|
270 |
defined bugtrackers.
|
|
271 |
"""
|
|
272 |
try: |
|
273 |
name = self.shorthand[name.lower()] |
|
274 |
del self.db[name] |
|
275 |
self.registryValue('bugtrackers').remove(name) |
|
276 |
self.shorthand = utils.abbrev(self.db.keys()) |
|
277 |
irc.replySuccess() |
|
278 |
except KeyError: |
|
279 |
s = self.registryValue('replyNoBugtracker', msg.args[0]) |
|
280 |
irc.error(s % name) |
|
|
126
by Terence Simpson
Update code from working branch and fix a couple of bugs |
281 |
remove = wrap(remove, [('checkCapability', 'admin'), 'text']) |
|
1
by Dennis Kaarsemaker
Initial checkin |
282 |
|
|
41
by Dennis Kaarsemaker
Bugtracker now is much more usable and contains documentation. Backwards |
283 |
def rename(self, irc, msg, args, oldname, newname, newdesc): |
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
284 |
"""<oldname> <newname>
|
285 |
||
|
72
by Terence Simpson
Added @help values |
286 |
Rename the bugtracker associated with <oldname> to <newname>.
|
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
287 |
"""
|
288 |
try: |
|
289 |
name = self.shorthand[oldname.lower()] |
|
290 |
group = self.registryValue('bugtrackers.%s' % name.replace('.','\\.'), value=False) |
|
|
41
by Dennis Kaarsemaker
Bugtracker now is much more usable and contains documentation. Backwards |
291 |
d = group.description() |
292 |
if newdesc: |
|
293 |
d = newdesc |
|
294 |
self.db[newname] = defined_bugtrackers[group.trackertype()](name,group.url(),d) |
|
295 |
registerBugtracker(newname, group.url(), d, group.trackertype()) |
|
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
296 |
del self.db[name] |
297 |
self.registryValue('bugtrackers').remove(name) |
|
298 |
self.shorthand = utils.abbrev(self.db.keys()) |
|
299 |
irc.replySuccess() |
|
300 |
except KeyError: |
|
301 |
s = self.registryValue('replyNoBugtracker', msg.args[0]) |
|
302 |
irc.error(s % name) |
|
|
126
by Terence Simpson
Update code from working branch and fix a couple of bugs |
303 |
rename = wrap(rename, [('checkCapability', 'admin'), 'something','something', additional('text')]) |
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
304 |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
305 |
def list(self, irc, msg, args, name): |
306 |
"""[abbreviation]
|
|
307 |
||
308 |
List defined bugtrackers. If [abbreviation] is specified, list the
|
|
309 |
information for that bugtracker.
|
|
310 |
"""
|
|
311 |
if name: |
|
312 |
name = name.lower() |
|
313 |
try: |
|
314 |
name = self.shorthand[name] |
|
315 |
(url, description, type) = (self.db[name].url, self.db[name].description, |
|
316 |
self.db[name].__class__.__name__) |
|
317 |
irc.reply('%s: %s, %s [%s]' % (name, description, url, type)) |
|
318 |
except KeyError: |
|
319 |
s = self.registryValue('replyNoBugtracker', msg.args[0]) |
|
320 |
irc.error(s % name) |
|
321 |
else: |
|
322 |
if self.db: |
|
323 |
L = self.db.keys() |
|
324 |
L.sort() |
|
325 |
irc.reply(utils.str.commaAndify(L)) |
|
326 |
else: |
|
327 |
irc.reply('I have no defined bugtrackers.') |
|
328 |
list = wrap(list, [additional('text')]) |
|
329 |
||
330 |
def bugSnarfer(self, irc, msg, match): |
|
|
144
by Terence Simpson
Tweak regex for bugSnarfer in Bugtracker (LP: #148777) |
331 |
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+))*)"""
|
|
28
by Dennis Kaarsemaker
Just keep fixing |
332 |
if msg.args[0][0] == '#' and not self.registryValue('bugSnarfer', msg.args[0]): |
|
1
by Dennis Kaarsemaker
Initial checkin |
333 |
return
|
|
43
by Dennis Kaarsemaker
More fixes everywhere |
334 |
nbugs = msg.tagged('nbugs') |
335 |
if not nbugs: nbugs = 0 |
|
336 |
if nbugs >= 5: |
|
337 |
return
|
|
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
338 |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
339 |
# Don't double on commands
|
340 |
s = str(msg).split(':')[2] |
|
|
92
by Terence Simpson
Bugtracker: Small fix |
341 |
if s and s[0] in str(conf.supybot.reply.whenAddressedBy.chars): |
|
1
by Dennis Kaarsemaker
Initial checkin |
342 |
return
|
343 |
sure_bug = match.group('bt').endswith('bug') or match.group('bt').endswith('bug') |
|
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
344 |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
345 |
# Get tracker name
|
346 |
bugids = match.group('bug') |
|
|
21
by Dennis Kaarsemaker
* Completely rewritten encyclopedia plugin |
347 |
reps = ((' ',''),('#',''),('and',','),('en',','),('et',','),('und',','),('ir',',')) |
|
1
by Dennis Kaarsemaker
Initial checkin |
348 |
for r in reps: |
349 |
bugids = bugids.replace(r[0],r[1]) |
|
|
43
by Dennis Kaarsemaker
More fixes everywhere |
350 |
bugids = bugids.split(',')[:5-nbugs] |
|
48
by Dennis Kaarsemaker
Fixes in the bugtracker plugin, first attempt at not disturbing a meeting |
351 |
if not sure_bug: |
352 |
bugids = [x for x in bugids if int(x) > 100] |
|
|
43
by Dennis Kaarsemaker
More fixes everywhere |
353 |
msg.tag('nbugs', nbugs + len(bugids)) |
|
1
by Dennis Kaarsemaker
Initial checkin |
354 |
bt = map(lambda x: x.lower(), match.group('bt').split()) |
355 |
name = '' |
|
356 |
if len(bt) == 1 and not (bt[0] in ['bug','bugs']): |
|
357 |
try: |
|
358 |
name = bt[0].lower() |
|
359 |
tracker = self.db[name] |
|
360 |
except: |
|
361 |
return
|
|
362 |
elif len(bt) == 2: |
|
363 |
try: |
|
364 |
name = bt[0].lower() |
|
365 |
tracker = self.db[name] |
|
366 |
except: |
|
367 |
name = '' |
|
368 |
pass
|
|
369 |
if not name: |
|
|
35
by Dennis Kaarsemaker
adkfasdyfb |
370 |
snarfTarget = self.registryValue('snarfTarget', msg.args[0]).lower() |
|
1
by Dennis Kaarsemaker
Initial checkin |
371 |
if not snarfTarget: |
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
372 |
self.log.warning("no snarfTarget for Bugtracker") |
|
1
by Dennis Kaarsemaker
Initial checkin |
373 |
return
|
374 |
try: |
|
375 |
name = self.shorthand[snarfTarget.lower()] |
|
376 |
except: |
|
377 |
s = self.registryValue('replyNoBugtracker', name) |
|
378 |
irc.error(s % name) |
|
379 |
try: |
|
380 |
tracker = self.db[name] |
|
381 |
except KeyError: |
|
382 |
s = self.registryValue('replyNoBugtracker', name) |
|
383 |
irc.error(s % name) |
|
384 |
else: |
|
385 |
for bugid in bugids: |
|
386 |
bugid = int(bugid) |
|
387 |
try: |
|
|
48
by Dennis Kaarsemaker
Fixes in the bugtracker plugin, first attempt at not disturbing a meeting |
388 |
report = self.get_bug(msg.args[0],tracker,bugid,self.registryValue('showassignee', msg.args[0])) |
|
41
by Dennis Kaarsemaker
Bugtracker now is much more usable and contains documentation. Backwards |
389 |
except BugNotFoundError: |
|
43
by Dennis Kaarsemaker
More fixes everywhere |
390 |
if self.registryValue('replyWhenNotFound'): |
391 |
irc.error("%s bug %d could not be found" % (tracker.description, bugid)) |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
392 |
except BugtrackerError, e: |
|
27
by Dennis Kaarsemaker
Yes, more features! |
393 |
if 'private' in str(e): |
394 |
irc.reply("Bug %d on http://launchpad.net/bugs/%d is private" % (bugid, bugid)) |
|
395 |
return
|
|
|
1
by Dennis Kaarsemaker
Initial checkin |
396 |
if not sure_bug and bugid < 30: |
397 |
return
|
|
398 |
irc.error(str(e)) |
|
399 |
else: |
|
|
35
by Dennis Kaarsemaker
adkfasdyfb |
400 |
for r in report: |
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
401 |
irc.reply(makeClean(r), prefixNick=False) |
|
1
by Dennis Kaarsemaker
Initial checkin |
402 |
|
403 |
def turlSnarfer(self, irc, msg, match): |
|
|
43
by Dennis Kaarsemaker
More fixes everywhere |
404 |
r"(?P<tracker>https?://\S*?)/(Bugs/0*|str.php\?L|show_bug.cgi\?id=|bugreport.cgi\?bug=|(bugs|\+bug)/|ticket/|tracker/|\S*aid=)(?P<bug>\d+)(?P<sfurl>&group_id=\d+&at_id=\d+)?"
|
|
28
by Dennis Kaarsemaker
Just keep fixing |
405 |
if msg.args[0][0] == '#' and not self.registryValue('bugSnarfer', msg.args[0]): |
|
1
by Dennis Kaarsemaker
Initial checkin |
406 |
return
|
|
43
by Dennis Kaarsemaker
More fixes everywhere |
407 |
nbugs = msg.tagged('nbugs') |
408 |
if not nbugs: nbugs = 0 |
|
409 |
if nbugs >= 5: |
|
410 |
return
|
|
411 |
msg.tag('nbugs', nbugs+1) |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
412 |
try: |
413 |
tracker = self.get_tracker(match.group(0),match.group('sfurl')) |
|
414 |
if not tracker: |
|
|
21
by Dennis Kaarsemaker
* Completely rewritten encyclopedia plugin |
415 |
return
|
|
48
by Dennis Kaarsemaker
Fixes in the bugtracker plugin, first attempt at not disturbing a meeting |
416 |
report = self.get_bug(msg.args[0],tracker,int(match.group('bug')),self.registryValue('showassignee', msg.args[0]), do_url = False) |
|
1
by Dennis Kaarsemaker
Initial checkin |
417 |
except BugtrackerError, e: |
418 |
irc.error(str(e)) |
|
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
419 |
except BugNotFoundError, e: |
420 |
irc.error("%s bug %s not found" % (tracker, match.group('bug'))) |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
421 |
else: |
|
35
by Dennis Kaarsemaker
adkfasdyfb |
422 |
for r in report: |
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
423 |
irc.reply(makeClean(r), prefixNick=False) |
|
1
by Dennis Kaarsemaker
Initial checkin |
424 |
turlSnarfer = urlSnarfer(turlSnarfer) |
425 |
||
426 |
# Only useful for launchpad developers
|
|
427 |
def oopsSnarfer(self, irc, msg, match): |
|
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
428 |
r"OOPS-(?P<oopsid>\d*[\dA-Z]+)"
|
|
51
by Dennis Kaarsemaker
Misc fixes |
429 |
if msg.args[0][0] == '#' and not self.registryValue('bugSnarfer', msg.args[0]): |
430 |
return
|
|
|
1
by Dennis Kaarsemaker
Initial checkin |
431 |
oopsid = match.group(1) |
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
432 |
if oopsid.lower() == "tools": |
433 |
return
|
|
434 |
irc.reply("https://lp-oops.canonical.com/oops.py/?oopsid=%s" % oopsid, prefixNick=False) |
|
435 |
#irc.reply("https://devpad.canonical.com/~jamesh/oops.cgi/%s" % oopsid, prefixNick=False)
|
|
|
51
by Dennis Kaarsemaker
Misc fixes |
436 |
|
437 |
def cveSnarfer(self, irc, msg, match): |
|
438 |
r"(cve[- ]\d{4}[- ]\d{4})"
|
|
439 |
if msg.args[0][0] == '#' and not self.registryValue('bugSnarfer', msg.args[0]): |
|
440 |
return
|
|
441 |
cve = match.group(1).replace(' ','-').upper() |
|
442 |
url = 'http://cve.mitre.org/cgi-bin/cvename.cgi?name=%s' % cve |
|
443 |
cvedata = utils.web.getUrl(url) |
|
444 |
m = cvere.search(cvedata) |
|
445 |
if m: |
|
446 |
cve = m.group(1).replace('\n', ' ') |
|
447 |
irc.reply("%s (%s)" % (cve,url)) |
|
448 |
||
449 |
def cveUrlSnarfer(self, irc, msg, match): |
|
450 |
pass
|
|
|
1
by Dennis Kaarsemaker
Initial checkin |
451 |
|
452 |
def get_tracker(self,snarfurl,sfdata): |
|
|
44
by Dennis Kaarsemaker
Fixy fixy! |
453 |
snarfurl = snarfurl.replace('sf.net','sourceforge.net') |
|
27
by Dennis Kaarsemaker
Yes, more features! |
454 |
snarfhost = snarfurl.replace('http://','').replace('https://','') |
455 |
if '/' in snarfurl: |
|
456 |
snarfhost = snarfhost[:snarfhost.index('/')] |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
457 |
for t in self.db.keys(): |
458 |
tracker = self.db[t] |
|
459 |
url = tracker.url.replace('http://','').replace('https://','') |
|
460 |
if 'sourceforge.net' in url: |
|
461 |
# Try to find the correct sf tracker
|
|
462 |
if str(sfdata) in tracker.url: |
|
463 |
return tracker |
|
464 |
if '/' in url: |
|
465 |
url = url[:url.index('/')] |
|
|
27
by Dennis Kaarsemaker
Yes, more features! |
466 |
if url in snarfhost: |
|
1
by Dennis Kaarsemaker
Initial checkin |
467 |
return tracker |
468 |
if 'sourceforge.net' in snarfurl: |
|
469 |
return self.db['sourceforge'] |
|
470 |
# No tracker found, bummer. Let's try and add one
|
|
471 |
if 'show_bug.cgi' in snarfurl: |
|
472 |
tracker = Bugzilla().get_tracker(snarfurl) |
|
473 |
if tracker: |
|
474 |
self.db[tracker.name] = tracker |
|
475 |
self.shorthand = utils.abbrev(self.db.keys()) |
|
476 |
return tracker |
|
477 |
return None |
|
478 |
||
|
48
by Dennis Kaarsemaker
Fixes in the bugtracker plugin, first attempt at not disturbing a meeting |
479 |
def get_bug(self, channel, tracker, id, do_assignee, do_url = True): |
|
35
by Dennis Kaarsemaker
adkfasdyfb |
480 |
reports = [] |
481 |
for r in tracker.get_bug(id): |
|
|
48
by Dennis Kaarsemaker
Fixes in the bugtracker plugin, first attempt at not disturbing a meeting |
482 |
if not self.is_ok(channel, tracker, r[0]): |
483 |
continue
|
|
|
35
by Dennis Kaarsemaker
adkfasdyfb |
484 |
(bid, product, title, severity, status, assignee, url) = r |
485 |
severity = severity[0].upper() + severity[1:].lower() |
|
486 |
status = status[0].upper() + status[1:].lower() |
|
487 |
if not do_url: |
|
488 |
url = '' |
|
489 |
if product: |
|
490 |
reports.append("%s bug %s in %s \"%s\" [%s,%s] %s" % (tracker.description, bid, product, |
|
491 |
title, severity, status, url)) |
|
492 |
else: |
|
493 |
reports.append("%s bug %s \"%s\" [%s,%s] %s" % (tracker.description, bid, title, severity, status, url)) |
|
494 |
if do_assignee and assignee: |
|
495 |
reports[-1] = reports[-1] + (" - Assigned to %s" % assignee) |
|
496 |
return reports |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
497 |
|
498 |
# Define all bugtrackers
|
|
499 |
class IBugtracker: |
|
500 |
def __init__(self, name=None, url=None, description=None): |
|
501 |
self.name = name |
|
502 |
self.url = url |
|
503 |
self.description = description |
|
504 |
||
505 |
def get_bug(self, id): |
|
506 |
raise BugTrackerError("Bugtracker class does not implement get_bug") |
|
507 |
||
508 |
def get_tracker(self, url): |
|
509 |
raise BugTrackerError("Bugtracker class does not implement get_tracker") |
|
510 |
||
511 |
class Bugzilla(IBugtracker): |
|
512 |
def get_tracker(self, url): |
|
513 |
url = url.replace('show_bug','xml') |
|
514 |
try: |
|
515 |
bugxml = utils.web.getUrl(url) |
|
516 |
tree = minidom.parseString(bugxml) |
|
517 |
url = str(tree.getElementsByTagName('bugzilla')[0].attributes['urlbase'].childNodes[0].data) |
|
518 |
if url[-1] == '/': |
|
519 |
url = url[:-1] |
|
520 |
name = url[url.find('//') + 2:] |
|
521 |
if '/' in name: |
|
522 |
name = name[:name.find('/')] |
|
523 |
desc = name |
|
524 |
registerBugtracker(name, url, desc, 'bugzilla') |
|
525 |
tracker = Bugzilla(name, url, desc) |
|
526 |
return tracker |
|
527 |
except: |
|
528 |
return None |
|
529 |
def get_bug(self, id): |
|
530 |
url = "%s/xml.cgi?id=%d" % (self.url,id) |
|
531 |
try: |
|
532 |
bugxml = utils.web.getUrl(url) |
|
533 |
zilladom = minidom.parseString(bugxml) |
|
534 |
except Exception, e: |
|
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
535 |
s = 'Could not parse XML returned by %s: %s (%s)' % (self.description, e, url) |
|
1
by Dennis Kaarsemaker
Initial checkin |
536 |
raise BugtrackerError, s |
537 |
bug_n = zilladom.getElementsByTagName('bug')[0] |
|
538 |
if bug_n.hasAttribute('error'): |
|
539 |
errtxt = bug_n.getAttribute('error') |
|
|
41
by Dennis Kaarsemaker
Bugtracker now is much more usable and contains documentation. Backwards |
540 |
if errtxt == 'NotFound': |
541 |
raise BugNotFoundError |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
542 |
s = 'Error getting %s bug #%s: %s' % (self.description, id, errtxt) |
543 |
raise BugtrackerError, s |
|
544 |
try: |
|
545 |
title = _getnodetxt(bug_n.getElementsByTagName('short_desc')[0]) |
|
546 |
status = _getnodetxt(bug_n.getElementsByTagName('bug_status')[0]) |
|
547 |
try: |
|
548 |
status += ": " + _getnodetxt(bug_n.getElementsByTagName('resolution')[0]) |
|
549 |
except: |
|
550 |
pass
|
|
551 |
component = _getnodetxt(bug_n.getElementsByTagName('component')[0]) |
|
552 |
severity = _getnodetxt(bug_n.getElementsByTagName('bug_severity')[0]) |
|
|
41
by Dennis Kaarsemaker
Bugtracker now is much more usable and contains documentation. Backwards |
553 |
assignee = '(unavailable)' |
554 |
try: |
|
555 |
assignee = _getnodetxt(bug_n.getElementsByTagName('assigned_to')[0]) |
|
556 |
except: |
|
557 |
pass
|
|
|
1
by Dennis Kaarsemaker
Initial checkin |
558 |
except Exception, e: |
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
559 |
s = 'Could not parse XML returned by %s bugzilla: %s (%s)' % (self.description, e, url) |
|
1
by Dennis Kaarsemaker
Initial checkin |
560 |
raise BugtrackerError, s |
|
35
by Dennis Kaarsemaker
adkfasdyfb |
561 |
return [(id, component, title, severity, status, assignee, "%s/show_bug.cgi?id=%d" % (self.url, id))] |
|
1
by Dennis Kaarsemaker
Initial checkin |
562 |
|
563 |
class Issuezilla(IBugtracker): |
|
564 |
def get_bug(self, id): |
|
565 |
url = "%s/xml.cgi?id=%d" % (self.url,id) |
|
566 |
try: |
|
567 |
bugxml = utils.web.getUrl(url) |
|
568 |
zilladom = minidom.parseString(bugxml) |
|
569 |
except Exception, e: |
|
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
570 |
s = 'Could not parse XML returned by %s: %s (%s)' % (self.description, e, url) |
|
1
by Dennis Kaarsemaker
Initial checkin |
571 |
raise BugtrackerError, s |
572 |
bug_n = zilladom.getElementsByTagName('issue')[0] |
|
573 |
if not (bug_n.getAttribute('status_code') == '200'): |
|
|
41
by Dennis Kaarsemaker
Bugtracker now is much more usable and contains documentation. Backwards |
574 |
if bug_n.getAttribute('status_message') == 'NotFound': |
575 |
raise BugNotFoundError |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
576 |
s = 'Error getting %s bug #%s: %s' % (self.description, id, bug_n.getAttribute('status_message')) |
577 |
raise BugtrackerError, s |
|
578 |
try: |
|
579 |
title = _getnodetxt(bug_n.getElementsByTagName('short_desc')[0]) |
|
580 |
status = _getnodetxt(bug_n.getElementsByTagName('issue_status')[0]) |
|
581 |
try: |
|
582 |
status += ": " + _getnodetxt(bug_n.getElementsByTagName('resolution')[0]) |
|
583 |
except: |
|
584 |
pass
|
|
585 |
component = _getnodetxt(bug_n.getElementsByTagName('component')[0]) |
|
586 |
severity = _getnodetxt(bug_n.getElementsByTagName('issue_type')[0]) |
|
|
35
by Dennis Kaarsemaker
adkfasdyfb |
587 |
assignee = _getnodetxt(bug_n.getElementsByTagName('assigned_to')[0]) |
|
1
by Dennis Kaarsemaker
Initial checkin |
588 |
except Exception, e: |
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
589 |
s = 'Could not parse XML returned by %s bugzilla: %s (%s)' % (self.description, e, url) |
|
1
by Dennis Kaarsemaker
Initial checkin |
590 |
raise BugtrackerError, s |
|
35
by Dennis Kaarsemaker
adkfasdyfb |
591 |
return [(id, component, title, severity, status, assignee, "%s/show_bug.cgi?id=%d" % (self.url, id))] |
|
1
by Dennis Kaarsemaker
Initial checkin |
592 |
|
|
51
by Dennis Kaarsemaker
Misc fixes |
593 |
class Launchpad(IBugtracker): |
|
1
by Dennis Kaarsemaker
Initial checkin |
594 |
def get_bug(self, id): |
595 |
try: |
|
|
156
by Jonathan Davies
Removed debug code. |
596 |
#print "Looking up bug #%s..." % id
|
|
154
by Jonathan Davies
Mass clean-up of code to the state that it actually works. |
597 |
bug_data = launchpad.bugs[int(id)] |
|
149
by Jonathan Davies
Implemented anonymous bug reporting support to Bugtracker via the Launchpad |
598 |
except KeyError: |
|
154
by Jonathan Davies
Mass clean-up of code to the state that it actually works. |
599 |
raise BugtrackerError, "Bug #%s not found." % id |
|
159
by Jonathan Davies
Really catch private bugs. |
600 |
except: |
|
168
by Jonathan Davies
Display bug heat stuff. |
601 |
print Exception.message |
602 |
||
603 |
try: |
|
604 |
bug_data.private |
|
605 |
except: |
|
|
149
by Jonathan Davies
Implemented anonymous bug reporting support to Bugtracker via the Launchpad |
606 |
raise BugtrackerError, "Bug #%s is private." % id |
607 |
||
|
154
by Jonathan Davies
Mass clean-up of code to the state that it actually works. |
608 |
bug_title = bug_data.title |
|
162
by Jonathan Davies
Display how many users a bug affects. |
609 |
people_affected = bug_data.users_affected_count_with_dupes |
|
158
by Jonathan Davies
Read task data of a bug from the last task. |
610 |
bug_tasks_number = len(bug_data.bug_tasks) - 1 |
611 |
# Read task data from last task.
|
|
612 |
bug_task = list(bug_data.bug_tasks)[bug_tasks_number] |
|
|
154
by Jonathan Davies
Mass clean-up of code to the state that it actually works. |
613 |
bug_project = bug_task.bug_target_name |
614 |
bug_importance = bug_task.importance |
|
615 |
bug_status = bug_task.status |
|
616 |
bug_assignee = "" |
|
|
163
by Jonathan Davies
Report how many duplicates a bug report has. |
617 |
bug_duplicates = len(bug_data.duplicates) |
|
168
by Jonathan Davies
Display bug heat stuff. |
618 |
bug_heat = bug_data.heat |
619 |
||
|
154
by Jonathan Davies
Mass clean-up of code to the state that it actually works. |
620 |
if bug_task.assignee: |
621 |
bug_assignee = bug_task.assignee.name |
|
|
168
by Jonathan Davies
Display bug heat stuff. |
622 |
|
|
160
by Jonathan Davies
Catch bugs with more than one task and report the number of tasks. |
623 |
if bug_tasks_number > 0: |
624 |
if bug_tasks_number == 1: |
|
|
161
by Jonathan Davies
Improved wording of more projects reply. |
625 |
bug_project += " (and %d other project)" % bug_tasks_number |
|
160
by Jonathan Davies
Catch bugs with more than one task and report the number of tasks. |
626 |
else: |
|
161
by Jonathan Davies
Improved wording of more projects reply. |
627 |
bug_project += " (and %d other projects)" % bug_tasks_number |
|
168
by Jonathan Davies
Display bug heat stuff. |
628 |
|
|
35
by Dennis Kaarsemaker
adkfasdyfb |
629 |
# Try and find duplicates
|
|
149
by Jonathan Davies
Implemented anonymous bug reporting support to Bugtracker via the Launchpad |
630 |
if bug_data.duplicate_of is not None: |
|
154
by Jonathan Davies
Mass clean-up of code to the state that it actually works. |
631 |
dup_bug = launchpad.bugs[id].duplicate_of |
|
160
by Jonathan Davies
Catch bugs with more than one task and report the number of tasks. |
632 |
return [(id, bug_project, |
633 |
bug_title + (' (dup-of: %d)' % dup_bug.id), bug_importance, |
|
634 |
bug_status, bug_assignee, |
|
635 |
"%s/bugs/%s" % (self.url, id))] + self.get_bug(dup_bug.id) |
|
|
149
by Jonathan Davies
Implemented anonymous bug reporting support to Bugtracker via the Launchpad |
636 |
|
|
162
by Jonathan Davies
Display how many users a bug affects. |
637 |
if people_affected > 0: |
|
164
by Jonathan Davies
Added a : here. |
638 |
bug_title += " (affects: %d)" % people_affected |
|
163
by Jonathan Davies
Report how many duplicates a bug report has. |
639 |
|
640 |
if bug_duplicates > 0: |
|
641 |
bug_title += " (dups: %d)" % bug_duplicates |
|
|
162
by Jonathan Davies
Display how many users a bug affects. |
642 |
|
|
168
by Jonathan Davies
Display bug heat stuff. |
643 |
if bug_heat != 0: |
644 |
bug_title += " (heat: %d)" % bug_heat |
|
645 |
||
|
160
by Jonathan Davies
Catch bugs with more than one task and report the number of tasks. |
646 |
return [(id, bug_project, bug_title, bug_importance, bug_status, |
647 |
bug_assignee, "%s/bugs/%s" % (self.url, id))] |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
648 |
|
649 |
# <rant>
|
|
650 |
# Debbugs sucks donkeyballs
|
|
651 |
# * HTML pages are inconsistent
|
|
652 |
# * Parsing mboxes gets incorrect with cloning perversions (eg with bug 330000)
|
|
|
21
by Dennis Kaarsemaker
* Completely rewritten encyclopedia plugin |
653 |
# * No sane way of accessing bug reports in a machine readable way (bts2ldap
|
654 |
# has no search on bugid)
|
|
655 |
# * The damn thing allow incomplete bugs, eg bugs without severity set. WTF?!?
|
|
|
1
by Dennis Kaarsemaker
Initial checkin |
656 |
#
|
|
53
by Dennis Kaarsemaker
Use the SOAP interface at bugs.donarmstrong.com for debbugs |
657 |
# Fortunately bugs.donarmstrong.com has a SOAP interface which we can use.
|
|
1
by Dennis Kaarsemaker
Initial checkin |
658 |
# </rant>
|
659 |
class Debbugs(IBugtracker): |
|
|
53
by Dennis Kaarsemaker
Use the SOAP interface at bugs.donarmstrong.com for debbugs |
660 |
def __init__(self, *args, **kwargs): |
661 |
IBugtracker.__init__(self, *args, **kwargs) |
|
|
66
by Dennis Kaarsemaker
Misc fixes |
662 |
self.soap_proxy = SOAPpy.SOAPProxy("bugs.debian.org/cgi-bin/soap.cgi", "Debbugs/SOAP/Status") |
|
53
by Dennis Kaarsemaker
Use the SOAP interface at bugs.donarmstrong.com for debbugs |
663 |
self.soap_proxy.soapaction = "Debbugs/SOAP/Status#get_status" |
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
664 |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
665 |
def get_bug(self, id): |
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
666 |
bug_url = "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%d" % id |
|
1
by Dennis Kaarsemaker
Initial checkin |
667 |
try: |
|
53
by Dennis Kaarsemaker
Use the SOAP interface at bugs.donarmstrong.com for debbugs |
668 |
raw = self.soap_proxy.get_status(id) |
|
1
by Dennis Kaarsemaker
Initial checkin |
669 |
except Exception, e: |
670 |
s = 'Could not parse data returned by %s: %s' % (self.description, e) |
|
671 |
raise BugtrackerError, s |
|
|
53
by Dennis Kaarsemaker
Use the SOAP interface at bugs.donarmstrong.com for debbugs |
672 |
if not raw: |
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
673 |
raise BugNotFoundError |
|
53
by Dennis Kaarsemaker
Use the SOAP interface at bugs.donarmstrong.com for debbugs |
674 |
raw = raw['item']['value'] |
|
1
by Dennis Kaarsemaker
Initial checkin |
675 |
try: |
|
53
by Dennis Kaarsemaker
Use the SOAP interface at bugs.donarmstrong.com for debbugs |
676 |
if len(raw['fixed_versions']): |
677 |
status = 'Fixed' |
|
678 |
else: |
|
679 |
status = 'Open' |
|
680 |
return [(id, raw['package'], raw['subject'], raw['severity'], status, '', "%s/%s" % (self.url, id))] |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
681 |
except Exception, e: |
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
682 |
s = 'Could not parse data returned by %s bugtracker: %s (%s)' % (self.description, e, bug_url) |
|
1
by Dennis Kaarsemaker
Initial checkin |
683 |
raise BugtrackerError, s |
684 |
||
|
95
by Terence Simpson
Big-Old-Update Edition |
685 |
class Mantis(IBugtracker): |
686 |
def __init__(self, *args, **kwargs): |
|
687 |
IBugtracker.__init__(self, *args, **kwargs) |
|
688 |
self.soap_proxy = SOAPpy.SOAPProxy(self.url + "/api/soap/mantisconnect.php", "http://futureware.biz/mantisconnect") |
|
689 |
self.soap_proxy.soapaction = "http://futureware.biz/mantisconnect#mc_issue_get" |
|
690 |
||
691 |
def get_bug(self, id): |
|
692 |
url = self.url + "/view.php?id=%i" % id |
|
693 |
try: |
|
694 |
raw = self.soap_proxy.mc_issue_get('', "", id) |
|
695 |
except Exception, e: |
|
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
696 |
s = 'Could not parse data returned by %s: %s (%s)' % (self.description, e, url) |
|
95
by Terence Simpson
Big-Old-Update Edition |
697 |
raise BugtrackerError, s |
698 |
if not raw: |
|
699 |
raise BugNotFoundError |
|
700 |
try: |
|
701 |
return [(id, raw['project']['name'], raw['summary'], raw['priority']['name'], raw['resolution']['name'], '', url)] |
|
702 |
except Exception, e: |
|
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
703 |
s = 'Could not parse data returned by %s bugtracker: %s (%s)' % (self.description, e, url) |
|
95
by Terence Simpson
Big-Old-Update Edition |
704 |
raise BugtrackerError, s |
705 |
||
|
132
by Terence Simpson
Bugtracker/plugin.py: Update Trac class to use the "Tab-delimited Text" source rather than screen-scraping |
706 |
# For trac based trackers we get the tab-separated-values format.
|
707 |
# The other option is a comma-separated-values format, but if the description
|
|
708 |
# has commas, things get tricky.
|
|
709 |
# This should be more robust than the screen-scraping done previously.
|
|
|
1
by Dennis Kaarsemaker
Initial checkin |
710 |
class Trac(IBugtracker): |
|
132
by Terence Simpson
Bugtracker/plugin.py: Update Trac class to use the "Tab-delimited Text" source rather than screen-scraping |
711 |
def get_bug(self, id): # This is still a little rough, but it works :) |
712 |
bug_url = "%s/%d" % (self.url, id) |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
713 |
try: |
|
132
by Terence Simpson
Bugtracker/plugin.py: Update Trac class to use the "Tab-delimited Text" source rather than screen-scraping |
714 |
raw = utils.web.getUrl("%s?format=tab" % bug_url) |
|
1
by Dennis Kaarsemaker
Initial checkin |
715 |
except Exception, e: |
|
41
by Dennis Kaarsemaker
Bugtracker now is much more usable and contains documentation. Backwards |
716 |
if 'HTTP Error 500' in str(e): |
717 |
raise BugNotFoundError |
|
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
718 |
s = 'Could not parse data returned by %s: %s' % (self.description, e, bug_url) |
|
1
by Dennis Kaarsemaker
Initial checkin |
719 |
raise BugtrackerError, s |
|
132
by Terence Simpson
Bugtracker/plugin.py: Update Trac class to use the "Tab-delimited Text" source rather than screen-scraping |
720 |
raw = raw.replace("\r\n", '\n') |
721 |
(headers, rest) = raw.split('\n', 1) |
|
722 |
headers = headers.strip().split('\t') |
|
723 |
rest = rest.strip().split('\t') |
|
|
131
by Terence Simpson
Bugtracker/plugin.py: Temporary fix for Trac |
724 |
title = status = package = severity = assignee = "Unknown" |
|
132
by Terence Simpson
Bugtracker/plugin.py: Update Trac class to use the "Tab-delimited Text" source rather than screen-scraping |
725 |
if "summary" in headers: |
726 |
title = rest[headers.index("summary")] |
|
727 |
if "status" in headers: |
|
728 |
status = rest[headers.index("status")] |
|
729 |
if "component" in headers: |
|
730 |
package = rest[headers.index("component")] |
|
731 |
if "severity" in headers: |
|
732 |
severity = rest[headers.index("severity")] |
|
733 |
if "owner" in headers: |
|
734 |
assingee = rest[headers.index("owner")] |
|
735 |
if severity == "Unknown" and "priority" in headers: |
|
736 |
severity = rest[headers.index("priority")] |
|
737 |
||
738 |
return [(id, package, title, severity, status, assignee, bug_url)] |
|
|
31
by Dennis Kaarsemaker
This project is now officially the one with the worst commitlog :) |
739 |
|
740 |
class WikiForms(IBugtracker): |
|
741 |
def get_bug(self, id): |
|
742 |
def strip_tags(s): |
|
743 |
while '<' in s and '>' in s: |
|
744 |
s = str(s[:s.find('<')]) + str(s[s.find('>')+1:]) |
|
745 |
return s |
|
746 |
||
747 |
url = "%s/%05d" % (self.url, id) |
|
748 |
try: |
|
749 |
bugdata = utils.web.getUrl(url) |
|
750 |
except Exception, e: |
|
|
41
by Dennis Kaarsemaker
Bugtracker now is much more usable and contains documentation. Backwards |
751 |
if 'HTTP Error 404' in str(e): |
752 |
raise BugNotFoundError |
|
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
753 |
s = 'Could not parse data returned by %s: %s (%s)' % (self.description, e, url) |
|
31
by Dennis Kaarsemaker
This project is now officially the one with the worst commitlog :) |
754 |
raise BugtrackerError, s |
755 |
for l in bugdata.split("\n"): |
|
756 |
l2 = l.lower() |
|
757 |
if '<dt>importance</dt>' in l2: |
|
758 |
severity = 'Importance ' + strip_tags(l[l.find('<dd>')+4:]) |
|
759 |
if '<dt>summary</dt>' in l2: |
|
760 |
title = strip_tags(l[l.find('<dd>')+4:]) |
|
761 |
if '<dt>status</dt>' in l2: |
|
762 |
status = strip_tags(l[l.find('<dd>')+4:]) |
|
763 |
if '<dt>category</dt>' in l2: |
|
764 |
package = strip_tags(l[l.find('<dd>')+4:]) |
|
|
35
by Dennis Kaarsemaker
adkfasdyfb |
765 |
return [(id, package, title, severity, status, '', "%s/%05d" % (self.url, id))] |
|
41
by Dennis Kaarsemaker
Bugtracker now is much more usable and contains documentation. Backwards |
766 |
|
767 |
class Str(IBugtracker): |
|
768 |
def get_bug(self, id): |
|
769 |
def strip_tags(s): |
|
770 |
while '<' in s and '>' in s: |
|
771 |
s = str(s[:s.find('<')]) + str(s[s.find('>')+1:]) |
|
772 |
return s |
|
773 |
url = "%s?L%d" % (self.url, id) |
|
774 |
try: |
|
775 |
bugdata = utils.web.getUrl(url) |
|
776 |
except Exception, e: |
|
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
777 |
s = 'Could not parse data returned by %s: %s (%s)' % (self.description, e, url) |
|
41
by Dennis Kaarsemaker
Bugtracker now is much more usable and contains documentation. Backwards |
778 |
raise BugtrackerError, s |
779 |
for l in bugdata.split("\n"): |
|
780 |
l2 = l.lower() |
|
781 |
if 'nowrap>priority:</th>' in l2: |
|
782 |
severity = 'Priority ' + l[l.find(' - ')+3:min(l.find(','),l.find('</td>'))] |
|
783 |
if '>application:</th>' in l2: |
|
784 |
package = l[l.find('<td>')+4:l.find('</td>')] |
|
785 |
if 'nowrap>status:</th>' in l2: |
|
786 |
status = l[l.find(' - ')+3:l.find('</td>')] |
|
787 |
if 'nowrap>summary:</th>' in l2: |
|
788 |
title = l[l.find('<td>')+4:l.find('</td>')] |
|
789 |
if 'nowrap>assigned to:</th>' in l2: |
|
790 |
assignee = strip_tags(l[l.find('<td>')+4:l.find('</td>')]) |
|
791 |
if assignee == 'Unassigned': |
|
792 |
assignee = 'nobody' |
|
|
42
by Dennis Kaarsemaker
Encyclopedia made neat. |
793 |
return [(id, package, title, severity, status, assignee, "%s?L%d" % (self.url, id))] |
|
41
by Dennis Kaarsemaker
Bugtracker now is much more usable and contains documentation. Backwards |
794 |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
795 |
|
796 |
sfre = re.compile(r""" |
|
797 |
.*?
|
|
798 |
<h2>\[.*?\]\s*(?P<title>.*?)</h2>
|
|
|
35
by Dennis Kaarsemaker
adkfasdyfb |
799 |
.*?
|
|
43
by Dennis Kaarsemaker
More fixes everywhere |
800 |
assigned.*?<br>\s+(?P<assignee>\S+)
|
|
1
by Dennis Kaarsemaker
Initial checkin |
801 |
.*?
|
|
43
by Dennis Kaarsemaker
More fixes everywhere |
802 |
priority.*?(?P<priority>\d+)
|
|
1
by Dennis Kaarsemaker
Initial checkin |
803 |
.*?
|
|
43
by Dennis Kaarsemaker
More fixes everywhere |
804 |
status.*?<br>\s+(?P<status>\S+)
|
|
1
by Dennis Kaarsemaker
Initial checkin |
805 |
.*?
|
|
43
by Dennis Kaarsemaker
More fixes everywhere |
806 |
resolution.*?<br>\s+(?P<resolution>\S+)
|
|
1
by Dennis Kaarsemaker
Initial checkin |
807 |
.*?
|
808 |
""", re.VERBOSE | re.DOTALL | re.I) |
|
809 |
class Sourceforge(IBugtracker): |
|
810 |
_sf_url = 'http://sf.net/support/tracker.php?aid=%d' |
|
811 |
def get_bug(self, id): |
|
812 |
url = self._sf_url % id |
|
813 |
try: |
|
814 |
bugdata = utils.web.getUrl(url) |
|
815 |
except Exception, e: |
|
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
816 |
s = 'Could not parse data returned by %s: %s (%s)' % (self.description, e, url) |
|
1
by Dennis Kaarsemaker
Initial checkin |
817 |
raise BugtrackerError, s |
818 |
try: |
|
819 |
reo = sfre.search(bugdata) |
|
820 |
status = reo.group('status') |
|
821 |
resolution = reo.group('resolution') |
|
822 |
if not (resolution.lower() == 'none'): |
|
823 |
status += ' ' + resolution |
|
|
35
by Dennis Kaarsemaker
adkfasdyfb |
824 |
return [(id, None, reo.group('title'), "Pri: %s" % reo.group('priority'), status, reo.group('assignee'),self._sf_url % id)] |
|
1
by Dennis Kaarsemaker
Initial checkin |
825 |
except: |
|
40
by Dennis Kaarsemaker
Made bugtracker plugin more usable |
826 |
raise BugNotFoundError |
|
1
by Dennis Kaarsemaker
Initial checkin |
827 |
|
828 |
# Introspection is quite cool
|
|
829 |
defined_bugtrackers = {} |
|
830 |
v = vars() |
|
831 |
for k in v.keys(): |
|
832 |
if type(v[k]) == type(IBugtracker) and issubclass(v[k], IBugtracker) and not (v[k] == IBugtracker): |
|
833 |
defined_bugtrackers[k.lower()] = v[k] |
|
834 |
||
835 |
registerBugtracker('mozilla', 'http://bugzilla.mozilla.org', 'Mozilla', 'bugzilla') |
|
|
133
by Terence Simpson
Resync all running ubottu code to bzr branch, they should now be in sync again |
836 |
#registerBugtracker('ubuntu', 'http://bugzilla.ubuntu.com', 'Ubuntu', 'bugzilla')
|
|
93
by Terence Simpson
Make sure 'ubuntu ###' looks at launchpad for the bug, not bugzilla.ubuntu.com |
837 |
registerBugtracker('ubuntu', 'https://launchpad.net', 'Ubuntu', 'launchpad') |
|
1
by Dennis Kaarsemaker
Initial checkin |
838 |
registerBugtracker('gnome', 'http://bugzilla.gnome.org', 'Gnome', 'bugzilla') |
839 |
registerBugtracker('gnome2', 'http://bugs.gnome.org', 'Gnome', 'bugzilla') |
|
840 |
registerBugtracker('kde', 'http://bugs.kde.org', 'KDE', 'bugzilla') |
|
841 |
registerBugtracker('ximian', 'http://bugzilla.ximian.com', 'Ximian', 'bugzilla') |
|
842 |
registerBugtracker('freedesktop', 'http://bugzilla.freedesktop.org', 'Freedesktop', 'bugzilla') |
|
843 |
registerBugtracker('freedesktop2', 'http://bugs.freedesktop.org', 'Freedesktop', 'bugzilla') |
|
844 |
registerBugtracker('openoffice', 'http://openoffice.org/issues', 'OpenOffice.org', 'issuezilla') |
|
|
51
by Dennis Kaarsemaker
Misc fixes |
845 |
registerBugtracker('launchpad', 'https://launchpad.net', 'Launchpad', 'launchpad') |
846 |
registerBugtracker('lp', 'https://launchpad.net', 'Launchpad', 'launchpad') |
|
847 |
registerBugtracker('malone', 'https://launchpad.net', 'Launchpad', 'launchpad') |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
848 |
registerBugtracker('debian', 'http://bugs.debian.org', 'Debian', 'debbugs') |
|
43
by Dennis Kaarsemaker
More fixes everywhere |
849 |
registerBugtracker('trac', 'http://trac.edgewall.org/ticket', 'Trac', 'trac') |
|
1
by Dennis Kaarsemaker
Initial checkin |
850 |
registerBugtracker('django', 'http://code.djangoproject.com/ticket', 'Django', 'trac') |
|
41
by Dennis Kaarsemaker
Bugtracker now is much more usable and contains documentation. Backwards |
851 |
registerBugtracker('cups', 'http://www.cups.org/str.php', 'CUPS', 'str') |
852 |
registerBugtracker('gnewsense', 'http://bugs.gnewsense.org/Bugs', 'gNewSense', 'wikiforms') |
|
|
1
by Dennis Kaarsemaker
Initial checkin |
853 |
registerBugtracker('supybot', 'http://sourceforge.net/tracker/?group_id=58965&atid=489447', 'Supybot', 'sourceforge') |
|
95
by Terence Simpson
Big-Old-Update Edition |
854 |
registerBugtracker('mantis', "http://www.mantisbt.org/bugs", "Mantis", 'mantis') |
|
41
by Dennis Kaarsemaker
Bugtracker now is much more usable and contains documentation. Backwards |
855 |
# Don't delete this one
|
|
1
by Dennis Kaarsemaker
Initial checkin |
856 |
registerBugtracker('sourceforge', 'http://sourceforge.net/tracker/', 'Sourceforge', 'sourceforge') |
857 |
Class = Bugtracker |