Redmine: Add announces support.

master
Valentin Lorentz 2012-12-15 22:16:37 +01:00
parent 8a58fd79ff
commit 73aa646f3d
3 changed files with 94 additions and 3 deletions

View File

@ -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:

View File

@ -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)

View File

@ -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