Support regexes in channel config yaml
With this change, the channel config yaml file can now be configured to support regular expressions. Any value in any section may be prefixed with `^` to denote that it is to be treated as a regular expression [1]. Start and end ^anchors$ are implicit (so add `.*` if needed). For example, given the following paragraph in the channel config yaml: openstack-foo: events: - patchset-created - change-merged projects: - openstack/foo - ^openstack/foo-.* - openstack/oslo.foo branches: - master - ^stable/(newton|ocata|pike) ...messages will be posted to #openstack-foo for events coming in from project openstack/foo, openstack/foo-one, openstack/foo-bar, etc.; on branches master, stable/newton, stable/ocata, or stable/pike. Behavior is unchanged for values not prefixed with `^`. [1] This paradigm cribbed from gerrit's search functionality: https://review.openstack.org/Documentation/user-search.html#path Change-Id: I97cb8faa72600bd1bd9792bb6bb59a3b652ec389
This commit is contained in:
parent
fc4041f6a3
commit
981dfa50fa
|
@ -19,36 +19,41 @@ when starting the bot. It should look like::
|
|||
port=6667
|
||||
force_ssl=True or False (Defaults to False)
|
||||
server_password=SERVERPASS
|
||||
channel_config=/path/to/yaml/config
|
||||
|
||||
channel_config=/path/to/yaml/config (See below)
|
||||
|
||||
[gerrit]
|
||||
user=gerrit2
|
||||
key=/path/to/id_rsa
|
||||
host=review.example.com
|
||||
port=29418
|
||||
|
||||
The second configures the IRC channels and the events and projects that each
|
||||
channel is interested in. This config file is written in yaml and should look
|
||||
like::
|
||||
The second, referenced by ``[ircbot]channel_config`` in the above, configures
|
||||
the IRC channels and the events and projects that each channel is interested
|
||||
in. This config file is written in yaml and should look like::
|
||||
|
||||
example-channel1:
|
||||
events:
|
||||
- patchset-created
|
||||
- change-merged
|
||||
- ^x-(crvw|vrif)-(plus|minus)-2$
|
||||
projects:
|
||||
- example/project1
|
||||
- example/project2
|
||||
branches:
|
||||
- master
|
||||
- development
|
||||
|
||||
example-channel2:
|
||||
events:
|
||||
- change-merged
|
||||
projects:
|
||||
- example/project3
|
||||
- example/project4
|
||||
- ^example/project[34]$
|
||||
- ^example/interesting-
|
||||
branches:
|
||||
- master
|
||||
- ^stable/(newton|ocata|pike)$
|
||||
|
||||
Denote regular expressions using the prefix ``^``.
|
||||
|
||||
Running
|
||||
=======
|
||||
|
|
|
@ -49,8 +49,10 @@ openstack-dev:
|
|||
projects:
|
||||
- openstack/nova
|
||||
- openstack/swift
|
||||
- ^openstack/fuel-.*
|
||||
branches:
|
||||
- master
|
||||
- ^stable/(newton|ocata|pike)
|
||||
"""
|
||||
|
||||
import ConfigParser
|
||||
|
@ -218,8 +220,8 @@ class Gerrit(threading.Thread):
|
|||
|
||||
for approval in data.get('approvals', []):
|
||||
if (approval['type'] == 'VRIF' and approval['value'] == '-2'
|
||||
and channel in self.channel_config.events.get(
|
||||
'x-vrif-minus-2', set())):
|
||||
and channel in self._channels_for('events',
|
||||
'x-vrif-minus-2')):
|
||||
msg = 'Verification of a change to %s failed: %s %s' % (
|
||||
data['change']['project'],
|
||||
data['change']['subject'],
|
||||
|
@ -228,8 +230,8 @@ class Gerrit(threading.Thread):
|
|||
self.ircbot.send(channel, msg)
|
||||
|
||||
if (approval['type'] == 'VRIF' and approval['value'] == '2'
|
||||
and channel in self.channel_config.events.get(
|
||||
'x-vrif-plus-2', set())):
|
||||
and channel in self._channels_for('events',
|
||||
'x-vrif-plus-2')):
|
||||
msg = 'Verification of a change to %s succeeded: %s %s' % (
|
||||
data['change']['project'],
|
||||
data['change']['subject'],
|
||||
|
@ -238,8 +240,8 @@ class Gerrit(threading.Thread):
|
|||
self.ircbot.send(channel, msg)
|
||||
|
||||
if (approval['type'] == 'CRVW' and approval['value'] == '-2'
|
||||
and channel in self.channel_config.events.get(
|
||||
'x-crvw-minus-2', set())):
|
||||
and channel in self._channels_for('events',
|
||||
'x-crvw-minus-2')):
|
||||
msg = 'A change to %s has been rejected: %s %s' % (
|
||||
data['change']['project'],
|
||||
data['change']['subject'],
|
||||
|
@ -248,8 +250,8 @@ class Gerrit(threading.Thread):
|
|||
self.ircbot.send(channel, msg)
|
||||
|
||||
if (approval['type'] == 'CRVW' and approval['value'] == '2'
|
||||
and channel in self.channel_config.events.get(
|
||||
'x-crvw-plus-2', set())):
|
||||
and channel in self._channels_for('events',
|
||||
'x-crvw-plus-2')):
|
||||
msg = 'A change to %s has been approved: %s %s' % (
|
||||
data['change']['project'],
|
||||
data['change']['subject'],
|
||||
|
@ -266,17 +268,63 @@ class Gerrit(threading.Thread):
|
|||
self.log.info('Compiled Message %s: %s' % (channel, msg))
|
||||
self.ircbot.send(channel, msg)
|
||||
|
||||
def _channels_for(self, section, datakey):
|
||||
"""Get a set of channel names for a given data value.
|
||||
|
||||
Finds all the channels that care about the specified datakey for a
|
||||
given channel_config section. If the channel config key starts with
|
||||
'^', datakey is matched by regex; otherwise it is matched by string
|
||||
equality. For example, given input data:
|
||||
|
||||
openstack-dev:
|
||||
projects:
|
||||
- openstack/foo-bar
|
||||
|
||||
openstack-infra:
|
||||
projects:
|
||||
- ^openstack/foo-.*$
|
||||
|
||||
openstack-sdks:
|
||||
projects:
|
||||
- openstack/foo
|
||||
|
||||
...the call:
|
||||
|
||||
_channels_for('projects', 'openstack/foo-bar')
|
||||
|
||||
...will return the set:
|
||||
|
||||
{'#openstack-dev', '#openstack-infra'}
|
||||
|
||||
:param str section: The channel_config section to inspect ('projects',
|
||||
'events', or 'branches')
|
||||
:param str datakey: The key into the section, from the source data.
|
||||
E.g. for section 'projects', the key would be the
|
||||
project name (data['change']['project']).
|
||||
"""
|
||||
ret = set()
|
||||
for key, chanset in getattr(self.channel_config, section, {}).items():
|
||||
for channel in chanset or set():
|
||||
if key.startswith('^'):
|
||||
if re.search(key, datakey):
|
||||
ret.add(channel)
|
||||
else:
|
||||
if key == datakey:
|
||||
ret.add(channel)
|
||||
return ret
|
||||
|
||||
def _read(self, data):
|
||||
try:
|
||||
if data['type'] == 'ref-updated':
|
||||
channel_set = self.channel_config.events.get('ref-updated')
|
||||
# We only consider event (not project/branch) filters for these.
|
||||
event_only_types = ('ref-updated',)
|
||||
if data['type'] in event_only_types:
|
||||
channel_set = self._channels_for('events', data['type'])
|
||||
else:
|
||||
channel_set = (self.channel_config.projects.get(
|
||||
data['change']['project'], set()) &
|
||||
self.channel_config.events.get(
|
||||
data['type'], set()) &
|
||||
self.channel_config.branches.get(
|
||||
data['change']['branch'], set()))
|
||||
channel_set = (
|
||||
self._channels_for('projects', data['change']['project']) &
|
||||
self._channels_for('events', data['type']) &
|
||||
self._channels_for('branches', data['change']['branch'])
|
||||
)
|
||||
except KeyError:
|
||||
# The data we care about was not present, no channels want
|
||||
# this event.
|
||||
|
|
|
@ -23,10 +23,7 @@ openstack-dev:
|
|||
events:
|
||||
- patchset-created
|
||||
- change-merged
|
||||
- x-vrif-minus-2
|
||||
- x-vrif-plus-2
|
||||
- x-crvw-minus-2
|
||||
- x-crvw-plus-2
|
||||
- ^x-(crvw|vrif)-(plus|minus)-2$
|
||||
projects:
|
||||
- openstack/nova
|
||||
- openstack/swift
|
||||
|
@ -39,14 +36,9 @@ openstack-infra:
|
|||
- change-merged
|
||||
- comment-added
|
||||
- ref-updated
|
||||
- x-vrif-minus-2
|
||||
- x-vrif-plus-2
|
||||
- x-crvw-minus-2
|
||||
- x-crvw-plus-2
|
||||
- ^x-(crvw|vrif)-(plus|minus)-2$
|
||||
projects:
|
||||
- openstack/gerritbot
|
||||
- openstack/nova
|
||||
- openstack/swift
|
||||
- ^openstack/
|
||||
branches:
|
||||
- master
|
||||
- stable/queens
|
||||
|
@ -80,21 +72,17 @@ class ChannelConfigTestCase(testtools.TestCase):
|
|||
'comment-added': {'#openstack-infra'},
|
||||
'patchset-created': expected_channels,
|
||||
'ref-updated': {'#openstack-infra'},
|
||||
'x-crvw-minus-2': expected_channels,
|
||||
'x-crvw-plus-2': expected_channels,
|
||||
'x-vrif-minus-2': expected_channels,
|
||||
'x-vrif-plus-2': expected_channels,
|
||||
'^x-(crvw|vrif)-(plus|minus)-2$': expected_channels,
|
||||
},
|
||||
channel_config.events)
|
||||
|
||||
def test_projects(self):
|
||||
channel_config = bot.ChannelConfig(yaml.load(CHANNEL_CONFIG_YAML))
|
||||
expected_channels = {'#openstack-dev', '#openstack-infra'}
|
||||
self.assertEqual(
|
||||
{
|
||||
'openstack/gerritbot': {'#openstack-infra'},
|
||||
'openstack/nova': expected_channels,
|
||||
'openstack/swift': expected_channels,
|
||||
'^openstack/': {'#openstack-infra'},
|
||||
'openstack/nova': {'#openstack-dev'},
|
||||
'openstack/swift': {'#openstack-dev'},
|
||||
},
|
||||
channel_config.projects)
|
||||
|
||||
|
|
Loading…
Reference in New Issue