Handle draft pull requests in canMerge
Github now supports draft pull requests which are blocked from merging by github. Currently those can end up in a gate loop if all requirements for the gate pipeline are fulfilled except for un-drafting it. Zuul needs to handle those in the canMerge check in order to handle them correctly. Change-Id: Ie9164ad5127d19ca3d75660b9718979da7cc344c
This commit is contained in:
parent
2b4770e8cc
commit
e78a31e85b
|
@ -1503,7 +1503,7 @@ class FakeGithubPullRequest(object):
|
|||
|
||||
def __init__(self, github, number, project, branch,
|
||||
subject, upstream_root, files=[], number_of_commits=1,
|
||||
writers=[], body=None):
|
||||
writers=[], body=None, draft=False):
|
||||
"""Creates a new PR with several commits.
|
||||
Sends an event about opened PR."""
|
||||
self.github = github
|
||||
|
@ -1513,6 +1513,7 @@ class FakeGithubPullRequest(object):
|
|||
self.branch = branch
|
||||
self.subject = subject
|
||||
self.body = body
|
||||
self.draft = draft
|
||||
self.number_of_commits = 0
|
||||
self.upstream_root = upstream_root
|
||||
self.files = []
|
||||
|
@ -1887,11 +1888,11 @@ class FakeGithubConnection(githubconnection.GithubConnection):
|
|||
self.zuul_web_port = port
|
||||
|
||||
def openFakePullRequest(self, project, branch, subject, files=[],
|
||||
body=None):
|
||||
body=None, draft=False):
|
||||
self.pr_number += 1
|
||||
pull_request = FakeGithubPullRequest(
|
||||
self, self.pr_number, project, branch, subject, self.upstream_root,
|
||||
files=files, body=body)
|
||||
files=files, body=body, draft=draft)
|
||||
self.pull_requests[self.pr_number] = pull_request
|
||||
return pull_request
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import re
|
|||
import time
|
||||
|
||||
from requests import HTTPError
|
||||
from requests.structures import CaseInsensitiveDict
|
||||
|
||||
FAKE_BASE_URL = 'https://example.com/api/v3/'
|
||||
|
||||
|
@ -380,6 +381,7 @@ class FakePull(object):
|
|||
},
|
||||
'ref': pr.branch,
|
||||
},
|
||||
'draft': pr.draft,
|
||||
'mergeable': True,
|
||||
'state': pr.state,
|
||||
'head': {
|
||||
|
@ -421,6 +423,7 @@ class FakeGithubSession(object):
|
|||
|
||||
def __init__(self, data):
|
||||
self._data = data
|
||||
self.headers = CaseInsensitiveDict()
|
||||
|
||||
def build_url(self, *args):
|
||||
fakepath = '/'.join(args)
|
||||
|
|
|
@ -613,6 +613,18 @@ class TestGithubDriver(ZuulTestCase):
|
|||
self.assertEqual(len(D.comments), 1)
|
||||
self.assertEqual(D.comments[0], 'Merge failed')
|
||||
|
||||
@simple_layout('layouts/dependent-github.yaml', driver='github')
|
||||
def test_draft_pr(self):
|
||||
# pipeline merges the pull request on success
|
||||
A = self.fake_github.openFakePullRequest('org/project', 'master',
|
||||
'PR title', draft=True)
|
||||
self.fake_github.emitEvent(A.addLabel('merge'))
|
||||
self.waitUntilSettled()
|
||||
|
||||
# A draft pull request must not enter the gate
|
||||
self.assertFalse(A.is_merged)
|
||||
self.assertHistory([])
|
||||
|
||||
@simple_layout('layouts/reporting-multiple-github.yaml', driver='github')
|
||||
def test_reporting_multiple_github(self):
|
||||
project = 'org/project1'
|
||||
|
|
|
@ -45,6 +45,7 @@ from zuul.driver.github.githubmodel import PullRequest, GithubTriggerEvent
|
|||
|
||||
GITHUB_BASE_URL = 'https://api.github.com'
|
||||
PREVIEW_JSON_ACCEPT = 'application/vnd.github.machine-man-preview+json'
|
||||
PREVIEW_DRAFT_ACCEPT = 'application/vnd.github.shadow-cat-preview+json'
|
||||
|
||||
|
||||
def _sign_request(body, secret):
|
||||
|
@ -868,6 +869,15 @@ class GithubConnection(BaseConnection):
|
|||
if app_key:
|
||||
self.app_key = app_key
|
||||
|
||||
@staticmethod
|
||||
def _append_accept_header(github, value):
|
||||
old_header = github.session.headers.get('Accept', None)
|
||||
if old_header:
|
||||
new_value = '%s,%s' % (old_header, value)
|
||||
else:
|
||||
new_value = value
|
||||
github.session.headers['Accept'] = new_value
|
||||
|
||||
def _get_app_auth_headers(self):
|
||||
now = datetime.datetime.now(utc)
|
||||
expiry = now + datetime.timedelta(minutes=5)
|
||||
|
@ -1414,10 +1424,25 @@ class GithubConnection(BaseConnection):
|
|||
# conflicts which would block merging finally will be detected by
|
||||
# the zuul-mergers anyway.
|
||||
|
||||
log = get_annotated_logger(self.log, event)
|
||||
|
||||
github = self.getGithubClient(change.project.name, zuul_event_id=event)
|
||||
|
||||
# Append accept header so we get the draft status
|
||||
self._append_accept_header(github, PREVIEW_DRAFT_ACCEPT)
|
||||
|
||||
owner, proj = change.project.name.split('/')
|
||||
pull = github.pull_request(owner, proj, change.number)
|
||||
|
||||
# If the PR is a draft it cannot be merged.
|
||||
# TODO: This uses the dict instead of the pull object since github3.py
|
||||
# has no support for draft PRs yet. Replace this with pull.draft when
|
||||
# support has been added.
|
||||
# https://github.com/sigmavirus24/github3.py/issues/926
|
||||
if pull.as_dict().get('draft', False):
|
||||
log.debug('Change %s can not merge because it is a draft', change)
|
||||
return False
|
||||
|
||||
protection = self._getBranchProtection(
|
||||
change.project.name, change.branch, zuul_event_id=event)
|
||||
|
||||
|
|
Loading…
Reference in New Issue