Merge "Don't store change_queue in QueueItem"
diff --git a/doc/source/zuul.rst b/doc/source/zuul.rst
index 1a94660..f71df22 100644
--- a/doc/source/zuul.rst
+++ b/doc/source/zuul.rst
@@ -333,6 +333,13 @@
     greedy matchers and to escapes dots!
     Example: ``email_filter: ^.*?@example\.org$``.
 
+    *username_filter*
+    This is used for any event.  It takes a regex applied on the performer
+    username, i.e. Gerrit account name.  If you want to specify several
+    username filters, you must use a YAML list.  Make sure to use non greedy
+    matchers and to escapes dots!
+    Example: ``username_filter: ^jenkins$``.
+
     *comment_filter*
     This is only used for ``comment-added`` events.  It accepts a list of
     regexes that are searched for in the comment string. If any of these
diff --git a/zuul/layoutvalidator.py b/zuul/layoutvalidator.py
index de1aec4..d464998 100644
--- a/zuul/layoutvalidator.py
+++ b/zuul/layoutvalidator.py
@@ -44,6 +44,7 @@
                                    'ref-updated')),
                       'comment_filter': toList(str),
                       'email_filter': toList(str),
+                      'username_filter': toList(str),
                       'branch': toList(str),
                       'ref': toList(str),
                       'approval': toList(variable_dict),
diff --git a/zuul/model.py b/zuul/model.py
index d6fc1f0..b66480a 100644
--- a/zuul/model.py
+++ b/zuul/model.py
@@ -874,17 +874,20 @@
 
 class EventFilter(object):
     def __init__(self, types=[], branches=[], refs=[], approvals={},
-                 comment_filters=[], email_filters=[], timespecs=[]):
+                 comment_filters=[], email_filters=[], username_filters=[],
+                 timespecs=[]):
         self._types = types
         self._branches = branches
         self._refs = refs
         self._comment_filters = comment_filters
         self._email_filters = email_filters
+        self._username_filters = username_filters
         self.types = [re.compile(x) for x in types]
         self.branches = [re.compile(x) for x in branches]
         self.refs = [re.compile(x) for x in refs]
         self.comment_filters = [re.compile(x) for x in comment_filters]
         self.email_filters = [re.compile(x) for x in email_filters]
+        self.username_filters = [re.compile(x) for x in username_filters]
         self.approvals = approvals
         self.timespecs = timespecs
 
@@ -904,6 +907,8 @@
             ret += ' comment_filters: %s' % ', '.join(self._comment_filters)
         if self._email_filters:
             ret += ' email_filters: %s' % ', '.join(self._email_filters)
+        if self._username_filters:
+            ret += ' username_filters: %s' % ', '.join(self._username_filters)
         if self.timespecs:
             ret += ' timespecs: %s' % ', '.join(self.timespecs)
         ret += '>'
@@ -961,6 +966,16 @@
             if self.email_filters and not matches_email_filter:
                 return False
 
+            # username_filters are ORed
+            account_username = event.account.get('username')
+            matches_username_filter = False
+            for username_filter in self.username_filters:
+                if (account_username is not None and
+                    username_filter.search(account_username)):
+                    matches_username_filter = True
+            if self.username_filters and not matches_username_filter:
+                return False
+
         # approvals are ANDed
         for category, value in self.approvals.items():
             matches_approval = False
diff --git a/zuul/scheduler.py b/zuul/scheduler.py
index 5a085e2..fabaa88 100644
--- a/zuul/scheduler.py
+++ b/zuul/scheduler.py
@@ -231,7 +231,9 @@
                                     comment_filters=
                                     toList(trigger.get('comment_filter')),
                                     email_filters=
-                                    toList(trigger.get('email_filter')))
+                                    toList(trigger.get('email_filter')),
+                                    username_filters=
+                                    toList(trigger.get('username_filter')))
                     manager.event_filters.append(f)
             elif 'timer' in conf_pipeline['trigger']:
                 pipeline.trigger = self.triggers['timer']