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