Redmine: Add announces support.
parent
8a58fd79ff
commit
73aa646f3d
|
@ -68,5 +68,15 @@ conf.registerChannelValue(Redmine.format, 'issue',
|
||||||
'\x02%(author__name)s\x02 (%(author__id)i) on \x02%(created_on)s\x02, '
|
'\x02%(author__name)s\x02 (%(author__id)i) on \x02%(created_on)s\x02, '
|
||||||
'last updated on \x02%(updated_on)s',
|
'last updated on \x02%(updated_on)s',
|
||||||
_("""Format of issues displayed by @issue.""")))
|
_("""Format of issues displayed by @issue.""")))
|
||||||
|
conf.registerGroup(Redmine.format, 'announces')
|
||||||
|
conf.registerChannelValue(Redmine.format.announces, 'issue',
|
||||||
|
registry.String('Updated issue: \x02#%(id)i (%(status__name)s)\x02: '
|
||||||
|
'\x02%(subject)s\x02 in \x02%(project__name)s\x02 (%(project__id)i).',
|
||||||
|
_("""Format of issues displayed by @issue.""")))
|
||||||
|
|
||||||
|
conf.registerGroup(Redmine, 'announce')
|
||||||
|
conf.registerChannelValue(Redmine.announce, 'sites',
|
||||||
|
registry.SpaceSeparatedListOfStrings([],
|
||||||
|
_("""List of sites announced on this channel.""")))
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
||||||
|
|
|
@ -28,12 +28,15 @@
|
||||||
|
|
||||||
###
|
###
|
||||||
|
|
||||||
|
import sys
|
||||||
import json
|
import json
|
||||||
|
import time
|
||||||
|
|
||||||
import supybot.conf as conf
|
import supybot.conf as conf
|
||||||
import supybot.utils as utils
|
import supybot.utils as utils
|
||||||
from supybot.commands import *
|
from supybot.commands import *
|
||||||
import supybot.plugins as plugins
|
import supybot.plugins as plugins
|
||||||
|
import supybot.ircmsgs as ircmsgs
|
||||||
import supybot.ircutils as ircutils
|
import supybot.ircutils as ircutils
|
||||||
import supybot.callbacks as callbacks
|
import supybot.callbacks as callbacks
|
||||||
from supybot.i18n import PluginInternationalization, internationalizeDocstring
|
from supybot.i18n import PluginInternationalization, internationalizeDocstring
|
||||||
|
@ -149,6 +152,47 @@ class Redmine(callbacks.Plugin):
|
||||||
This should describe *how* to use this plugin."""
|
This should describe *how* to use this plugin."""
|
||||||
threaded = True
|
threaded = True
|
||||||
|
|
||||||
|
_last_fetch = {} # {site: (time, data)}
|
||||||
|
def __call__(self, irc, msg):
|
||||||
|
super(Redmine, self).__call__(irc, msg)
|
||||||
|
with self.registryValue('sites', value=False).editable() as sites:
|
||||||
|
assert isinstance(sites, dict), repr(sites)
|
||||||
|
for site_name, site in sites.items():
|
||||||
|
if 'interval' not in site:
|
||||||
|
site['interval'] = 60
|
||||||
|
if site_name in self._last_fetch:
|
||||||
|
last_time, last_data = self._last_fetch[site_name]
|
||||||
|
if last_time>time.time()-site['interval']:
|
||||||
|
continue
|
||||||
|
data = fetch(site, 'issues', sort='updated_on:desc')
|
||||||
|
self._last_fetch[site_name] = (time.time(), data)
|
||||||
|
if 'last_time' not in locals():
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
last_update = last_data['issues'][0]['updated_on']
|
||||||
|
except IndexError:
|
||||||
|
# There was no issue submitted before
|
||||||
|
last_update = ''
|
||||||
|
|
||||||
|
announces = []
|
||||||
|
for issue in data['issues']:
|
||||||
|
if issue['updated_on'] <= last_update:
|
||||||
|
break
|
||||||
|
announces.append(issue)
|
||||||
|
for channel in irc.state.channels:
|
||||||
|
if site_name in self.registryValue('announce.sites',
|
||||||
|
channel):
|
||||||
|
format_ = self.registryValue('format.announces.issue',
|
||||||
|
channel)
|
||||||
|
for issue in announces:
|
||||||
|
s = format_ % flatten_subdicts(issue)
|
||||||
|
if sys.version_info[0] < 3:
|
||||||
|
s = s.encode('utf8', errors='replace')
|
||||||
|
msg = ircmsgs.privmsg(channel, s)
|
||||||
|
irc.sendMsg(msg)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class site(callbacks.Commands):
|
class site(callbacks.Commands):
|
||||||
conf = conf.supybot.plugins.Redmine
|
conf = conf.supybot.plugins.Redmine
|
||||||
@internationalizeDocstring
|
@internationalizeDocstring
|
||||||
|
@ -158,7 +202,7 @@ class Redmine(callbacks.Plugin):
|
||||||
Add a site to the list of known redmine sites."""
|
Add a site to the list of known redmine sites."""
|
||||||
if not url.endswith('/'):
|
if not url.endswith('/'):
|
||||||
url += '/'
|
url += '/'
|
||||||
if name == '':
|
if not name:
|
||||||
irc.error(_('Invalid site name.'), Raise=True)
|
irc.error(_('Invalid site name.'), Raise=True)
|
||||||
if name in self.conf.sites():
|
if name in self.conf.sites():
|
||||||
irc.error(_('This site name is already registered.'), Raise=True)
|
irc.error(_('This site name is already registered.'), Raise=True)
|
||||||
|
|
|
@ -28,6 +28,9 @@
|
||||||
|
|
||||||
###
|
###
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
import supybot.conf as conf
|
||||||
from supybot.test import *
|
from supybot.test import *
|
||||||
|
|
||||||
def init(f):
|
def init(f):
|
||||||
|
@ -39,8 +42,8 @@ def init(f):
|
||||||
self.assertNotError('site remove lqdn')
|
self.assertNotError('site remove lqdn')
|
||||||
return newf
|
return newf
|
||||||
|
|
||||||
class RedmineTestCase(PluginTestCase):
|
class RedmineTestCase(ChannelPluginTestCase):
|
||||||
plugins = ('Redmine',)
|
plugins = ('Redmine', 'Config', 'Utilities')
|
||||||
|
|
||||||
def testSite(self):
|
def testSite(self):
|
||||||
self.assertRegexp('site list', 'No registered')
|
self.assertRegexp('site list', 'No registered')
|
||||||
|
@ -66,6 +69,40 @@ class RedmineTestCase(PluginTestCase):
|
||||||
self.assertNotError('issue lqdn 130')
|
self.assertNotError('issue lqdn 130')
|
||||||
self.assertResponse('issue lqdn 999999', 'Error: Issue not found.')
|
self.assertResponse('issue lqdn 999999', 'Error: Issue not found.')
|
||||||
|
|
||||||
|
@init
|
||||||
|
def testAnnounce(self):
|
||||||
|
pl = self.irc.getCallback('Redmine')
|
||||||
|
|
||||||
|
self.assertNotError('ping')
|
||||||
|
self.assertNotError('config plugins.Redmine.announce.sites lqdn')
|
||||||
|
with conf.supybot.plugins.Redmine.sites.editable() as sites:
|
||||||
|
sites['lqdn']['interval'] = 1
|
||||||
|
|
||||||
|
# Make sure it does not update everytime a message is received
|
||||||
|
self.assertNotError('ping')
|
||||||
|
self.assertIs(self.irc.takeMsg(), None)
|
||||||
|
last_fetch = pl._last_fetch.copy()
|
||||||
|
self.assertNotError('ping')
|
||||||
|
self.assertEqual(last_fetch, pl._last_fetch)
|
||||||
|
self.assertIs(self.irc.takeMsg(), None)
|
||||||
|
|
||||||
|
# Make sure it updates after the interval is finished, but there is
|
||||||
|
# nothing new
|
||||||
|
time.sleep(1.1)
|
||||||
|
self.assertNotError('ping')
|
||||||
|
self.assertNotEqual(last_fetch, pl._last_fetch)
|
||||||
|
self.assertIs(self.irc.takeMsg(), None)
|
||||||
|
|
||||||
|
# Let's cheat a little and "olderize" the latest issue.
|
||||||
|
pl._last_fetch['lqdn'][1]['issues'][0]['updated_on'] = \
|
||||||
|
'2012/12/09 20:37:27 +0100'
|
||||||
|
time.sleep(1.1)
|
||||||
|
self.assertNotError('ping')
|
||||||
|
self.assertNotEqual(last_fetch, pl._last_fetch)
|
||||||
|
m = self.irc.takeMsg()
|
||||||
|
self.assertIsNot(m, None)
|
||||||
|
|
||||||
|
|
||||||
if not network:
|
if not network:
|
||||||
del RedmineTestCase
|
del RedmineTestCase
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue