util: Retry resolving git branches

When there's a temporary network issue, Pungi will fail to turn a branch
into a commit hash. This would abort the whole compose. Instead we
should just retry a few times.

Signed-off-by: Lubomír Sedlář <lsedlar@redhat.com>
This commit is contained in:
Lubomír Sedlář 2017-06-02 09:46:05 +02:00
parent 700106facf
commit 0cdf996e6e
2 changed files with 18 additions and 1 deletions

View File

@ -253,7 +253,7 @@ def resolve_git_url(url):
scheme = r.scheme.replace('git+', '') scheme = r.scheme.replace('git+', '')
baseurl = urlparse.urlunsplit((scheme, r.netloc, r.path, '', '')) baseurl = urlparse.urlunsplit((scheme, r.netloc, r.path, '', ''))
_, output = run(['git', 'ls-remote', baseurl, ref]) _, output = git_ls_remote(baseurl, ref)
lines = [line for line in output.split('\n') if line] lines = [line for line in output.split('\n') if line]
if len(lines) == 0: if len(lines) == 0:
@ -776,3 +776,8 @@ def retry(timeout=120, interval=30, wait_on=Exception):
time.sleep(interval) time.sleep(interval)
return inner return inner
return wrapper return wrapper
@retry(wait_on=RuntimeError)
def git_ls_remote(baseurl, ref):
return run(['git', 'ls-remote', baseurl, ref])

View File

@ -92,6 +92,18 @@ class TestGitRefResolver(unittest.TestCase):
['git', 'ls-remote', 'https://git.example.com/repo.git', 'refs/heads/my-branch']) ['git', 'ls-remote', 'https://git.example.com/repo.git', 'refs/heads/my-branch'])
self.assertIn('ref does not exist in remote repo', str(ctx.exception)) self.assertIn('ref does not exist in remote repo', str(ctx.exception))
@mock.patch('time.sleep')
@mock.patch('pungi.util.run')
def test_retry(self, run, sleep):
run.side_effect = [RuntimeError('Boom'), (0, 'CAFEBABE\tHEAD\n')]
url = util.resolve_git_url('https://git.example.com/repo.git?somedir#HEAD')
self.assertEqual(url, 'https://git.example.com/repo.git?somedir#CAFEBABE')
self.assertEqual(sleep.call_args_list, [mock.call(30)])
self.assertEqual(run.call_args_list,
[mock.call(['git', 'ls-remote', 'https://git.example.com/repo.git', 'HEAD'])] * 2)
class TestGetVariantData(unittest.TestCase): class TestGetVariantData(unittest.TestCase):
def test_get_simple(self): def test_get_simple(self):