Implement github pipeline req of current-patchset

Require that the commit from the event is the latest commit in the pull
request.

Also fix a problem with faked github status grabs. Now we're sending an
event where the sha of the event isn't the head sha, and that was
tripping up our fakes.

Change-Id: I269c97d096e42f0a2d4a0f1b0e57eb238e0b7baf
This commit is contained in:
Jesse Keating 2017-05-26 11:32:53 -07:00
parent 4a27f135a6
commit 0d40c127c7
6 changed files with 65 additions and 3 deletions

View File

@ -996,8 +996,12 @@ class FakeGithubConnection(githubconnection.GithubConnection):
owner, proj = project.split('/')
for pr in self.pull_requests:
pr_owner, pr_project = pr.project.split('/')
# This is somewhat risky, if the same commit exists in multiple
# PRs, we might grab the wrong one that doesn't have a status
# that is expected to be there. Maybe re-work this so that there
# is a global registry of commit statuses like with github.
if (pr_owner == owner and pr_project == proj and
pr.head_sha == sha):
sha in pr.statuses):
return pr.statuses[sha]
def setCommitStatus(self, project, sha, state,

View File

@ -154,6 +154,20 @@
github:
comment: true
- pipeline:
name: require_current
manager: independent
require:
github:
current-patchset: true
trigger:
github:
- event: pull_request
action: changed
success:
github:
comment: true
- job:
name: project1-pipeline
- job:
@ -170,6 +184,8 @@
name: project7-olderthan
- job:
name: project8-requireopen
- job:
name: project9-requirecurrent
- project:
name: org/project1
@ -221,3 +237,9 @@
require_open:
jobs:
- project8-requireopen
- project:
name: org/project9
require_current:
jobs:
- project9-requirecurrent

View File

@ -307,3 +307,22 @@ class TestGithubRequirements(ZuulTestCase):
self.waitUntilSettled()
# PR is closed, should not trigger
self.assertEqual(len(self.history), 1)
@simple_layout('layouts/requirements-github.yaml', driver='github')
def test_require_current(self):
A = self.fake_github.openFakePullRequest('org/project9', 'master', 'A')
# A sync event that we will keep submitting to trigger
sync = A.getPullRequestSynchronizeEvent()
self.fake_github.emitEvent(sync)
self.waitUntilSettled()
# PR head is current should enqueue
self.assertEqual(len(self.history), 1)
# Add a commit to the PR, re-issue the original comment event
A.addCommit()
self.fake_github.emitEvent(sync)
self.waitUntilSettled()
# Event hash is not current, should not trigger
self.assertEqual(len(self.history), 1)

View File

@ -480,6 +480,9 @@ class GithubConnection(BaseConnection):
change.reviews = self.getPullReviews(project, change.number)
change.source_event = event
change.open = self.getPullOpen(project, change.number)
change.is_current_patchset = self.getIsCurrent(project,
change.number,
event.patch_number)
elif event.ref:
change = Ref(project)
change.ref = event.ref
@ -721,6 +724,10 @@ class GithubConnection(BaseConnection):
pr = self.getPull(project, number)
return pr.get('state') == 'open'
def getIsCurrent(self, project, number, sha):
pr = self.getPull(project, number)
return pr.get('head').get('sha') == sha
def _ghTimestampToDate(self, timestamp):
return time.strptime(timestamp, '%Y-%m-%dT%H:%M:%SZ')

View File

@ -263,13 +263,15 @@ class GithubEventFilter(EventFilter, GithubCommonFilter):
class GithubRefFilter(RefFilter, GithubCommonFilter):
def __init__(self, statuses=[], required_reviews=[], open=None):
def __init__(self, statuses=[], required_reviews=[], open=None,
current_patchset=None):
RefFilter.__init__(self)
GithubCommonFilter.__init__(self, required_reviews=required_reviews,
required_statuses=statuses)
self.statuses = statuses
self.open = open
self.current_patchset = current_patchset
def __repr__(self):
ret = '<GithubRefFilter'
@ -281,6 +283,8 @@ class GithubRefFilter(RefFilter, GithubCommonFilter):
str(self.required_reviews))
if self.open:
ret += ' open: %s' % self.open
if self.current_patchset:
ret += ' current-patchset: %s' % self.current_patchset
ret += '>'
@ -294,6 +298,10 @@ class GithubRefFilter(RefFilter, GithubCommonFilter):
if self.open != change.open:
return False
if self.current_patchset is not None:
if self.current_patchset != change.is_current_patchset:
return False
# required reviews are ANDed
if not self.matchesReviews(change):
return False

View File

@ -99,6 +99,7 @@ class GithubSource(BaseSource):
statuses=to_list(config.get('status')),
required_reviews=to_list(config.get('review')),
open=config.get('open'),
current_patchset=config.get('current-patchset'),
)
return [f]
@ -118,7 +119,8 @@ review = v.Schema({'username': str,
def getRequireSchema():
require = {'status': scalar_or_list(str),
'review': scalar_or_list(review),
'open': bool}
'open': bool,
'current-patchset': bool}
return require