summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2019-09-20 18:22:32 +0000
committerGerrit Code Review <review@openstack.org>2019-09-20 18:22:32 +0000
commit68ffec06680a9f3e383865426e88b81bf85efaa9 (patch)
tree754df6e9f8f4c9cb7e73db1ad5df6ac23e1301d6
parent3837ab4120734c355824b54fed390a42b4a8f1e3 (diff)
parentae42bbe73576d696de710370701c3a1c138d981b (diff)
downloadzuul-68ffec06680a9f3e383865426e88b81bf85efaa9.tar.gz
Merge "Pagure - handle Pull Request tags (labels) metadata"
-rw-r--r--doc/source/admin/drivers/pagure.rst19
-rw-r--r--doc/source/admin/examples/pipelines/pagure-reference-pipelines.yaml4
-rw-r--r--tests/base.py25
-rw-r--r--tests/fixtures/layouts/requirements-pagure.yaml40
-rw-r--r--tests/unit/test_pagure_driver.py46
-rw-r--r--zuul/driver/pagure/pagureconnection.py34
-rw-r--r--zuul/driver/pagure/paguremodel.py24
-rw-r--r--zuul/driver/pagure/paguresource.py4
-rw-r--r--zuul/driver/pagure/paguretrigger.py2
9 files changed, 185 insertions, 13 deletions
diff --git a/doc/source/admin/drivers/pagure.rst b/doc/source/admin/drivers/pagure.rst
index 540940c67..889ba8d37 100644
--- a/doc/source/admin/drivers/pagure.rst
+++ b/doc/source/admin/drivers/pagure.rst
@@ -109,6 +109,10 @@ the following options.
Status set on pull request.
+ .. value:: tagged
+
+ Tag metadata set on pull request.
+
A :value:`pipeline.trigger.<pagure
source>.event.pg_pull_request_review` event will have associated
action(s) to trigger from. The supported actions are:
@@ -123,7 +127,7 @@ the following options.
.. attr:: comment
- This is only used for ``pg_pull_request`` ``comment`` actions. It
+ This is only used for ``pg_pull_request`` and ``comment`` actions. It
accepts a list of regexes that are searched for in the comment
string. If any of these regexes matches a portion of the comment
string the trigger is matched. ``comment: retrigger`` will
@@ -137,6 +141,12 @@ the following options.
the status, the status context, and the status itself in the
format of ``status``. For example, ``success`` or ``failure``.
+ .. attr:: tag
+
+ This is used for ``pg_pull_request`` and ``tagged`` actions. It
+ accepts a list of strings and if one of them is part of the
+ event tags metadata then the trigger is matched.
+
.. attr:: ref
This is only used for ``pg_push`` events. This field is treated as
@@ -199,6 +209,8 @@ configuration such as the following:
score: 1
merged: false
status: success
+ tags:
+ - gateit
This indicates that changes originating from the Pagure connection
must have a score of *1*, a CI status *success* and not being already merged.
@@ -226,6 +238,11 @@ must have a score of *1*, a CI status *success* and not being already merged.
A boolean value (``true`` or ``false``) that indicates whether
the Pull Request must be open or closed in order to be enqueued.
+ .. attr:: tags
+
+ if present, the list of tags a Pull Request must have.
+
+
Reference pipelines configuration
---------------------------------
diff --git a/doc/source/admin/examples/pipelines/pagure-reference-pipelines.yaml b/doc/source/admin/examples/pipelines/pagure-reference-pipelines.yaml
index 6d23e2b0a..e55ebf20a 100644
--- a/doc/source/admin/examples/pipelines/pagure-reference-pipelines.yaml
+++ b/doc/source/admin/examples/pipelines/pagure-reference-pipelines.yaml
@@ -35,6 +35,7 @@
pagure.io:
score: 1
merged: False
+ tags: gateit
status: success
sqlreporter:
trigger:
@@ -44,6 +45,9 @@
status: success
- event: pg_pull_request_review
action: thumbsup
+ - event: pg_pull_request
+ action: tagged
+ tag: gateit
start:
pagure.io:
status: 'pending'
diff --git a/tests/base.py b/tests/base.py
index da1c099ef..58d7ce029 100644
--- a/tests/base.py
+++ b/tests/base.py
@@ -1108,6 +1108,7 @@ class FakePagurePullRequest(object):
self.comments = []
self.flags = []
self.files = {}
+ self.tags = []
self.cached_merge_status = ''
self.threshold_reached = False
self.commit_stop = None
@@ -1122,16 +1123,17 @@ class FakePagurePullRequest(object):
self._addCommitInPR(files=files)
self._updateTimeStamp()
- def _getPullRequestEvent(self, action):
+ def _getPullRequestEvent(self, action, pull_data_field='pullrequest'):
name = 'pg_pull_request'
data = {
'msg': {
- 'pullrequest': {
+ pull_data_field: {
'branch': self.branch,
'comments': self.comments,
'commit_start': self.commit_start,
'commit_stop': self.commit_stop,
'date_created': '0',
+ 'tags': self.tags,
'initial_comment': self.initial_comment,
'id': self.number,
'project': {
@@ -1148,6 +1150,8 @@ class FakePagurePullRequest(object):
}
if action == 'pull-request.flag.added':
data['msg']['flag'] = self.flags[0]
+ if action == 'pull-request.tag.added':
+ data['msg']['tags'] = self.tags
return (name, data)
def getPullRequestOpenedEvent(self):
@@ -1169,6 +1173,20 @@ class FakePagurePullRequest(object):
self._updateTimeStamp()
return self._getPullRequestEvent('pull-request.initial_comment.edited')
+ def getPullRequestTagAddedEvent(self, tags, reset=True):
+ if reset:
+ self.tags = []
+ _tags = set(self.tags)
+ _tags.update(set(tags))
+ self.tags = list(_tags)
+ self.addComment(
+ "**Metadata Update from @pingou**:\n- " +
+ "Pull-request tagged with: %s" % ', '.join(tags),
+ True)
+ self._updateTimeStamp()
+ return self._getPullRequestEvent(
+ 'pull-request.tag.added', pull_data_field='pull_request')
+
def getPullRequestStatusSetEvent(self, status):
self.addFlag(
status, "https://url", "Build %s" % status)
@@ -1295,7 +1313,8 @@ class FakePagureAPIClient(pagureconnection.PagureAPIClient):
'comments': pr.comments,
'commit_stop': pr.commit_stop,
'threshold_reached': pr.threshold_reached,
- 'cached_merge_status': pr.cached_merge_status
+ 'cached_merge_status': pr.cached_merge_status,
+ 'tags': pr.tags,
}, 200, "", "GET"
match = re.match(r'.+/api/0/(.+)/pull-request/(\d+)/flag$', url)
diff --git a/tests/fixtures/layouts/requirements-pagure.yaml b/tests/fixtures/layouts/requirements-pagure.yaml
index 47ca6c135..36f785f30 100644
--- a/tests/fixtures/layouts/requirements-pagure.yaml
+++ b/tests/fixtures/layouts/requirements-pagure.yaml
@@ -38,6 +38,34 @@
pagure:
status: 'success'
+- pipeline:
+ name: trigger-tag
+ manager: independent
+ trigger:
+ pagure:
+ - event: pg_pull_request
+ action: tagged
+ tag:
+ - gateit
+ - mergeit
+ success:
+ pagure:
+ status: 'success'
+
+- pipeline:
+ name: require-tag
+ manager: independent
+ require:
+ pagure:
+ tags: gateit
+ trigger:
+ pagure:
+ - event: pg_pull_request
+ action: changed
+ success:
+ pagure:
+ status: 'success'
+
- job:
name: base
parent: null
@@ -64,3 +92,15 @@
trigger-flag:
jobs:
- project-test
+
+- project:
+ name: org/project4
+ trigger-tag:
+ jobs:
+ - project-test
+
+- project:
+ name: org/project5
+ require-tag:
+ jobs:
+ - project-test \ No newline at end of file
diff --git a/tests/unit/test_pagure_driver.py b/tests/unit/test_pagure_driver.py
index 4643b8620..3f023beea 100644
--- a/tests/unit/test_pagure_driver.py
+++ b/tests/unit/test_pagure_driver.py
@@ -360,6 +360,52 @@ class TestPagureDriver(ZuulTestCase):
self.waitUntilSettled()
self.assertEqual(1, len(self.history))
+ @simple_layout('layouts/requirements-pagure.yaml', driver='pagure')
+ def test_tag_trigger(self):
+
+ A = self.fake_pagure.openFakePullRequest(
+ 'org/project4', 'master', 'A')
+
+ self.fake_pagure.emitEvent(
+ A.getPullRequestTagAddedEvent(["lambda"]))
+ self.waitUntilSettled()
+ self.assertEqual(0, len(self.history))
+
+ self.fake_pagure.emitEvent(
+ A.getPullRequestTagAddedEvent(["gateit", "lambda"]))
+ self.waitUntilSettled()
+ self.assertEqual(1, len(self.history))
+
+ self.fake_pagure.emitEvent(
+ A.getPullRequestTagAddedEvent(["mergeit"]))
+ self.waitUntilSettled()
+ self.assertEqual(2, len(self.history))
+
+ @simple_layout('layouts/requirements-pagure.yaml', driver='pagure')
+ def test_tag_require(self):
+
+ A = self.fake_pagure.openFakePullRequest(
+ 'org/project5', 'master', 'A')
+
+ self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
+ self.waitUntilSettled()
+ self.assertEqual(0, len(self.history))
+
+ A.tags = ["lambda"]
+ self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
+ self.waitUntilSettled()
+ self.assertEqual(0, len(self.history))
+
+ A.tags = ["lambda", "gateit"]
+ self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
+ self.waitUntilSettled()
+ self.assertEqual(1, len(self.history))
+
+ A.tags = []
+ self.fake_pagure.emitEvent(A.getPullRequestUpdatedEvent())
+ self.waitUntilSettled()
+ self.assertEqual(1, len(self.history))
+
@simple_layout('layouts/merging-pagure.yaml', driver='pagure')
def test_merge_action_in_independent(self):
diff --git a/zuul/driver/pagure/pagureconnection.py b/zuul/driver/pagure/pagureconnection.py
index 8d91df223..313a900bf 100644
--- a/zuul/driver/pagure/pagureconnection.py
+++ b/zuul/driver/pagure/pagureconnection.py
@@ -18,6 +18,7 @@ import hashlib
import queue
import threading
import time
+import re
import json
import requests
import cherrypy
@@ -194,13 +195,17 @@ class PagureEventConnector(threading.Thread):
self.daemon = True
self.connection = connection
self._stopped = False
+ self.metadata_notif = re.compile(
+ r"^\*\*Metadata Update", re.MULTILINE)
self.event_handler_mapping = {
'pull-request.comment.added': self._event_issue_comment,
'pull-request.new': self._event_pull_request,
'pull-request.flag.added': self._event_flag_added,
'git.receive': self._event_ref_updated,
'pull-request.initial_comment.edited':
- self._event_issue_initial_comment
+ self._event_issue_initial_comment,
+ 'pull-request.tag.added':
+ self._event_pull_request_tags_changed
}
def stop(self):
@@ -244,16 +249,19 @@ class PagureEventConnector(threading.Thread):
self.connection.logEvent(event)
self.connection.sched.addEvent(event)
- def _event_base(self, body):
+ def _event_base(self, body, pull_data_field='pullrequest'):
event = PagureTriggerEvent()
- if 'pullrequest' in body['msg']:
- data = body['msg']['pullrequest']
+
+ if pull_data_field in body['msg']:
+ data = body['msg'][pull_data_field]
+ data['tags'] = body['msg'].get('tags', [])
data['flag'] = body['msg'].get('flag')
event.title = data.get('title')
event.project_name = data.get('project', {}).get('fullname')
event.change_number = data.get('id')
event.updated_at = data.get('date_created')
event.branch = data.get('branch')
+ event.tags = data.get('tags', [])
event.change_url = self.connection.getPullUrl(event.project_name,
event.change_number)
event.ref = "refs/pull/%s/head" % event.change_number
@@ -271,12 +279,21 @@ class PagureEventConnector(threading.Thread):
event.action = 'changed'
return event
+ def _event_pull_request_tags_changed(self, body):
+ """ Handles pull request metadata change """
+ # pull-request.tag.added/removed use pull_request in payload body
+ event, _ = self._event_base(body, pull_data_field='pull_request')
+ event.action = 'tagged'
+ return event
+
def _event_issue_comment(self, body):
""" Handles pull request comments """
# https://fedora-fedmsg.readthedocs.io/en/latest/topics.html#pagure-pull-request-comment-added
event, data = self._event_base(body)
last_comment = data.get('comments', [])[-1]
- if last_comment.get('notification') is True:
+ if (last_comment.get('notification') is True and
+ not self.metadata_notif.match(
+ last_comment.get('comment', ''))):
# An updated PR (new commits) triggers the comment.added
# event. A message is added by pagure on the PR but notification
# is set to true.
@@ -556,7 +573,8 @@ class PagureConnection(BaseConnection):
self.connectors = {}
self.source = driver.getSource(self)
self.event_queue = queue.Queue()
-
+ self.metadata_notif = re.compile(
+ r"^\*\*Metadata Update", re.MULTILINE)
self.sched = None
def onLoad(self):
@@ -793,6 +811,9 @@ class PagureConnection(BaseConnection):
for comment in pr.get('comments', []):
# PR updated are reported as comment but with the notification flag
if comment['notification']:
+ # Ignore metadata update such as assignee and tags
+ if self.metadata_notif.match(comment.get('comment', '')):
+ continue
date = int(comment['date_created'])
if date > last_pr_code_updated:
last_pr_code_updated = date
@@ -822,6 +843,7 @@ class PagureConnection(BaseConnection):
change.patchset = change.pr.get('commit_stop')
change.files = change.pr.get('files')
change.title = change.pr.get('title')
+ change.tags = change.pr.get('tags')
change.open = change.pr.get('status') == 'Open'
change.is_merged = change.pr.get('status') == 'Merged'
change.status = self.getStatus(change.project, change.number)
diff --git a/zuul/driver/pagure/paguremodel.py b/zuul/driver/pagure/paguremodel.py
index 5036fc8a7..f62e7f787 100644
--- a/zuul/driver/pagure/paguremodel.py
+++ b/zuul/driver/pagure/paguremodel.py
@@ -27,6 +27,7 @@ class PullRequest(Change):
self.title = None
self.score = 0
self.files = []
+ self.tags = []
def __repr__(self):
r = ['<Change 0x%x' % id(self)]
@@ -42,6 +43,8 @@ class PullRequest(Change):
r.append('status: %s' % self.status)
if self.score:
r.append('score: %s' % self.score)
+ if self.tags:
+ r.append('tags: %s' % ', '.join(self.tags))
if self.is_merged:
r.append('state: merged')
if self.open:
@@ -64,6 +67,7 @@ class PagureTriggerEvent(TriggerEvent):
self.title = None
self.action = None
self.status = None
+ self.tags = []
def _repr(self):
r = [super(PagureTriggerEvent, self)._repr()]
@@ -74,6 +78,8 @@ class PagureTriggerEvent(TriggerEvent):
r.append("project:%s" % self.canonical_project_name)
if self.change_number:
r.append("pr:%s" % self.change_number)
+ if self.tags:
+ r.append("tags:%s" % ', '.join(self.tags))
return ' '.join(r)
def isPatchsetCreated(self):
@@ -84,7 +90,7 @@ class PagureTriggerEvent(TriggerEvent):
class PagureEventFilter(EventFilter):
def __init__(self, trigger, types=[], refs=[], statuses=[],
- comments=[], actions=[], ignore_deletes=True):
+ comments=[], actions=[], tags=[], ignore_deletes=True):
EventFilter.__init__(self, trigger)
@@ -96,6 +102,7 @@ class PagureEventFilter(EventFilter):
self.comments = [re.compile(x) for x in comments]
self.actions = actions
self.statuses = statuses
+ self.tags = tags
self.ignore_deletes = ignore_deletes
def __repr__(self):
@@ -113,6 +120,8 @@ class PagureEventFilter(EventFilter):
ret += ' actions: %s' % ', '.join(self.actions)
if self.statuses:
ret += ' statuses: %s' % ', '.join(self.statuses)
+ if self.tags:
+ ret += ' tags: %s' % ', '.join(self.tags)
ret += '>'
return ret
@@ -159,6 +168,10 @@ class PagureEventFilter(EventFilter):
if self.statuses and not matches_status:
return False
+ if self.tags:
+ if not set(event.tags).intersection(set(self.tags)):
+ return False
+
return True
@@ -166,12 +179,13 @@ class PagureEventFilter(EventFilter):
# pipeline requires definition)
class PagureRefFilter(RefFilter):
def __init__(self, connection_name, score=None,
- open=None, merged=None, status=None):
+ open=None, merged=None, status=None, tags=[]):
RefFilter.__init__(self, connection_name)
self.score = score
self.open = open
self.merged = merged
self.status = status
+ self.tags = tags
def __repr__(self):
ret = '<PagureRefFilter connection_name: %s ' % self.connection_name
@@ -183,6 +197,8 @@ class PagureRefFilter(RefFilter):
ret += ' merged: %s' % self.merged
if self.status is not None:
ret += ' status: %s' % self.status
+ if self.tags:
+ ret += ' tags: %s' % ', '.join(self.tags)
ret += '>'
return ret
@@ -203,4 +219,8 @@ class PagureRefFilter(RefFilter):
if change.status != self.status:
return False
+ if self.tags:
+ if not set(change.tags).intersection(set(self.tags)):
+ return False
+
return True
diff --git a/zuul/driver/pagure/paguresource.py b/zuul/driver/pagure/paguresource.py
index 00ee07830..40862d307 100644
--- a/zuul/driver/pagure/paguresource.py
+++ b/zuul/driver/pagure/paguresource.py
@@ -20,6 +20,7 @@ from zuul.source import BaseSource
from zuul.model import Project
from zuul.driver.pagure.paguremodel import PagureRefFilter
+from zuul.driver.util import scalar_or_list, to_list
class PagureSource(BaseSource):
@@ -117,7 +118,6 @@ class PagureSource(BaseSource):
"""Get the git-web url for a project."""
raise NotImplementedError()
- # This driver does not implement pipeline requirements.
def getRequireFilters(self, config):
f = PagureRefFilter(
connection_name=self.connection.connection_name,
@@ -125,6 +125,7 @@ class PagureSource(BaseSource):
open=config.get('open'),
merged=config.get('merged'),
status=config.get('status'),
+ tags=to_list(config.get('tags'))
)
return [f]
@@ -142,6 +143,7 @@ def getRequireSchema():
'open': bool,
'merged': bool,
'status': str,
+ 'tags': scalar_or_list(str)
}
return require
diff --git a/zuul/driver/pagure/paguretrigger.py b/zuul/driver/pagure/paguretrigger.py
index 61c1fe289..e475e49e6 100644
--- a/zuul/driver/pagure/paguretrigger.py
+++ b/zuul/driver/pagure/paguretrigger.py
@@ -33,6 +33,7 @@ class PagureTrigger(BaseTrigger):
refs=to_list(trigger.get('ref')),
comments=to_list(trigger.get('comment')),
statuses=to_list(trigger.get('status')),
+ tags=to_list(trigger.get('tag')),
)
efilters.append(f)
@@ -56,6 +57,7 @@ def getSchema():
'ref': scalar_or_list(str),
'comment': scalar_or_list(str),
'status': scalar_or_list(str),
+ 'tag': scalar_or_list(str)
}
return pagure_trigger