implement gitlab project get/create/delete

This commit is contained in:
Loic Dachary 2021-01-28 00:05:19 +01:00
parent b0bf115f64
commit 60ba328469
No known key found for this signature in database
GPG Key ID: 992D23B392F9E4F2
5 changed files with 116 additions and 20 deletions

View File

@ -4,6 +4,8 @@ import os
import requests
import time
from fedeproxy.common.retry import retry
logger = logging.getLogger(__name__)
@ -38,8 +40,8 @@ class GitLab(object):
def set_token(self, token):
self.s.headers['Authorization'] = f'Bearer {token}'
def get_namespace(self, user):
r = self.s.get(self.s.api + '/namespaces?search=' + user)
def get_namespace_id(self, name):
r = self.s.get(self.s.api + '/namespaces?search=' + name)
r.raise_for_status()
return r.json()[0]['id']
@ -57,23 +59,47 @@ class GitLab(object):
user = r.json()
return self.is_member_of_group(group, user['username'])
def recreate_project(self, user, project):
namespace_id = self.get_namespace(user)
r = self.s.get(self.s.api + '/projects/' + user + '%2F' + project)
if r.status_code == requests.codes.ok:
r = self.s.delete(self.s.api + '/projects/' + user + '%2F' + project)
r.raise_for_status()
for _ in range(10):
r = self.s.post(self.s.api + '/projects', data={
"name": project,
"namespace_id": int(namespace_id),
"visibility": "public",
})
time.sleep(5)
if r.status_code == 201:
break
print(str(r.text))
def project_delete(self, namespace, project):
info = self.project_get(namespace, project)
if info is None:
return False
r = self.s.delete(f'{self.s.api}/projects/{info["id"]}')
r.raise_for_status()
while self.project_get(namespace, project) is not None:
time.sleep(1)
return True
def project_get(self, namespace, project):
r = self.s.get(f'{self.s.api}/projects/{namespace}%2F{project}')
if r.status_code == requests.codes.ok:
return r.json()
else:
return None
class DeletionInProgress(Exception):
pass
@retry(DeletionInProgress, tries=5)
def _project_create(self, namespace, project):
namespace_id = self.get_namespace_id(namespace)
data = {
"name": project,
"namespace_id": int(namespace_id),
"visibility": "public",
}
r = self.s.post(f'{self.s.api}/projects', data=data)
if r.status_code == 201:
return r.json()
if r.status_code == 400 and 'still being deleted' in r.text:
raise GitLab.DeletionInProgress()
r.raise_for_status()
def project_create(self, namespace, project):
info = self.project_get(namespace, project)
if info is None:
return self._project_create(namespace, project)
else:
return info
def create_api_application(self, domain):
callbacks = [

29
fedeproxy/common/retry.py Normal file
View File

@ -0,0 +1,29 @@
import logging
import time
from functools import wraps
logger = logging.getLogger(__name__)
class RetryException(Exception):
pass
def retry(exceptions, tries=2, delay=1):
def deco_retry(f):
@wraps(f)
def f_retry(*args, **kwargs):
mtries, mdelay = tries + 1, delay
while mtries > 0:
try:
return f(*args, **kwargs)
except exceptions as e:
logger.info('%s: %s, Retrying in %s seconds...', f.__qualname__, e, mdelay)
if mtries == tries + 1:
logger.debug("", exc_info=True)
time.sleep(mdelay)
mtries -= 1
mdelay *= 2
raise RetryException("Number of retries exceeded for function " + f.__name__)
return f_retry
return deco_retry

2
tests/conftest.py Normal file
View File

@ -0,0 +1,2 @@
def pytest_configure(config):
config.addinivalue_line("markers", "gitlab: mark tests which require live GitLab instances")

View File

@ -5,8 +5,11 @@ from fedeproxy.common.gitlab import GitLab
@pytest.mark.gitlab
def test_recreate_project(tmpdir):
def test_create_project(tmpdir):
ip = os.environ.get('FEDEPROXY_IP', '0.0.0.0')
gitlab = GitLab(f'http://{ip}:8181')
gitlab.login('root', 'Wrobyak4')
gitlab.recreate_project('root', 'testproject')
gitlab.project_delete('root', 'testproject')
assert gitlab.project_get('root', 'testproject') is None
p = gitlab.project_create('root', 'testproject')
assert p['id'] == gitlab.project_create('root', 'testproject')['id']

View File

@ -0,0 +1,36 @@
import pytest
from enough.common import retry
def test_that_retry_works_on_simple_function():
@retry.retry(Exception)
def f():
return True
assert f()
def test_that_retry_fails():
@retry.retry(AssertionError)
def f():
assert 0
with pytest.raises(retry.RetryException):
f()
def test_that_retry_works_on_complex_function():
class C():
fail = 2
@retry.retry(Exception, tries=3)
def f(self):
self.fail -= 1
assert self.fail == 0
return True
c = C()
assert c.f()
assert c.fail == 0