Retry queries for commits
When a pull_request event arrives we also get the commit statuses which are attached to the commit object. Sometimes the commit is not yet queryable and we get a 404 [1]. In this case we need to retry the query. In the future we probably want to use that as a feedback mechanism of a dynamic event delay. [1] Trace 2018-06-13 11:49:11,881 ERROR zuul.GithubEventConnector: Exception moving GitHub event: Traceback (most recent call last): File "/usr/lib/python3.6/site-packages/zuul/driver/github/githubconnection.py", line 391, in run self._handleEvent() File "/usr/lib/python3.6/site-packages/zuul/driver/github/githubconnection.py", line 226, in _handleEvent refresh=True) File "/usr/lib/python3.6/site-packages/zuul/driver/github/githubconnection.py", line 751, in _getChange self._updateChange(change) File "/usr/lib/python3.6/site-packages/zuul/driver/github/githubconnection.py", line 837, in _updateChange change.patchset) File "/usr/lib/python3.6/site-packages/zuul/driver/github/githubconnection.py", line 1226, in _get_statuses for status in self.getCommitStatuses(project.name, sha): File "/usr/lib/python3.6/site-packages/zuul/driver/github/githubconnection.py", line 1171, in getCommitStatuses commit = repository.commit(sha) File "/usr/lib/python3.6/site-packages/github3/repos/repo.py", line 342, in commit json = self._json(self._get(url), 200) File "/usr/lib/python3.6/site-packages/github3/models.py", line 156, in _json raise exceptions.error_for(response) github3.exceptions.NotFoundError: 404 Not Found Change-Id: I5cc6d95ed18148657d9e5a8d132a8e43f385771d
This commit is contained in:
parent
bc136cb40e
commit
f312bda118
|
@ -14,6 +14,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import github3.exceptions
|
||||
import re
|
||||
|
||||
FAKE_BASE_URL = 'https://example.com/api/v3/'
|
||||
|
@ -82,6 +83,9 @@ class FakeRepository(object):
|
|||
self.data = data
|
||||
self.name = name
|
||||
|
||||
# fail the next commit requests with 404
|
||||
self.fail_not_found = 0
|
||||
|
||||
def branches(self, protected=False):
|
||||
if protected:
|
||||
# simulate there is no protected branch
|
||||
|
@ -121,6 +125,25 @@ class FakeRepository(object):
|
|||
commit.set_status(state, url, description, context, user)
|
||||
|
||||
def commit(self, sha):
|
||||
|
||||
if self.fail_not_found > 0:
|
||||
self.fail_not_found -= 1
|
||||
|
||||
class Response:
|
||||
status_code = 0
|
||||
message = ''
|
||||
|
||||
def json(self):
|
||||
return {
|
||||
'message': self.message
|
||||
}
|
||||
|
||||
resp = Response()
|
||||
resp.status_code = 404
|
||||
resp.message = 'Not Found'
|
||||
|
||||
raise github3.exceptions.NotFoundError(resp)
|
||||
|
||||
commit = self._commits.get(sha, None)
|
||||
if commit is None:
|
||||
commit = FakeCommit(sha)
|
||||
|
|
|
@ -1000,6 +1000,37 @@ class TestGithubDriver(ZuulTestCase):
|
|||
self.assertEquals('https://github.com/org/project/pull/1',
|
||||
job2_params['zuul']['items'][0]['change_url'])
|
||||
|
||||
@simple_layout('layouts/basic-github.yaml', driver='github')
|
||||
def test_pull_commit_race(self):
|
||||
"""Test graceful handling of delayed availability of commits"""
|
||||
|
||||
github = self.fake_github.getGithubClient('org/project')
|
||||
repo = github.repo_from_project('org/project')
|
||||
repo.fail_not_found = 1
|
||||
|
||||
A = self.fake_github.openFakePullRequest('org/project', 'master', 'A')
|
||||
self.fake_github.emitEvent(A.getPullRequestOpenedEvent())
|
||||
self.waitUntilSettled()
|
||||
|
||||
self.assertEqual('SUCCESS',
|
||||
self.getJobFromHistory('project-test1').result)
|
||||
self.assertEqual('SUCCESS',
|
||||
self.getJobFromHistory('project-test2').result)
|
||||
|
||||
job = self.getJobFromHistory('project-test2')
|
||||
zuulvars = job.parameters['zuul']
|
||||
self.assertEqual(str(A.number), zuulvars['change'])
|
||||
self.assertEqual(str(A.head_sha), zuulvars['patchset'])
|
||||
self.assertEqual('master', zuulvars['branch'])
|
||||
self.assertEqual(1, len(A.comments))
|
||||
self.assertThat(
|
||||
A.comments[0],
|
||||
MatchesRegex(r'.*\[project-test1 \]\(.*\).*', re.DOTALL))
|
||||
self.assertThat(
|
||||
A.comments[0],
|
||||
MatchesRegex(r'.*\[project-test2 \]\(.*\).*', re.DOTALL))
|
||||
self.assertEqual(2, len(self.history))
|
||||
|
||||
|
||||
class TestGithubUnprotectedBranches(ZuulTestCase):
|
||||
config_file = 'zuul-github-driver.conf'
|
||||
|
|
|
@ -1322,11 +1322,24 @@ class GithubConnection(BaseConnection):
|
|||
if not result:
|
||||
raise Exception('Pull request was not merged')
|
||||
|
||||
def _getCommit(self, repository, sha, retries=5):
|
||||
try:
|
||||
return repository.commit(sha)
|
||||
except github3.exceptions.NotFoundError:
|
||||
self.log.warning("Commit %s of project %s returned None",
|
||||
sha, repository.name)
|
||||
if retries <= 0:
|
||||
raise
|
||||
time.sleep(1)
|
||||
return self._getCommit(repository, sha, retries - 1)
|
||||
|
||||
def getCommitStatuses(self, project, sha):
|
||||
github = self.getGithubClient(project)
|
||||
owner, proj = project.split('/')
|
||||
repository = github.repository(owner, proj)
|
||||
commit = repository.commit(sha)
|
||||
|
||||
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()]
|
||||
|
|
Loading…
Reference in New Issue