Support for dependent pipelines with github
Change-Id: I5e7937d0f524107572f8aec7945f94b620d77b61 Co-Authored-By: Jesse Keating <omgjlk@us.ibm.com>
This commit is contained in:
committed by
Jesse Keating
parent
324ca5b744
commit
37615e5c6f
@@ -547,7 +547,7 @@ class GithubChangeReference(git.Reference):
|
||||
class FakeGithubPullRequest(object):
|
||||
|
||||
def __init__(self, github, number, project, branch,
|
||||
upstream_root, number_of_commits=1):
|
||||
subject, upstream_root, number_of_commits=1):
|
||||
"""Creates a new PR with several commits.
|
||||
Sends an event about opened PR."""
|
||||
self.github = github
|
||||
@@ -555,6 +555,8 @@ class FakeGithubPullRequest(object):
|
||||
self.number = number
|
||||
self.project = project
|
||||
self.branch = branch
|
||||
self.subject = subject
|
||||
self.number_of_commits = 0
|
||||
self.upstream_root = upstream_root
|
||||
self.comments = []
|
||||
self.labels = []
|
||||
@@ -681,13 +683,15 @@ class FakeGithubPullRequest(object):
|
||||
repo = self._getRepo()
|
||||
ref = repo.references[self._getPRReference()]
|
||||
if reset:
|
||||
self.number_of_commits = 0
|
||||
ref.set_object('refs/tags/init')
|
||||
self.number_of_commits += 1
|
||||
repo.head.reference = ref
|
||||
zuul.merger.merger.reset_repo_to_head(repo)
|
||||
repo.git.clean('-x', '-f', '-d')
|
||||
|
||||
fn = '%s-%s' % (self.branch.replace('/', '_'), self.number)
|
||||
msg = 'test-%s' % self.number
|
||||
msg = self.subject + '-' + str(self.number_of_commits)
|
||||
fn = os.path.join(repo.working_dir, fn)
|
||||
f = open(fn, 'w')
|
||||
with open(fn, 'w') as f:
|
||||
@@ -757,10 +761,10 @@ class FakeGithubConnection(githubconnection.GithubConnection):
|
||||
self.merge_failure = False
|
||||
self.merge_not_allowed_count = 0
|
||||
|
||||
def openFakePullRequest(self, project, branch):
|
||||
def openFakePullRequest(self, project, branch, subject):
|
||||
self.pr_number += 1
|
||||
pull_request = FakeGithubPullRequest(
|
||||
self, self.pr_number, project, branch, self.upstream_root)
|
||||
self, self.pr_number, project, branch, subject, self.upstream_root)
|
||||
self.pull_requests.append(pull_request)
|
||||
return pull_request
|
||||
|
||||
@@ -803,6 +807,7 @@ class FakeGithubConnection(githubconnection.GithubConnection):
|
||||
},
|
||||
'ref': pr.branch,
|
||||
},
|
||||
'mergeable': True,
|
||||
'head': {
|
||||
'sha': pr.head_sha
|
||||
}
|
||||
|
||||
35
tests/fixtures/layouts/dependent-github.yaml
vendored
Normal file
35
tests/fixtures/layouts/dependent-github.yaml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
- pipeline:
|
||||
name: gate
|
||||
description: Gatekeeping
|
||||
manager: dependent
|
||||
trigger:
|
||||
github:
|
||||
- event: pull_request
|
||||
action: labeled
|
||||
label: 'merge'
|
||||
success:
|
||||
github:
|
||||
merge: true
|
||||
unlabel: 'merge'
|
||||
failure:
|
||||
github:
|
||||
unlabel: 'merge'
|
||||
|
||||
- job:
|
||||
name: project-test1
|
||||
- job:
|
||||
name: project-test2
|
||||
- job:
|
||||
name: project-merge
|
||||
failure-message: Unable to merge change
|
||||
hold-following-changes: true
|
||||
|
||||
- project:
|
||||
name: org/project
|
||||
gate:
|
||||
jobs:
|
||||
- project-merge
|
||||
- project-test1:
|
||||
dependencies: project-merge
|
||||
- project-test2:
|
||||
dependencies: project-merge
|
||||
@@ -31,14 +31,14 @@ class TestGithubDriver(ZuulTestCase):
|
||||
def test_pull_event(self):
|
||||
self.executor_server.hold_jobs_in_build = True
|
||||
|
||||
pr = self.fake_github.openFakePullRequest('org/project', 'master')
|
||||
self.fake_github.emitEvent(pr.getPullRequestOpenedEvent())
|
||||
A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
|
||||
self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
|
||||
self.waitUntilSettled()
|
||||
|
||||
build_params = self.builds[0].parameters
|
||||
self.assertEqual('master', build_params['ZUUL_BRANCH'])
|
||||
self.assertEqual(str(pr.number), build_params['ZUUL_CHANGE'])
|
||||
self.assertEqual(pr.head_sha, build_params['ZUUL_PATCHSET'])
|
||||
self.assertEqual(str(A.number), build_params['ZUUL_CHANGE'])
|
||||
self.assertEqual(A.head_sha, build_params['ZUUL_PATCHSET'])
|
||||
|
||||
self.executor_server.hold_jobs_in_build = False
|
||||
self.executor_server.release()
|
||||
@@ -51,20 +51,20 @@ class TestGithubDriver(ZuulTestCase):
|
||||
|
||||
job = self.getJobFromHistory('project-test2')
|
||||
zuulvars = job.parameters['vars']['zuul']
|
||||
self.assertEqual(pr.number, zuulvars['change'])
|
||||
self.assertEqual(pr.head_sha, zuulvars['patchset'])
|
||||
self.assertEqual(1, len(pr.comments))
|
||||
self.assertEqual(A.number, zuulvars['change'])
|
||||
self.assertEqual(A.head_sha, zuulvars['patchset'])
|
||||
self.assertEqual(1, len(A.comments))
|
||||
|
||||
@simple_layout('layouts/basic-github.yaml', driver='github')
|
||||
def test_comment_event(self):
|
||||
pr = self.fake_github.openFakePullRequest('org/project', 'master')
|
||||
self.fake_github.emitEvent(pr.getCommentAddedEvent('test me'))
|
||||
A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
|
||||
self.fake_github.emitEvent(A.getCommentAddedEvent('test me'))
|
||||
self.waitUntilSettled()
|
||||
self.assertEqual(2, len(self.history))
|
||||
|
||||
# Test an unmatched comment, history should remain the same
|
||||
pr = self.fake_github.openFakePullRequest('org/project', 'master')
|
||||
self.fake_github.emitEvent(pr.getCommentAddedEvent('casual comment'))
|
||||
B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
|
||||
self.fake_github.emitEvent(B.getCommentAddedEvent('casual comment'))
|
||||
self.waitUntilSettled()
|
||||
self.assertEqual(2, len(self.history))
|
||||
|
||||
@@ -116,7 +116,7 @@ class TestGithubDriver(ZuulTestCase):
|
||||
|
||||
@simple_layout('layouts/labeling-github.yaml', driver='github')
|
||||
def test_labels(self):
|
||||
A = self.fake_github.openFakePullRequest('org/project', 'master')
|
||||
A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
|
||||
self.fake_github.emitEvent(A.addLabel('test'))
|
||||
self.waitUntilSettled()
|
||||
self.assertEqual(1, len(self.history))
|
||||
@@ -124,7 +124,7 @@ class TestGithubDriver(ZuulTestCase):
|
||||
self.assertEqual(['tests passed'], A.labels)
|
||||
|
||||
# test label removed
|
||||
B = self.fake_github.openFakePullRequest('org/project', 'master')
|
||||
B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
|
||||
B.addLabel('do not test')
|
||||
self.fake_github.emitEvent(B.removeLabel('do not test'))
|
||||
self.waitUntilSettled()
|
||||
@@ -133,7 +133,7 @@ class TestGithubDriver(ZuulTestCase):
|
||||
self.assertEqual(['tests passed'], B.labels)
|
||||
|
||||
# test unmatched label
|
||||
C = self.fake_github.openFakePullRequest('org/project', 'master')
|
||||
C = self.fake_github.openFakePullRequest('org/project', 'master', 'C')
|
||||
self.fake_github.emitEvent(C.addLabel('other label'))
|
||||
self.waitUntilSettled()
|
||||
self.assertEqual(2, len(self.history))
|
||||
@@ -143,16 +143,16 @@ class TestGithubDriver(ZuulTestCase):
|
||||
def test_dequeue_pull_synchronized(self):
|
||||
self.executor_server.hold_jobs_in_build = True
|
||||
|
||||
pr = self.fake_github.openFakePullRequest(
|
||||
'org/one-job-project', 'master')
|
||||
self.fake_github.emitEvent(pr.getPullRequestOpenedEvent())
|
||||
A = self.fake_github.openFakePullRequest(
|
||||
'org/one-job-project', 'master', 'A')
|
||||
self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
|
||||
self.waitUntilSettled()
|
||||
|
||||
# event update stamp has resolution one second, wait so the latter
|
||||
# one has newer timestamp
|
||||
time.sleep(1)
|
||||
pr.addCommit()
|
||||
self.fake_github.emitEvent(pr.getPullRequestSynchronizeEvent())
|
||||
A.addCommit()
|
||||
self.fake_github.emitEvent(A.getPullRequestSynchronizeEvent())
|
||||
self.waitUntilSettled()
|
||||
|
||||
self.executor_server.hold_jobs_in_build = False
|
||||
@@ -166,11 +166,11 @@ class TestGithubDriver(ZuulTestCase):
|
||||
def test_dequeue_pull_abandoned(self):
|
||||
self.executor_server.hold_jobs_in_build = True
|
||||
|
||||
pr = self.fake_github.openFakePullRequest(
|
||||
'org/one-job-project', 'master')
|
||||
self.fake_github.emitEvent(pr.getPullRequestOpenedEvent())
|
||||
A = self.fake_github.openFakePullRequest(
|
||||
'org/one-job-project', 'master', 'A')
|
||||
self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
|
||||
self.waitUntilSettled()
|
||||
self.fake_github.emitEvent(pr.getPullRequestClosedEvent())
|
||||
self.fake_github.emitEvent(A.getPullRequestClosedEvent())
|
||||
self.waitUntilSettled()
|
||||
|
||||
self.executor_server.hold_jobs_in_build = False
|
||||
@@ -196,54 +196,54 @@ class TestGithubDriver(ZuulTestCase):
|
||||
def test_reporting(self):
|
||||
# pipeline reports pull status both on start and success
|
||||
self.executor_server.hold_jobs_in_build = True
|
||||
pr = self.fake_github.openFakePullRequest('org/project', 'master')
|
||||
self.fake_github.emitEvent(pr.getPullRequestOpenedEvent())
|
||||
A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
|
||||
self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
|
||||
self.waitUntilSettled()
|
||||
self.assertIn('check', pr.statuses)
|
||||
check_status = pr.statuses['check']
|
||||
self.assertIn('check', A.statuses)
|
||||
check_status = A.statuses['check']
|
||||
self.assertEqual('Standard check', check_status['description'])
|
||||
self.assertEqual('pending', check_status['state'])
|
||||
self.assertEqual('http://zuul.example.com/status', check_status['url'])
|
||||
self.assertEqual(0, len(pr.comments))
|
||||
self.assertEqual(0, len(A.comments))
|
||||
|
||||
self.executor_server.hold_jobs_in_build = False
|
||||
self.executor_server.release()
|
||||
self.waitUntilSettled()
|
||||
check_status = pr.statuses['check']
|
||||
check_status = A.statuses['check']
|
||||
self.assertEqual('Standard check', check_status['description'])
|
||||
self.assertEqual('success', check_status['state'])
|
||||
self.assertEqual('http://zuul.example.com/status', check_status['url'])
|
||||
self.assertEqual(1, len(pr.comments))
|
||||
self.assertThat(pr.comments[0],
|
||||
self.assertEqual(1, len(A.comments))
|
||||
self.assertThat(A.comments[0],
|
||||
MatchesRegex('.*Build succeeded.*', re.DOTALL))
|
||||
|
||||
# pipeline does not report any status but does comment
|
||||
self.executor_server.hold_jobs_in_build = True
|
||||
self.fake_github.emitEvent(
|
||||
pr.getCommentAddedEvent('reporting check'))
|
||||
A.getCommentAddedEvent('reporting check'))
|
||||
self.waitUntilSettled()
|
||||
self.assertNotIn('reporting', pr.statuses)
|
||||
self.assertNotIn('reporting', A.statuses)
|
||||
# comments increased by one for the start message
|
||||
self.assertEqual(2, len(pr.comments))
|
||||
self.assertThat(pr.comments[1],
|
||||
self.assertEqual(2, len(A.comments))
|
||||
self.assertThat(A.comments[1],
|
||||
MatchesRegex('.*Starting reporting jobs.*', re.DOTALL))
|
||||
self.executor_server.hold_jobs_in_build = False
|
||||
self.executor_server.release()
|
||||
self.waitUntilSettled()
|
||||
self.assertNotIn('reporting', pr.statuses)
|
||||
self.assertEqual(2, len(pr.comments))
|
||||
self.assertNotIn('reporting', A.statuses)
|
||||
self.assertEqual(2, len(A.comments))
|
||||
|
||||
@simple_layout('layouts/merging-github.yaml', driver='github')
|
||||
def test_report_pull_merge(self):
|
||||
# pipeline merges the pull request on success
|
||||
A = self.fake_github.openFakePullRequest('org/project', 'master')
|
||||
A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
|
||||
self.fake_github.emitEvent(A.getCommentAddedEvent('merge me'))
|
||||
self.waitUntilSettled()
|
||||
self.assertTrue(A.is_merged)
|
||||
|
||||
# pipeline merges the pull request on success after failure
|
||||
self.fake_github.merge_failure = True
|
||||
B = self.fake_github.openFakePullRequest('org/project', 'master')
|
||||
B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
|
||||
self.fake_github.emitEvent(B.getCommentAddedEvent('merge me'))
|
||||
self.waitUntilSettled()
|
||||
self.assertFalse(B.is_merged)
|
||||
@@ -252,7 +252,7 @@ class TestGithubDriver(ZuulTestCase):
|
||||
# pipeline merges the pull request on second run of merge
|
||||
# first merge failed on 405 Method Not Allowed error
|
||||
self.fake_github.merge_not_allowed_count = 1
|
||||
C = self.fake_github.openFakePullRequest('org/project', 'master')
|
||||
C = self.fake_github.openFakePullRequest('org/project', 'master', 'C')
|
||||
self.fake_github.emitEvent(C.getCommentAddedEvent('merge me'))
|
||||
self.waitUntilSettled()
|
||||
self.assertTrue(C.is_merged)
|
||||
@@ -260,7 +260,180 @@ class TestGithubDriver(ZuulTestCase):
|
||||
# pipeline does not merge the pull request
|
||||
# merge failed on 405 Method Not Allowed error - twice
|
||||
self.fake_github.merge_not_allowed_count = 2
|
||||
D = self.fake_github.openFakePullRequest('org/project', 'master')
|
||||
D = self.fake_github.openFakePullRequest('org/project', 'master', 'D')
|
||||
self.fake_github.emitEvent(D.getCommentAddedEvent('merge me'))
|
||||
self.waitUntilSettled()
|
||||
self.assertFalse(D.is_merged)
|
||||
|
||||
@simple_layout('layouts/dependent-github.yaml', driver='github')
|
||||
def test_parallel_changes(self):
|
||||
"Test that changes are tested in parallel and merged in series"
|
||||
|
||||
self.executor_server.hold_jobs_in_build = True
|
||||
A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
|
||||
B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
|
||||
C = self.fake_github.openFakePullRequest('org/project', 'master', 'C')
|
||||
|
||||
self.fake_github.emitEvent(A.addLabel('merge'))
|
||||
self.fake_github.emitEvent(B.addLabel('merge'))
|
||||
self.fake_github.emitEvent(C.addLabel('merge'))
|
||||
|
||||
self.waitUntilSettled()
|
||||
self.assertEqual(len(self.builds), 1)
|
||||
self.assertEqual(self.builds[0].name, 'project-merge')
|
||||
self.assertTrue(self.builds[0].hasChanges(A))
|
||||
|
||||
self.executor_server.release('.*-merge')
|
||||
self.waitUntilSettled()
|
||||
self.assertEqual(len(self.builds), 3)
|
||||
self.assertEqual(self.builds[0].name, 'project-test1')
|
||||
self.assertTrue(self.builds[0].hasChanges(A))
|
||||
self.assertEqual(self.builds[1].name, 'project-test2')
|
||||
self.assertTrue(self.builds[1].hasChanges(A))
|
||||
self.assertEqual(self.builds[2].name, 'project-merge')
|
||||
self.assertTrue(self.builds[2].hasChanges(A, B))
|
||||
|
||||
self.executor_server.release('.*-merge')
|
||||
self.waitUntilSettled()
|
||||
self.assertEqual(len(self.builds), 5)
|
||||
self.assertEqual(self.builds[0].name, 'project-test1')
|
||||
self.assertTrue(self.builds[0].hasChanges(A))
|
||||
self.assertEqual(self.builds[1].name, 'project-test2')
|
||||
self.assertTrue(self.builds[1].hasChanges(A))
|
||||
|
||||
self.assertEqual(self.builds[2].name, 'project-test1')
|
||||
self.assertTrue(self.builds[2].hasChanges(A))
|
||||
self.assertEqual(self.builds[3].name, 'project-test2')
|
||||
self.assertTrue(self.builds[3].hasChanges(A, B))
|
||||
|
||||
self.assertEqual(self.builds[4].name, 'project-merge')
|
||||
self.assertTrue(self.builds[4].hasChanges(A, B, C))
|
||||
|
||||
self.executor_server.release('.*-merge')
|
||||
self.waitUntilSettled()
|
||||
self.assertEqual(len(self.builds), 6)
|
||||
self.assertEqual(self.builds[0].name, 'project-test1')
|
||||
self.assertTrue(self.builds[0].hasChanges(A))
|
||||
self.assertEqual(self.builds[1].name, 'project-test2')
|
||||
self.assertTrue(self.builds[1].hasChanges(A))
|
||||
|
||||
self.assertEqual(self.builds[2].name, 'project-test1')
|
||||
self.assertTrue(self.builds[2].hasChanges(A, B))
|
||||
self.assertEqual(self.builds[3].name, 'project-test2')
|
||||
self.assertTrue(self.builds[3].hasChanges(A, B))
|
||||
|
||||
self.assertEqual(self.builds[4].name, 'project-test1')
|
||||
self.assertTrue(self.builds[4].hasChanges(A, B, C))
|
||||
self.assertEqual(self.builds[5].name, 'project-test2')
|
||||
self.assertTrue(self.builds[5].hasChanges(A, B, C))
|
||||
|
||||
all_builds = self.builds[:]
|
||||
self.release(all_builds[2])
|
||||
self.release(all_builds[3])
|
||||
self.waitUntilSettled()
|
||||
self.assertFalse(A.is_merged)
|
||||
self.assertFalse(B.is_merged)
|
||||
self.assertFalse(C.is_merged)
|
||||
|
||||
self.release(all_builds[0])
|
||||
self.release(all_builds[1])
|
||||
self.waitUntilSettled()
|
||||
self.assertTrue(A.is_merged)
|
||||
self.assertTrue(B.is_merged)
|
||||
self.assertFalse(C.is_merged)
|
||||
|
||||
self.executor_server.hold_jobs_in_build = False
|
||||
self.executor_server.release()
|
||||
self.waitUntilSettled()
|
||||
self.assertEqual(len(self.builds), 0)
|
||||
self.assertEqual(len(self.history), 9)
|
||||
self.assertTrue(C.is_merged)
|
||||
|
||||
self.assertNotIn('merge', A.labels)
|
||||
self.assertNotIn('merge', B.labels)
|
||||
self.assertNotIn('merge', C.labels)
|
||||
|
||||
@simple_layout('layouts/dependent-github.yaml', driver='github')
|
||||
def test_failed_changes(self):
|
||||
"Test that a change behind a failed change is retested"
|
||||
self.executor_server.hold_jobs_in_build = True
|
||||
|
||||
A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
|
||||
B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
|
||||
|
||||
self.executor_server.failJob('project-test1', A)
|
||||
|
||||
self.fake_github.emitEvent(A.addLabel('merge'))
|
||||
self.fake_github.emitEvent(B.addLabel('merge'))
|
||||
self.waitUntilSettled()
|
||||
|
||||
self.executor_server.release('.*-merge')
|
||||
self.waitUntilSettled()
|
||||
|
||||
self.executor_server.hold_jobs_in_build = False
|
||||
self.executor_server.release()
|
||||
|
||||
self.waitUntilSettled()
|
||||
# It's certain that the merge job for change 2 will run, but
|
||||
# the test1 and test2 jobs may or may not run.
|
||||
self.assertTrue(len(self.history) > 6)
|
||||
self.assertFalse(A.is_merged)
|
||||
self.assertTrue(B.is_merged)
|
||||
self.assertNotIn('merge', A.labels)
|
||||
self.assertNotIn('merge', B.labels)
|
||||
|
||||
@simple_layout('layouts/dependent-github.yaml', driver='github')
|
||||
def test_failed_change_at_head(self):
|
||||
"Test that if a change at the head fails, jobs behind it are canceled"
|
||||
|
||||
self.executor_server.hold_jobs_in_build = True
|
||||
A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
|
||||
B = self.fake_github.openFakePullRequest('org/project', 'master', 'B')
|
||||
C = self.fake_github.openFakePullRequest('org/project', 'master', 'C')
|
||||
|
||||
self.executor_server.failJob('project-test1', A)
|
||||
|
||||
self.fake_github.emitEvent(A.addLabel('merge'))
|
||||
self.fake_github.emitEvent(B.addLabel('merge'))
|
||||
self.fake_github.emitEvent(C.addLabel('merge'))
|
||||
|
||||
self.waitUntilSettled()
|
||||
|
||||
self.assertEqual(len(self.builds), 1)
|
||||
self.assertEqual(self.builds[0].name, 'project-merge')
|
||||
self.assertTrue(self.builds[0].hasChanges(A))
|
||||
|
||||
self.executor_server.release('.*-merge')
|
||||
self.waitUntilSettled()
|
||||
self.executor_server.release('.*-merge')
|
||||
self.waitUntilSettled()
|
||||
self.executor_server.release('.*-merge')
|
||||
self.waitUntilSettled()
|
||||
|
||||
self.assertEqual(len(self.builds), 6)
|
||||
self.assertEqual(self.builds[0].name, 'project-test1')
|
||||
self.assertEqual(self.builds[1].name, 'project-test2')
|
||||
self.assertEqual(self.builds[2].name, 'project-test1')
|
||||
self.assertEqual(self.builds[3].name, 'project-test2')
|
||||
self.assertEqual(self.builds[4].name, 'project-test1')
|
||||
self.assertEqual(self.builds[5].name, 'project-test2')
|
||||
|
||||
self.release(self.builds[0])
|
||||
self.waitUntilSettled()
|
||||
|
||||
# project-test2, project-merge for B
|
||||
self.assertEqual(len(self.builds), 2)
|
||||
self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 4)
|
||||
|
||||
self.executor_server.hold_jobs_in_build = False
|
||||
self.executor_server.release()
|
||||
self.waitUntilSettled()
|
||||
|
||||
self.assertEqual(len(self.builds), 0)
|
||||
self.assertEqual(len(self.history), 15)
|
||||
self.assertFalse(A.is_merged)
|
||||
self.assertTrue(B.is_merged)
|
||||
self.assertTrue(C.is_merged)
|
||||
self.assertNotIn('merge', A.labels)
|
||||
self.assertNotIn('merge', B.labels)
|
||||
self.assertNotIn('merge', C.labels)
|
||||
|
||||
@@ -293,6 +293,19 @@ class GithubConnection(BaseConnection):
|
||||
owner, proj = project_name.split('/')
|
||||
return self.github.pull_request(owner, proj, number).as_dict()
|
||||
|
||||
def canMerge(self, change, allow_needs):
|
||||
# This API call may get a false (null) while GitHub is calculating
|
||||
# if it can merge. The github3.py library will just return that as
|
||||
# false. This could lead to false negatives.
|
||||
# Additionally, this only checks if the PR code could merge
|
||||
# cleanly to the target branch. It does not evaluate any branch
|
||||
# protection merge requirements (such as reviews and status states)
|
||||
# At some point in the future this may be available through the API
|
||||
# or we can fetch the branch protection settings and evaluate within
|
||||
# Zuul whether or not those protections have been met
|
||||
# For now, just send back a True value.
|
||||
return True
|
||||
|
||||
def commentPull(self, project, pr_number, message):
|
||||
owner, proj = project.split('/')
|
||||
repository = self.github.repository(owner, proj)
|
||||
|
||||
@@ -38,11 +38,18 @@ class GithubSource(BaseSource):
|
||||
|
||||
def isMerged(self, change, head=None):
|
||||
"""Determine if change is merged."""
|
||||
raise NotImplementedError()
|
||||
if not change.number:
|
||||
# Not a pull request, considering merged.
|
||||
return True
|
||||
return change.is_merged
|
||||
|
||||
def canMerge(self, change, allow_needs):
|
||||
"""Determine if change can merge."""
|
||||
raise NotImplementedError()
|
||||
|
||||
if not change.number:
|
||||
# Not a pull request, considering merged.
|
||||
return True
|
||||
return self.connection.canMerge(change, allow_needs)
|
||||
|
||||
def postConfig(self):
|
||||
"""Called after configuration has been processed."""
|
||||
|
||||
Reference in New Issue
Block a user