Merge "Filter events on event connection"
This commit is contained in:
commit
ba7b146fd1
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
fixes:
|
||||
- |
|
||||
Fixed a bug where multiple connections of the same type would not filter
|
||||
trigger events coming from the wrong connection.
|
|
@ -30,8 +30,10 @@
|
|||
trigger:
|
||||
another_gerrit:
|
||||
- event: patchset-created
|
||||
branch: 'master'
|
||||
review_gerrit:
|
||||
- event: patchset-created
|
||||
branch: 'develop'
|
||||
success:
|
||||
review_gerrit:
|
||||
Verified: 1
|
||||
|
|
|
@ -493,6 +493,16 @@ class TestMultipleGerrits(ZuulTestCase):
|
|||
def test_multiple_project_separate_gerrits_common_pipeline(self):
|
||||
self.executor_server.hold_jobs_in_build = True
|
||||
|
||||
self.create_branch('org/project2', 'develop')
|
||||
self.fake_another_gerrit.addEvent(
|
||||
self.fake_another_gerrit.getFakeBranchCreatedEvent(
|
||||
'org/project2', 'develop'))
|
||||
|
||||
self.fake_another_gerrit.addEvent(
|
||||
self.fake_review_gerrit.getFakeBranchCreatedEvent(
|
||||
'org/project2', 'develop'))
|
||||
self.waitUntilSettled()
|
||||
|
||||
A = self.fake_another_gerrit.addFakeChange(
|
||||
'org/project2', 'master', 'A')
|
||||
self.fake_another_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
|
||||
|
@ -512,7 +522,7 @@ class TestMultipleGerrits(ZuulTestCase):
|
|||
self.fake_review_gerrit.change_number = 50
|
||||
|
||||
B = self.fake_review_gerrit.addFakeChange(
|
||||
'org/project2', 'master', 'B')
|
||||
'org/project2', 'develop', 'B')
|
||||
self.fake_review_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
|
||||
|
||||
self.waitUntilSettled()
|
||||
|
@ -528,6 +538,25 @@ class TestMultipleGerrits(ZuulTestCase):
|
|||
pipeline='common_check'),
|
||||
])
|
||||
|
||||
# NOTE(avass): This last change should not trigger any pipelines since
|
||||
# common_check is configured to only run on master for another_gerrit
|
||||
C = self.fake_another_gerrit.addFakeChange(
|
||||
'org/project2', 'develop', 'C')
|
||||
self.fake_another_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
|
||||
|
||||
self.waitUntilSettled()
|
||||
|
||||
self.assertBuilds([
|
||||
dict(name='project-test2',
|
||||
changes='1,1',
|
||||
project='org/project2',
|
||||
pipeline='common_check'),
|
||||
dict(name='project-test1',
|
||||
changes='51,1',
|
||||
project='org/project2',
|
||||
pipeline='common_check'),
|
||||
])
|
||||
|
||||
self.executor_server.hold_jobs_in_build = False
|
||||
self.executor_server.release()
|
||||
self.waitUntilSettled()
|
||||
|
|
|
@ -1368,15 +1368,16 @@ class PipelineParser(object):
|
|||
manager.ref_filters.extend(
|
||||
source.getRejectFilters(reject_config))
|
||||
|
||||
for trigger_name, trigger_config in conf.get('trigger').items():
|
||||
for connection_name, trigger_config in conf.get('trigger').items():
|
||||
if self.pcontext.tenant.allowed_triggers is not None and \
|
||||
trigger_name not in self.pcontext.tenant.allowed_triggers:
|
||||
raise UnknownConnection(trigger_name)
|
||||
connection_name not in self.pcontext.tenant.allowed_triggers:
|
||||
raise UnknownConnection(connection_name)
|
||||
trigger = self.pcontext.connections.getTrigger(
|
||||
trigger_name, trigger_config)
|
||||
connection_name, trigger_config)
|
||||
pipeline.triggers.append(trigger)
|
||||
manager.event_filters.extend(
|
||||
trigger.getEventFilters(conf['trigger'][trigger_name]))
|
||||
trigger.getEventFilters(connection_name,
|
||||
conf['trigger'][connection_name]))
|
||||
|
||||
# Pipelines don't get frozen
|
||||
return pipeline
|
||||
|
|
|
@ -179,6 +179,7 @@ class GerritEventConnector(threading.Thread):
|
|||
time.sleep(max((timestamp + self.delay) - now, 0.0))
|
||||
event = GerritTriggerEvent()
|
||||
event.timestamp = timestamp
|
||||
event.connection_name = self.connection.connection_name
|
||||
|
||||
# Gerrit events don't have an event id that could be used to globally
|
||||
# identify this event in the system so we have to generate one.
|
||||
|
|
|
@ -295,12 +295,12 @@ class GerritApprovalFilter(object):
|
|||
|
||||
|
||||
class GerritEventFilter(EventFilter, GerritApprovalFilter):
|
||||
def __init__(self, trigger, types=[], branches=[], refs=[],
|
||||
event_approvals={}, comments=[], emails=[], usernames=[],
|
||||
required_approvals=[], reject_approvals=[], uuid=None,
|
||||
scheme=None, ignore_deletes=True):
|
||||
def __init__(self, connection_name, trigger, types=[], branches=[],
|
||||
refs=[], event_approvals={}, comments=[], emails=[],
|
||||
usernames=[], required_approvals=[], reject_approvals=[],
|
||||
uuid=None, scheme=None, ignore_deletes=True):
|
||||
|
||||
EventFilter.__init__(self, trigger)
|
||||
EventFilter.__init__(self, connection_name, trigger)
|
||||
|
||||
GerritApprovalFilter.__init__(self,
|
||||
required_approvals=required_approvals,
|
||||
|
@ -325,6 +325,7 @@ class GerritEventFilter(EventFilter, GerritApprovalFilter):
|
|||
|
||||
def __repr__(self):
|
||||
ret = '<GerritEventFilter'
|
||||
ret += ' connection: %s' % self.connection_name
|
||||
|
||||
if self._types:
|
||||
ret += ' types: %s' % ', '.join(self._types)
|
||||
|
@ -358,6 +359,9 @@ class GerritEventFilter(EventFilter, GerritApprovalFilter):
|
|||
return ret
|
||||
|
||||
def matches(self, event, change):
|
||||
if not super().matches(event, change):
|
||||
return False
|
||||
|
||||
# event types are ORed
|
||||
matches_type = False
|
||||
for etype in self.types:
|
||||
|
|
|
@ -23,7 +23,7 @@ class GerritTrigger(BaseTrigger):
|
|||
name = 'gerrit'
|
||||
log = logging.getLogger("zuul.GerritTrigger")
|
||||
|
||||
def getEventFilters(self, trigger_conf):
|
||||
def getEventFilters(self, connection_name, trigger_conf):
|
||||
efilters = []
|
||||
for trigger in to_list(trigger_conf):
|
||||
approvals = {}
|
||||
|
@ -42,6 +42,7 @@ class GerritTrigger(BaseTrigger):
|
|||
usernames = to_list(trigger.get('username_filter'))
|
||||
ignore_deletes = trigger.get('ignore-deletes', True)
|
||||
f = GerritEventFilter(
|
||||
connection_name=connection_name,
|
||||
trigger=self,
|
||||
types=to_list(trigger['event']),
|
||||
branches=to_list(trigger.get('branch')),
|
||||
|
|
|
@ -137,6 +137,7 @@ class GitConnection(BaseConnection):
|
|||
|
||||
def watcherCallback(self, data):
|
||||
event = GitTriggerEvent()
|
||||
event.connection_name = self.connection_name
|
||||
event.type = 'ref-updated'
|
||||
event.timestamp = time.time()
|
||||
event.project_hostname = self.canonical_hostname
|
||||
|
|
|
@ -40,10 +40,10 @@ class GitTriggerEvent(TriggerEvent):
|
|||
|
||||
|
||||
class GitEventFilter(EventFilter):
|
||||
def __init__(self, trigger, types=None, refs=None,
|
||||
def __init__(self, connection_name, trigger, types=None, refs=None,
|
||||
ignore_deletes=True):
|
||||
|
||||
super().__init__(trigger)
|
||||
super().__init__(connection_name, trigger)
|
||||
|
||||
self._refs = refs
|
||||
self.types = types if types is not None else []
|
||||
|
@ -53,6 +53,7 @@ class GitEventFilter(EventFilter):
|
|||
|
||||
def __repr__(self):
|
||||
ret = '<GitEventFilter'
|
||||
ret += ' connection: %s' % self.connection_name
|
||||
|
||||
if self.types:
|
||||
ret += ' types: %s' % ', '.join(self.types)
|
||||
|
@ -65,6 +66,9 @@ class GitEventFilter(EventFilter):
|
|||
return ret
|
||||
|
||||
def matches(self, event, change):
|
||||
if not super().matches(event, change):
|
||||
return False
|
||||
|
||||
# event types are ORed
|
||||
matches_type = False
|
||||
for etype in self.types:
|
||||
|
|
|
@ -23,10 +23,11 @@ class GitTrigger(BaseTrigger):
|
|||
name = 'git'
|
||||
log = logging.getLogger("zuul.GitTrigger")
|
||||
|
||||
def getEventFilters(self, trigger_conf):
|
||||
def getEventFilters(self, connection_name, trigger_conf):
|
||||
efilters = []
|
||||
for trigger in to_list(trigger_conf):
|
||||
f = GitEventFilter(
|
||||
connection_name=connection_name,
|
||||
trigger=self,
|
||||
types=to_list(trigger['event']),
|
||||
refs=to_list(trigger.get('ref')),
|
||||
|
|
|
@ -406,6 +406,7 @@ class GithubEventProcessor(object):
|
|||
base_repo = self.body.get('repository')
|
||||
|
||||
event = GithubTriggerEvent()
|
||||
event.connection_name = self.connection.connection_name
|
||||
event.trigger_name = 'github'
|
||||
event.project_name = base_repo.get('full_name')
|
||||
event.type = 'push'
|
||||
|
@ -615,6 +616,7 @@ class GithubEventProcessor(object):
|
|||
|
||||
def _pull_request_to_event(self, pr_body):
|
||||
event = GithubTriggerEvent()
|
||||
event.connection_name = self.connection.connection_name
|
||||
event.trigger_name = 'github'
|
||||
|
||||
base = pr_body.get('base')
|
||||
|
|
|
@ -260,12 +260,12 @@ class GithubCommonFilter(object):
|
|||
|
||||
|
||||
class GithubEventFilter(EventFilter, GithubCommonFilter):
|
||||
def __init__(self, trigger, types=[], branches=[], refs=[],
|
||||
comments=[], actions=[], labels=[], unlabels=[],
|
||||
def __init__(self, connection_name, trigger, types=[], branches=[],
|
||||
refs=[], comments=[], actions=[], labels=[], unlabels=[],
|
||||
states=[], statuses=[], required_statuses=[],
|
||||
check_runs=[], ignore_deletes=True):
|
||||
|
||||
EventFilter.__init__(self, trigger)
|
||||
EventFilter.__init__(self, connection_name, trigger)
|
||||
|
||||
GithubCommonFilter.__init__(self, required_statuses=required_statuses)
|
||||
|
||||
|
@ -288,7 +288,7 @@ class GithubEventFilter(EventFilter, GithubCommonFilter):
|
|||
|
||||
def __repr__(self):
|
||||
ret = '<GithubEventFilter'
|
||||
|
||||
ret += ' connection: %s' % self.connection_name
|
||||
if self._types:
|
||||
ret += ' types: %s' % ', '.join(self._types)
|
||||
if self._branches:
|
||||
|
@ -318,6 +318,9 @@ class GithubEventFilter(EventFilter, GithubCommonFilter):
|
|||
return ret
|
||||
|
||||
def matches(self, event, change):
|
||||
if not super().matches(event, change):
|
||||
return False
|
||||
|
||||
# event types are ORed
|
||||
matches_type = False
|
||||
for etype in self.types:
|
||||
|
|
|
@ -23,10 +23,11 @@ class GithubTrigger(BaseTrigger):
|
|||
name = 'github'
|
||||
log = logging.getLogger("zuul.trigger.GithubTrigger")
|
||||
|
||||
def getEventFilters(self, trigger_config):
|
||||
def getEventFilters(self, connection_name, trigger_config):
|
||||
efilters = []
|
||||
for trigger in to_list(trigger_config):
|
||||
f = GithubEventFilter(
|
||||
connection_name=connection_name,
|
||||
trigger=self,
|
||||
types=to_list(trigger['event']),
|
||||
actions=to_list(trigger.get('action')),
|
||||
|
|
|
@ -86,6 +86,7 @@ class GitlabEventConnector(threading.Thread):
|
|||
|
||||
def _event_base(self, body):
|
||||
event = GitlabTriggerEvent()
|
||||
event.connection_name = self.connection.connection_name
|
||||
attrs = body.get('object_attributes')
|
||||
if attrs:
|
||||
event.updated_at = int(dateutil.parser.parse(
|
||||
|
|
|
@ -103,9 +103,9 @@ class GitlabTriggerEvent(TriggerEvent):
|
|||
|
||||
class GitlabEventFilter(EventFilter):
|
||||
def __init__(
|
||||
self, trigger, types=None, actions=None,
|
||||
self, connection_name, trigger, types=None, actions=None,
|
||||
comments=None, refs=None, labels=None, ignore_deletes=True):
|
||||
super(GitlabEventFilter, self).__init__(self)
|
||||
super().__init__(connection_name, trigger)
|
||||
self._types = types or []
|
||||
self.types = [re.compile(x) for x in self._types]
|
||||
self.actions = actions or []
|
||||
|
@ -118,6 +118,7 @@ class GitlabEventFilter(EventFilter):
|
|||
|
||||
def __repr__(self):
|
||||
ret = '<GitlabEventFilter'
|
||||
ret += ' connection: %s' % self.connection_name
|
||||
|
||||
if self._types:
|
||||
ret += ' types: %s' % ', '.join(self._types)
|
||||
|
@ -136,6 +137,9 @@ class GitlabEventFilter(EventFilter):
|
|||
return ret
|
||||
|
||||
def matches(self, event, change):
|
||||
if not super().matches(event, change):
|
||||
return False
|
||||
|
||||
matches_type = False
|
||||
for etype in self.types:
|
||||
if etype.match(event.type):
|
||||
|
|
|
@ -23,10 +23,11 @@ class GitlabTrigger(BaseTrigger):
|
|||
name = 'gitlab'
|
||||
log = logging.getLogger("zuul.trigger.GitlabTrigger")
|
||||
|
||||
def getEventFilters(self, trigger_config):
|
||||
def getEventFilters(self, connection_name, trigger_config):
|
||||
efilters = []
|
||||
for trigger in to_list(trigger_config):
|
||||
f = GitlabEventFilter(
|
||||
connection_name=connection_name,
|
||||
trigger=self,
|
||||
types=to_list(trigger['event']),
|
||||
actions=to_list(trigger.get('action')),
|
||||
|
|
|
@ -203,6 +203,7 @@ class PagureEventConnector(threading.Thread):
|
|||
|
||||
def _event_base(self, body, pull_data_field='pullrequest'):
|
||||
event = PagureTriggerEvent()
|
||||
event.connection_name = self.connection.connection_name
|
||||
|
||||
if pull_data_field in body['msg']:
|
||||
data = body['msg'][pull_data_field]
|
||||
|
|
|
@ -111,10 +111,11 @@ class PagureTriggerEvent(TriggerEvent):
|
|||
|
||||
|
||||
class PagureEventFilter(EventFilter):
|
||||
def __init__(self, trigger, types=[], refs=[], statuses=[],
|
||||
comments=[], actions=[], tags=[], ignore_deletes=True):
|
||||
def __init__(self, connection_name, trigger, types=[], refs=[],
|
||||
statuses=[], comments=[], actions=[], tags=[],
|
||||
ignore_deletes=True):
|
||||
|
||||
EventFilter.__init__(self, trigger)
|
||||
EventFilter.__init__(self, connection_name, trigger)
|
||||
|
||||
self._types = types
|
||||
self._refs = refs
|
||||
|
@ -129,6 +130,7 @@ class PagureEventFilter(EventFilter):
|
|||
|
||||
def __repr__(self):
|
||||
ret = '<PagureEventFilter'
|
||||
ret += ' connection: %s' % self.connection_name
|
||||
|
||||
if self._types:
|
||||
ret += ' types: %s' % ', '.join(self._types)
|
||||
|
@ -149,6 +151,9 @@ class PagureEventFilter(EventFilter):
|
|||
return ret
|
||||
|
||||
def matches(self, event, change):
|
||||
if not super().matches(event, change):
|
||||
return False
|
||||
|
||||
matches_type = False
|
||||
for etype in self.types:
|
||||
if etype.match(event.type):
|
||||
|
|
|
@ -23,10 +23,11 @@ class PagureTrigger(BaseTrigger):
|
|||
name = 'pagure'
|
||||
log = logging.getLogger("zuul.trigger.PagureTrigger")
|
||||
|
||||
def getEventFilters(self, trigger_config):
|
||||
def getEventFilters(self, connection_name, trigger_config):
|
||||
efilters = []
|
||||
for trigger in to_list(trigger_config):
|
||||
f = PagureEventFilter(
|
||||
connection_name=connection_name,
|
||||
trigger=self,
|
||||
types=to_list(trigger['event']),
|
||||
actions=to_list(trigger.get('action')),
|
||||
|
|
|
@ -18,8 +18,8 @@ from zuul.model import EventFilter, TriggerEvent
|
|||
|
||||
|
||||
class TimerEventFilter(EventFilter):
|
||||
def __init__(self, trigger, types=[], timespecs=[]):
|
||||
EventFilter.__init__(self, trigger)
|
||||
def __init__(self, connection_name, trigger, types=[], timespecs=[]):
|
||||
EventFilter.__init__(self, connection_name, trigger)
|
||||
|
||||
self._types = types
|
||||
self.types = [re.compile(x) for x in types]
|
||||
|
@ -27,6 +27,7 @@ class TimerEventFilter(EventFilter):
|
|||
|
||||
def __repr__(self):
|
||||
ret = '<TimerEventFilter'
|
||||
ret += ' connection: %s' % self.connection_name
|
||||
|
||||
if self._types:
|
||||
ret += ' types: %s' % ', '.join(self._types)
|
||||
|
|
|
@ -23,10 +23,11 @@ from zuul.driver.util import to_list
|
|||
class TimerTrigger(BaseTrigger):
|
||||
name = 'timer'
|
||||
|
||||
def getEventFilters(self, trigger_conf):
|
||||
def getEventFilters(self, connection_name, trigger_conf):
|
||||
efilters = []
|
||||
for trigger in to_list(trigger_conf):
|
||||
f = TimerEventFilter(trigger=self,
|
||||
f = TimerEventFilter(connection_name=connection_name,
|
||||
trigger=self,
|
||||
types=['timer'],
|
||||
timespecs=to_list(trigger['time']))
|
||||
|
||||
|
|
|
@ -87,6 +87,7 @@ class ZuulDriver(Driver, TriggerInterface):
|
|||
event = ZuulTriggerEvent()
|
||||
event.type = PROJECT_CHANGE_MERGED
|
||||
event.trigger_name = self.name
|
||||
event.connection_name = "zuul"
|
||||
event.project_hostname = change.project.canonical_hostname
|
||||
event.project_name = change.project.name
|
||||
event.change_number = change.number
|
||||
|
@ -123,6 +124,7 @@ class ZuulDriver(Driver, TriggerInterface):
|
|||
def _createParentChangeEnqueuedEvent(self, change, pipeline):
|
||||
event = ZuulTriggerEvent()
|
||||
event.type = PARENT_CHANGE_ENQUEUED
|
||||
event.connection_name = "zuul"
|
||||
event.trigger_name = self.name
|
||||
event.pipeline_name = pipeline.name
|
||||
event.project_hostname = change.project.canonical_hostname
|
||||
|
|
|
@ -18,8 +18,8 @@ from zuul.model import EventFilter, TriggerEvent
|
|||
|
||||
|
||||
class ZuulEventFilter(EventFilter):
|
||||
def __init__(self, trigger, types=[], pipelines=[]):
|
||||
EventFilter.__init__(self, trigger)
|
||||
def __init__(self, connection_name, trigger, types=[], pipelines=[]):
|
||||
EventFilter.__init__(self, connection_name, trigger)
|
||||
|
||||
self._types = types
|
||||
self._pipelines = pipelines
|
||||
|
@ -28,6 +28,7 @@ class ZuulEventFilter(EventFilter):
|
|||
|
||||
def __repr__(self):
|
||||
ret = '<ZuulEventFilter'
|
||||
ret += ' connection: %s' % self.connection_name
|
||||
|
||||
if self._types:
|
||||
ret += ' types: %s' % ', '.join(self._types)
|
||||
|
@ -38,6 +39,9 @@ class ZuulEventFilter(EventFilter):
|
|||
return ret
|
||||
|
||||
def matches(self, event, change):
|
||||
if not super().matches(event, change):
|
||||
return False
|
||||
|
||||
# event types are ORed
|
||||
matches_type = False
|
||||
for etype in self.types:
|
||||
|
|
|
@ -29,10 +29,11 @@ class ZuulTrigger(BaseTrigger):
|
|||
self._handle_parent_change_enqueued_events = False
|
||||
self._handle_project_change_merged_events = False
|
||||
|
||||
def getEventFilters(self, trigger_conf):
|
||||
def getEventFilters(self, connection_name, trigger_conf):
|
||||
efilters = []
|
||||
for trigger in to_list(trigger_conf):
|
||||
f = ZuulEventFilter(
|
||||
connection_name=connection_name,
|
||||
trigger=self,
|
||||
types=to_list(trigger['event']),
|
||||
pipelines=to_list(trigger.get('pipeline')),
|
||||
|
|
|
@ -3932,6 +3932,7 @@ class TriggerEvent(AbstractEvent):
|
|||
self.project_hostname = None
|
||||
self.project_name = None
|
||||
self.trigger_name = None
|
||||
self.connection_name = None
|
||||
# Representation of the user account that performed the event.
|
||||
self.account = None
|
||||
# patchset-created, comment-added, etc.
|
||||
|
@ -3966,6 +3967,7 @@ class TriggerEvent(AbstractEvent):
|
|||
"project_hostname": self.project_hostname,
|
||||
"project_name": self.project_name,
|
||||
"trigger_name": self.trigger_name,
|
||||
"connection_name": self.connection_name,
|
||||
"account": self.account,
|
||||
"change_number": self.change_number,
|
||||
"change_url": self.change_url,
|
||||
|
@ -3995,6 +3997,7 @@ class TriggerEvent(AbstractEvent):
|
|||
self.project_hostname = d["project_hostname"]
|
||||
self.project_name = d["project_name"]
|
||||
self.trigger_name = d["trigger_name"]
|
||||
self.connection_name = d["connection_name"]
|
||||
self.account = d["account"]
|
||||
self.change_number = d["change_number"]
|
||||
self.change_url = d["change_url"]
|
||||
|
@ -4059,12 +4062,18 @@ class BaseFilter(ConfigObject):
|
|||
|
||||
class EventFilter(BaseFilter):
|
||||
"""Allows a Pipeline to only respond to certain events."""
|
||||
def __init__(self, trigger):
|
||||
def __init__(self, connection_name, trigger):
|
||||
super(EventFilter, self).__init__()
|
||||
self.connection_name = connection_name
|
||||
self.trigger = trigger
|
||||
|
||||
def matches(self, event, ref):
|
||||
# TODO(jeblair): consider removing ref argument
|
||||
|
||||
# Event came from wrong connection
|
||||
if self.connection_name != event.connection_name:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ class BaseTrigger(object, metaclass=abc.ABCMeta):
|
|||
self.config = config or {}
|
||||
|
||||
@abc.abstractmethod
|
||||
def getEventFilters(self, trigger_conf):
|
||||
def getEventFilters(self, connection_name, trigger_conf):
|
||||
"""Return a list of EventFilter's for the scheduler to match against.
|
||||
"""
|
||||
|
||||
|
|
Loading…
Reference in New Issue