Eliminate two github requests per _updateChange

When processing _updateChange we fetch the statuses of the commit. Due
the object model of Github3.py we currently get the repository
(request 1), then the commit (request 2) and finally the commit
statuses (request 3). However we already have all information needed
to directly perform the request 3. Further we're in any case only
using the json structure of the statuses so we can easily do a direct
request and avoid the first two. This essentially saves us two api
requests per incoming events.

Change-Id: I4185e15dcaf2b66bc1e6629e725dfd508368140a
This commit is contained in:
Tobias Henkel 2019-06-15 15:20:14 +02:00
parent 88f5423d4d
commit 6ee03a4408
No known key found for this signature in database
GPG Key ID: 03750DEC158E5FA2
2 changed files with 45 additions and 12 deletions

View File

@ -18,6 +18,7 @@ import github3.exceptions
import re
import time
from requests import HTTPError
FAKE_BASE_URL = 'https://example.com/api/v3/'
@ -89,6 +90,11 @@ class FakeCommit(object):
# the last status provided for a commit.
self._statuses.insert(0, status)
def get_url(self, path, params=None):
if path == 'statuses':
statuses = [s.as_dict() for s in self._statuses]
return FakeResponse(statuses)
def statuses(self):
return self._statuses
@ -192,6 +198,8 @@ class FakeRepository(object):
return self.get_url_branches(request, params=params)
if entity == 'collaborators':
return self.get_url_collaborators(request)
if entity == 'commits':
return self.get_url_commits(request, params=params)
else:
return None
@ -211,6 +219,28 @@ class FakeRepository(object):
branch = '/'.join(elements)
return self.get_url_branch(branch)
def get_url_commits(self, path, params=None):
if '/' in path:
sha, request = path.split('/', 1)
else:
sha = path
request = None
commit = self._commits.get(sha)
# Commits are created lazy so check if there is a PR with the correct
# head sha.
if commit is None:
pull_requests = [pr for pr in self.data.pull_requests.values()
if pr.head_sha == sha]
if pull_requests:
commit = FakeCommit(sha)
self._commits[sha] = commit
if not commit:
return FakeResponse({}, 404)
return commit.get_url(request, params=params)
def get_url_branch_list(self, params):
if params.get('protected') == 1:
exclude_unprotected = True
@ -378,6 +408,11 @@ class FakeResponse(object):
def json(self):
return self.data
def raise_for_status(self):
if 400 <= self.status_code < 600:
raise HTTPError('{} Something went wrong'.format(self.status_code),
response=self)
class FakeGithubSession(object):

View File

@ -1589,20 +1589,18 @@ class GithubConnection(BaseConnection):
time.sleep(1)
return self._getCommit(repository, sha, retries - 1)
def getCommitStatuses(self, project, sha, zuul_event_id=None):
def getCommitStatuses(self, project_name, sha, 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('/')
repository = github.repository(owner, proj)
github = self.getGithubClient(
project_name, zuul_event_id=zuul_event_id)
url = github.session.build_url('repos', project_name,
'commits', sha, 'statuses')
params = {'per_page': 100}
resp = github.session.get(url, params=params)
resp.raise_for_status()
commit = self._getCommit(repository, sha, 5)
# make a list out of the statuses so that we complete our
# API transaction
statuses = [status.as_dict() for status in commit.statuses()]
log.debug("Got commit statuses for sha %s on %s", sha, project)
return statuses
log.debug("Got commit statuses for sha %s on %s", sha, project_name)
return resp.json()
def setCommitStatus(self, project, sha, state, url='', description='',
context='', zuul_event_id=None):