Optimize GitHub requests on PR merge

Using github3py for merging a pull request there is always one extra
request to get the pull request before the merge can be done due to the
github3py data model.

Since merging is done synchronously in in the scheduler main loop, it
makes sense to save the extra API request by building and executing the
merge call directly.

Change-Id: I48dbb5fc1b7e7dec4cb09c779b9661d82935d9df
This commit is contained in:
Simon Westphahl 2020-09-21 09:54:58 +02:00
parent cb27f37153
commit eed5820fb3
2 changed files with 44 additions and 23 deletions

View File

@ -506,24 +506,6 @@ class FakePull(object):
# with the head_sha as the only commit
return [self.head]
def merge(self, commit_message=None, sha=None, merge_method=None):
conn = self._fake_pull_request.github
pr = self._fake_pull_request
# record that this got reported
conn.github_data.reports.append(
(pr.project, pr.number, 'merge', merge_method))
if conn.merge_failure:
raise Exception('Unknown merge failure')
if conn.merge_not_allowed_count > 0:
conn.merge_not_allowed_count -= 1
resp = ErrorResponse()
resp.status_code = 403
resp.message = 'Merge not allowed'
raise github3.exceptions.MethodNotAllowed(resp)
pr.setMerged(commit_message)
return True
def as_dict(self):
pr = self._fake_pull_request
connection = pr.github
@ -654,6 +636,31 @@ class FakeGithubSession(object):
return FakeResponse(None, 404)
def put(self, url, data=None, headers=None, params=None, json=None):
# Handle pull request merge
match = re.match(r'.+/repos/(.+)/pulls/(\d+)/merge$', url)
if match:
project, pr_number = match.groups()
project = urllib.parse.unquote(project)
pr = self.client._data.pull_requests[int(pr_number)]
conn = pr.github
# record that this got reported
self.client._data.reports.append(
(pr.project, pr.number, 'merge', json["merge_method"]))
if conn.merge_failure:
raise Exception('Unknown merge failure')
if conn.merge_not_allowed_count > 0:
conn.merge_not_allowed_count -= 1
resp = ErrorResponse()
resp.status_code = 403
resp.message = 'Merge not allowed'
raise github3.exceptions.MethodNotAllowed(resp)
pr.setMerged(json["commit_message"])
return FakeResponse({"merged": True}, 200)
return FakeResponse(None, 404)
def get_repo(self, request, params=None):
org, project, request = request.split('/', 2)
project_name = '{}/{}'.format(org, project)

View File

@ -1856,17 +1856,31 @@ class GithubConnection(BaseConnection):
method='merge', zuul_event_id=None):
log = get_annotated_logger(self.log, zuul_event_id)
github = self.getGithubClient(project, zuul_event_id=zuul_event_id)
owner, proj = project.split('/')
pull_request = github.pull_request(owner, proj, pr_number)
url = github.session.build_url("repos", project, "pulls",
str(pr_number), "merge")
payload = {
"merge_method": method,
}
if sha:
payload["sha"] = sha
if commit_message:
payload["commit_message"] = commit_message
try:
result = pull_request.merge(commit_message=commit_message, sha=sha,
merge_method=method)
resp = github.session.put(url, json=payload)
resp.raise_for_status()
data = resp.json()
if not data:
result = False
else:
result = data["merged"]
except Exception as e:
raise MergeFailure('Pull request merge failed: %s' % e)
if not result:
raise MergeFailure('Pull request was not merged')
log.debug("Merged PR %s/%s#%s", owner, proj, pr_number)
log.debug("Merged PR %s#%s", project, pr_number)
def _getCommit(self, repository, sha, retries=5):
try: