summaryrefslogtreecommitdiff
path: root/zuul/driver/github
diff options
context:
space:
mode:
authorTobias Henkel <tobias.henkel@bmw.de>2020-09-15 18:33:12 +0200
committerTobias Henkel <tobias.henkel@bmw.de>2020-11-04 08:52:28 +0100
commitba6d86ada2960e1aca8bb1a81321e013027fa5b4 (patch)
tree918d0fee0b4dc67ba06044df193c58950b62f53a /zuul/driver/github
parent418bf6b462db1286e856cb562c9c8ffcd118d080 (diff)
downloadzuul-ba6d86ada2960e1aca8bb1a81321e013027fa5b4.tar.gz
Save superfluous api requests in check run reporting
When reporting the check run result zuul is currently doing four github api requests: 1. Get repository 2. Get head commit of pr 3. Get check runs of head commit 4. (optional) Create initial version of check run in case start reporting is disabled 5. Update check run that has been created in start reporting The first three requests are basically unneeded if we craft a direct PATCH request and remember the check run id that has been created in the start reporting. This is needed since those run in the critical path of the event processing and can cause large event processing delays in a very busy zuul system. Change-Id: I55df1cc28279bb6923e51686dde8809421486c6a
Diffstat (limited to 'zuul/driver/github')
-rw-r--r--zuul/driver/github/githubconnection.py169
-rw-r--r--zuul/driver/github/githubreporter.py9
2 files changed, 74 insertions, 104 deletions
diff --git a/zuul/driver/github/githubconnection.py b/zuul/driver/github/githubconnection.py
index 1ef5f9a8d..9e5c2bbc4 100644
--- a/zuul/driver/github/githubconnection.py
+++ b/zuul/driver/github/githubconnection.py
@@ -1988,13 +1988,27 @@ class GithubConnection(BaseConnection):
pull_request.remove_label(label)
log.debug("Removed label %s from %s#%s", label, proj, pr_number)
+ def _create_or_update_check(self, github, project_name, check_run_id,
+ **kwargs):
+ if check_run_id:
+ # Update an existing check run
+ url = github.session.build_url(
+ 'repos', project_name, 'check-runs', str(check_run_id))
+ resp = github.session.patch(url, json=kwargs)
+ else:
+ # Create a new check run
+ url = github.session.build_url(
+ 'repos', project_name, 'check-runs')
+ resp = github.session.post(url, json=kwargs)
+ resp.raise_for_status()
+ return resp.json().get('id')
+
def updateCheck(self, project, pr_number, sha, status, completed, context,
details_url, message, file_comments, external_id,
- zuul_event_id=None):
+ zuul_event_id=None, check_run_id=None):
log = get_annotated_logger(self.log, zuul_event_id)
github = self.getGithubClient(project, zuul_event_id=zuul_event_id)
self._append_accept_header(github, PREVIEW_CHECKS_ACCEPT)
- owner, proj = project.split("/")
# Always provide an empty list of actions by default
actions = []
@@ -2018,7 +2032,7 @@ class GithubConnection(BaseConnection):
context
)
)
- return errors
+ return None, errors
output = {"title": "Summary", "summary": message}
@@ -2041,83 +2055,34 @@ class GithubConnection(BaseConnection):
# conclusion, as the status will always be "completed".
conclusion = status
- # Unless something went wrong during the start reporting of this
- # change (e.g. the check_run creation failed), there should already
- # be a check_run available. If not we will create one.
- check_runs = []
-
- repository = github.repository(owner, proj)
- try:
- check_runs = [
- c for c in repository.commit(sha).check_runs()
- if c.name == context
- ]
- except github3.exceptions.GitHubException as exc:
- log.error(
- "Could not retrieve existing check runs for %s#%s on "
- "sha %s: %s",
- project, pr_number, sha, str(exc),
- )
-
- if not check_runs:
- log.debug(
- "Could not find check run %s for %s#%s on sha %s. "
- "Creating a new one",
- context, project, pr_number, sha,
+ if not check_run_id:
+ log.debug("Could not find check run %s for %s#%s on sha %s. "
+ "Creating a new one", context, project, pr_number,
+ sha)
+ action = 'create'
+ arguments = dict(
+ name=context,
+ head_sha=sha,
+ conclusion=conclusion,
+ completed_at=completed_at,
+ output=output,
+ details_url=details_url,
+ external_id=external_id,
+ actions=actions,
)
-
- try:
- check_run = repository.create_check_run(
- name=context,
- head_sha=sha,
- conclusion=conclusion,
- completed_at=completed_at,
- output=output,
- details_url=details_url,
- external_id=external_id,
- actions=actions,
- )
- except github3.exceptions.GitHubException as exc:
- # TODO (felix): Should we retry the check_run creation?
- log.error(
- "Failed to create check run %s for %s#%s on sha %s: "
- "%s",
- context, project, pr_number, sha, str(exc)
- )
- errors.append(
- "Failed to create check run {}: {}".format(
- context, str(exc)
- )
- )
else:
- check_run = check_runs[0]
- log.debug(
- "Updating existing check run %s for %s#%s on sha %s "
- "with status %s",
- context, project, pr_number, sha, status,
+ log.debug("Updating existing check run %s for %s#%s on sha %s "
+ "with status %s", context, project, pr_number, sha,
+ status)
+ action = 'update'
+ arguments = dict(
+ conclusion=conclusion,
+ completed_at=completed_at,
+ output=output,
+ details_url=details_url,
+ external_id=external_id,
+ actions=actions,
)
-
- try:
- check_run.update(
- conclusion=conclusion,
- completed_at=completed_at,
- output=output,
- details_url=details_url,
- external_id=external_id,
- actions=actions,
- )
- except github3.exceptions.GitHubException as exc:
- log.error(
- "Failed to update check run %s for %s#%s on sha %s: "
- "%s",
- context, project, pr_number, sha, str(exc),
- )
- errors.append(
- "Failed to update check run {}: {}".format(
- context, str(exc)
- )
- )
-
else:
# Add an abort/dequeue action to running check runs
actions.append(
@@ -2132,35 +2097,33 @@ class GithubConnection(BaseConnection):
}
)
- # Report the start of a check run
- try:
- data = dict(
- name=context,
- head_sha=sha,
- status=status,
- output=output,
- details_url=details_url,
- external_id=external_id,
- actions=actions,
- )
+ action = 'create'
+ arguments = dict(
+ name=context,
+ head_sha=sha,
+ status=status,
+ output=output,
+ details_url=details_url,
+ external_id=external_id,
+ actions=actions,
+ )
- url = github.session.build_url('repos', project,
- 'check-runs')
- resp = github.session.post(url, json=data)
- resp.raise_for_status()
+ # Create/update the check run
+ try:
+ check_run_id = self._create_or_update_check(
+ github,
+ project,
+ check_run_id,
+ **arguments,
+ )
- except requests.exceptions.HTTPError as exc:
- log.error(
- "Failed to create check run %s for %s#%s on sha %s: %s",
- context, project, pr_number, sha, str(exc),
- )
- errors.append(
- "Failed to update check run {}: {}".format(
- context, str(exc)
- )
- )
+ except requests.exceptions.HTTPError as exc:
+ log.error("Failed to %s check run %s for %s#%s on sha %s: %s",
+ action, context, project, pr_number, sha, str(exc))
+ errors.append("Failed to {} check run {}: {}".format(
+ action, context, str(exc)))
- return errors
+ return check_run_id, errors
def _buildAnnotationsFromComments(self, file_comments):
annotations = []
diff --git a/zuul/driver/github/githubreporter.py b/zuul/driver/github/githubreporter.py
index b2487d61e..0925b50d7 100644
--- a/zuul/driver/github/githubreporter.py
+++ b/zuul/driver/github/githubreporter.py
@@ -245,7 +245,8 @@ class GithubReporter(BaseReporter):
}
)
- return self.connection.updateCheck(
+ state = item.dynamic_state[self.connection.connection_name]
+ check_run_id, errors = self.connection.updateCheck(
project,
pr_number,
sha,
@@ -257,8 +258,14 @@ class GithubReporter(BaseReporter):
file_comments,
external_id,
zuul_event_id=item.event,
+ check_run_id=state.get('check_run_id')
)
+ if check_run_id:
+ state['check_run_id'] = check_run_id
+
+ return errors
+
def setLabels(self, item):
log = get_annotated_logger(self.log, item.event)
project = item.change.project.name