Merge "Add trigger capability on github pr review" into feature/zuulv3
This commit is contained in:
commit
e35885cbde
|
@ -109,7 +109,10 @@ A connection name with the github driver can take multiple events with the
|
|||
following options.
|
||||
|
||||
**event**
|
||||
The pull request event from github. A ``pull_request`` event will
|
||||
The event from github. Supported events are ``pull_request``,
|
||||
``pull_request_review``, and ``push``.
|
||||
|
||||
A ``pull_request`` event will
|
||||
have associated action(s) to trigger from. The supported actions are:
|
||||
|
||||
*opened* - pull request opened
|
||||
|
@ -126,32 +129,46 @@ following options.
|
|||
|
||||
*unlabeled* - label removed from pull request
|
||||
|
||||
*review* - review added on pull request
|
||||
|
||||
*push* - head reference updated (pushed to branch)
|
||||
|
||||
A ``pull_request_review`` event will
|
||||
have associated action(s) to trigger from. The supported actions are:
|
||||
|
||||
*submitted* - pull request review added
|
||||
|
||||
*dismissed* - pull request review removed
|
||||
|
||||
**branch**
|
||||
The branch associated with the event. Example: ``master``. This
|
||||
field is treated as a regular expression, and multiple branches may
|
||||
be listed. Used for ``pull-request`` events.
|
||||
be listed. Used for ``pull_request`` and ``pull_request_review`` events.
|
||||
|
||||
**comment**
|
||||
This is only used for ``pull_request`` ``comment`` events. It accepts a list
|
||||
of regexes that are searched for in the comment string. If any of these
|
||||
This is only used for ``pull_request`` ``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 match when comments containing 'retrigger'
|
||||
somewhere in the comment text are added to a pull request.
|
||||
|
||||
**label**
|
||||
This is only used for ``labeled`` and ``unlabeled`` actions. It accepts a list
|
||||
of strings each of which matches the label name in the event literally.
|
||||
``label: recheck`` will match a ``labeled`` action when pull request is
|
||||
labeled with a ``recheck`` label. ``label: 'do not test'`` will match a
|
||||
``unlabeled`` action when a label with name ``do not test`` is removed from
|
||||
the pull request.
|
||||
This is only used for ``labeled`` and ``unlabeled`` ``pull_request`` actions.
|
||||
It accepts a list of strings each of which matches the label name in the
|
||||
event literally. ``label: recheck`` will match a ``labeled`` action when
|
||||
pull request is labeled with a ``recheck`` label. ``label: 'do not test'``
|
||||
will match a ``unlabeled`` action when a label with name ``do not test`` is
|
||||
removed from the pull request.
|
||||
|
||||
Additionally a ``push`` event can be configured, with an ``ref`` field. This
|
||||
field is treated as a regular expression and multiple refs may be listed.
|
||||
Github always sends full ref name, eg. ``refs/tags/bar`` and this string is
|
||||
matched against the regexp.
|
||||
**state**
|
||||
This is only used for ``pull_request_review`` events. It accepts a list of
|
||||
strings each of which is matched to the review state, which can be one of
|
||||
``approved``, ``comment``, or ``request_changes``.
|
||||
|
||||
**ref**
|
||||
This is only used for ``push`` events. This field is treated as a regular
|
||||
expression and multiple refs may be listed. Github always sends full ref
|
||||
name, eg. ``refs/tags/bar`` and this string is matched against the regexp.
|
||||
|
||||
GitHub Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -617,6 +617,36 @@ class FakeGithubPullRequest(object):
|
|||
}
|
||||
return (name, data)
|
||||
|
||||
def getReviewAddedEvent(self, review):
|
||||
name = 'pull_request_review'
|
||||
data = {
|
||||
'action': 'submitted',
|
||||
'pull_request': {
|
||||
'number': self.number,
|
||||
'title': self.subject,
|
||||
'updated_at': self.updated_at,
|
||||
'base': {
|
||||
'ref': self.branch,
|
||||
'repo': {
|
||||
'full_name': self.project
|
||||
}
|
||||
},
|
||||
'head': {
|
||||
'sha': self.head_sha
|
||||
}
|
||||
},
|
||||
'review': {
|
||||
'state': review
|
||||
},
|
||||
'repository': {
|
||||
'full_name': self.project
|
||||
},
|
||||
'sender': {
|
||||
'login': 'ghuser'
|
||||
}
|
||||
}
|
||||
return (name, data)
|
||||
|
||||
def addLabel(self, name):
|
||||
if name not in self.labels:
|
||||
self.labels.append(name)
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
- pipeline:
|
||||
name: reviews
|
||||
manager: independent
|
||||
trigger:
|
||||
github:
|
||||
- event: pull_request_review
|
||||
action: submitted
|
||||
state: 'approve'
|
||||
success:
|
||||
github:
|
||||
label:
|
||||
- 'tests passed'
|
||||
|
||||
- job:
|
||||
name: project-reviews
|
||||
|
||||
- project:
|
||||
name: org/project
|
||||
reviews:
|
||||
jobs:
|
||||
- project-reviews
|
|
@ -177,6 +177,21 @@ class TestGithubDriver(ZuulTestCase):
|
|||
self.assertEqual(2, len(self.history))
|
||||
self.assertEqual(['other label'], C.labels)
|
||||
|
||||
@simple_layout('layouts/reviews-github.yaml', driver='github')
|
||||
def test_review_event(self):
|
||||
A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
|
||||
self.fake_github.emitEvent(A.getReviewAddedEvent('approve'))
|
||||
self.waitUntilSettled()
|
||||
self.assertEqual(1, len(self.history))
|
||||
self.assertEqual('project-reviews', self.history[0].name)
|
||||
self.assertEqual(['tests passed'], A.labels)
|
||||
|
||||
# test_review_unmatched_event
|
||||
B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
|
||||
self.fake_github.emitEvent(B.getReviewAddedEvent('comment'))
|
||||
self.waitUntilSettled()
|
||||
self.assertEqual(1, len(self.history))
|
||||
|
||||
@simple_layout('layouts/dequeue-github.yaml', driver='github')
|
||||
def test_dequeue_pull_synchronized(self):
|
||||
self.executor_server.hold_jobs_in_build = True
|
||||
|
|
|
@ -143,6 +143,24 @@ class GithubWebhookListener():
|
|||
event.action = 'comment'
|
||||
return event
|
||||
|
||||
def _event_pull_request_review(self, request):
|
||||
"""Handles pull request reviews"""
|
||||
body = request.json_body
|
||||
pr_body = body.get('pull_request')
|
||||
if pr_body is None:
|
||||
return
|
||||
|
||||
review = body.get('review')
|
||||
if review is None:
|
||||
return
|
||||
|
||||
event = self._pull_request_to_event(pr_body)
|
||||
event.state = review.get('state')
|
||||
event.account = self._get_sender(body)
|
||||
event.type = 'pull_request_review'
|
||||
event.action = body.get('action')
|
||||
return event
|
||||
|
||||
def _issue_to_pull_request(self, body):
|
||||
number = body.get('issue').get('number')
|
||||
project_name = body.get('repository').get('full_name')
|
||||
|
|
|
@ -40,7 +40,8 @@ class GithubTrigger(BaseTrigger):
|
|||
refs=toList(trigger.get('ref')),
|
||||
comments=toList(trigger.get('comment')),
|
||||
labels=toList(trigger.get('label')),
|
||||
unlabels=toList(trigger.get('unlabel'))
|
||||
unlabels=toList(trigger.get('unlabel')),
|
||||
states=toList(trigger.get('state'))
|
||||
)
|
||||
efilters.append(f)
|
||||
|
||||
|
@ -57,6 +58,7 @@ def getSchema():
|
|||
github_trigger = {
|
||||
v.Required('event'):
|
||||
toList(v.Any('pull_request',
|
||||
'pull_request_review',
|
||||
'push')),
|
||||
'action': toList(str),
|
||||
'branch': toList(str),
|
||||
|
@ -64,6 +66,7 @@ def getSchema():
|
|||
'comment': toList(str),
|
||||
'label': toList(str),
|
||||
'unlabel': toList(str),
|
||||
'state': toList(str),
|
||||
}
|
||||
|
||||
return github_trigger
|
||||
|
|
|
@ -1896,6 +1896,7 @@ class TriggerEvent(object):
|
|||
self.comment = None
|
||||
self.label = None
|
||||
self.unlabel = None
|
||||
self.state = None
|
||||
# ref-updated
|
||||
self.ref = None
|
||||
self.oldrev = None
|
||||
|
@ -2047,7 +2048,7 @@ class EventFilter(BaseFilter):
|
|||
def __init__(self, trigger, types=[], branches=[], refs=[],
|
||||
event_approvals={}, comments=[], emails=[], usernames=[],
|
||||
timespecs=[], required_approvals=[], reject_approvals=[],
|
||||
pipelines=[], actions=[], labels=[], unlabels=[],
|
||||
pipelines=[], actions=[], labels=[], unlabels=[], states=[],
|
||||
ignore_deletes=True):
|
||||
super(EventFilter, self).__init__(
|
||||
required_approvals=required_approvals,
|
||||
|
@ -2072,6 +2073,7 @@ class EventFilter(BaseFilter):
|
|||
self.timespecs = timespecs
|
||||
self.labels = labels
|
||||
self.unlabels = unlabels
|
||||
self.states = states
|
||||
self.ignore_deletes = ignore_deletes
|
||||
|
||||
def __repr__(self):
|
||||
|
@ -2110,6 +2112,8 @@ class EventFilter(BaseFilter):
|
|||
ret += ' labels: %s' % ', '.join(self.labels)
|
||||
if self.unlabels:
|
||||
ret += ' unlabels: %s' % ', '.join(self.unlabels)
|
||||
if self.states:
|
||||
ret += ' states: %s' % ', '.join(self.states)
|
||||
ret += '>'
|
||||
|
||||
return ret
|
||||
|
@ -2222,6 +2226,10 @@ class EventFilter(BaseFilter):
|
|||
if self.unlabels and event.unlabel not in self.unlabels:
|
||||
return False
|
||||
|
||||
# states are ORed
|
||||
if self.states and event.state not in self.states:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue