Skip to content

Commit 2bbaeb3

Browse files
committed
Add basic gerrit support (repo cloning)
1 parent e80d990 commit 2bbaeb3

File tree

5 files changed

+264
-2
lines changed

5 files changed

+264
-2
lines changed

git_repo/services/ext/gerrit.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#!/usr/bin/env python
2+
3+
from ..service import register_target, RepositoryService
4+
5+
from gerritclient import client
6+
from gerritclient.error import HTTPError
7+
8+
@register_target('gerrit', 'gerrit')
9+
class GerritService(RepositoryService):
10+
fqdn = 'review.gerrithub.io'
11+
auth_type = 'basic'
12+
ssh_port = 29418
13+
_max_nested_namespaces = 99
14+
_min_nested_namespaces = 0
15+
ro_suffix = ''
16+
17+
def create_connection(self):
18+
self.connection = client.connect(self.url_ro, auth_type=self.auth_type,
19+
username=self._username, password=self._privatekey)
20+
self._session = self.connection.session
21+
22+
def connect(self):
23+
if not hasattr(self, 'connection'):
24+
self.create_connection()
25+
self.server_client = client.get_client('server', connection=self.connection)
26+
self.project_client = client.get_client('project', connection=self.connection)
27+
28+
try:
29+
self.server_client.get_version()
30+
except HTTPError as err:
31+
if not self._username or not self._privatekey:
32+
raise ConnectionError('Could not connect to Gerrit. '
33+
'Please configure .gitconfig '
34+
'with your gerrit username and HTTP password.') from err
35+
else:
36+
raise ConnectionError('Could not connect to Gerrit. '
37+
'Please check your configuration and try again.') from err
38+
39+
@classmethod
40+
def get_auth_token(self, login, password, prompt=None):
41+
# HTTP password is used as auth token
42+
return password
43+
44+
def load_configuration(self, c, hc=[]):
45+
super(GerritService, self).load_configuration(c, hc)
46+
self.ssh_port = c.get('ssh-port', self.ssh_port)
47+
self.auth_type = c.get('auth-type', self.auth_type)
48+
self.ro_suffix = c.get('ro-suffix', self.ro_suffix)
49+
50+
@property
51+
def session(self):
52+
if not hasattr(self, '_session'):
53+
self.create_connection()
54+
return self._session
55+
56+
@property
57+
def git_user(self):
58+
return self._username
59+
60+
@property
61+
def url_ro(self):
62+
'''Property that returns the HTTP URL of the service'''
63+
return self.build_url(self) + self.ro_suffix
64+
65+
@property
66+
def url_rw(self):
67+
return 'ssh://{}@{}:{}'.format(self.git_user, self.ssh_url, self.ssh_port)
68+
69+
def repo_name(self, namespace, repo):
70+
if namespace:
71+
return '{}/{}'.format(namespace, repo)
72+
else:
73+
return repo
74+
75+
def get_repository(self, namespace, repo):
76+
if namespace is not None:
77+
return self.project_client.get_by_name(self.repo_name(namespace, repo))
78+
else:
79+
return self.project_client.get_by_name(repo)
80+
81+
def get_project_default_branch(self, project):
82+
branches = self.project_client.get_branches(project['name'])
83+
for branch in branches:
84+
if branch['ref'] == 'HEAD':
85+
return branch['revision']
86+
87+
def is_repository_empty(self, project):
88+
# There is no way to find out if repository is empty, so always return False
89+
return False
90+
91+
def get_parent_project_url(self, namespace, repo, rw=True):
92+
# Gerrit parent project concept is quite different from other services,
93+
# so it is better to always return None here
94+
return None

git_repo/services/service.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ class RepositoryService:
7070
]
7171

7272
_max_nested_namespaces = 1
73+
_min_nested_namespaces = 1
7374

7475
@staticmethod
7576
def get_config_path():
@@ -287,9 +288,9 @@ def format_path(self, repository, namespace=None, rw=False):
287288
if namespace:
288289
repo = '{}/{}'.format(namespace, repository)
289290

290-
if not rw and '/' in repo:
291+
if not rw and repo.count('/') >= self._min_nested_namespaces:
291292
return '{}/{}'.format(self.url_ro, repo)
292-
elif rw and '/' in repo:
293+
elif rw and repo.count('/') >= self._min_nested_namespaces:
293294
if self.url_rw.startswith('ssh://'):
294295
return '{}/{}'.format(self.url_rw, repo)
295296
else:

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ github3.py<1.0.0
77
python-gitlab>=1.0.0
88
gogs-client>=1.0.3
99
pybitbucket_fork>=0.12.2
10+
python-gerritclient>=0.0.1dev137
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
{
2+
"http_interactions": [
3+
{
4+
"recorded_at": "2017-12-15T14:53:08",
5+
"request": {
6+
"body": {
7+
"encoding": "utf-8",
8+
"string": ""
9+
},
10+
"headers": {
11+
"Accept": "application/json",
12+
"Accept-Encoding": "identity",
13+
"Authorization": "Basic UGhhbnRvbS00MjovRk45NTI2TE84MkxYTXJucWJUNWE3Y25wSkY4b2hVTVFRQ1l6TkgzTVE=",
14+
"Connection": "keep-alive",
15+
"Content-Type": "application/json",
16+
"User-Agent": "python-requests/2.18.2"
17+
},
18+
"method": "GET",
19+
"uri": "https://review.gerrithub.io/a/config/server/version"
20+
},
21+
"response": {
22+
"body": {
23+
"encoding": "utf-8",
24+
"string": ")]}'\n\"2.13.6-3044-g7e9c06d\"\n"
25+
},
26+
"headers": {
27+
"Cache-Control": "no-cache, no-store, max-age=0, must-revalidate",
28+
"Connection": "close",
29+
"Content-Disposition": "attachment",
30+
"Content-Length": "28",
31+
"Content-Type": "application/json;charset=utf-8",
32+
"Date": "Fri, 15 Dec 2017 14:53:08 GMT",
33+
"Expires": "Mon, 01 Jan 1990 00:00:00 GMT",
34+
"Pragma": "no-cache",
35+
"Server": "Apache/2.4.6 (CentOS)",
36+
"Set-Cookie": "JSESSIONID=30vs3del55hzzd9bl35gjmm8;Path=/;Secure",
37+
"X-Content-Type-Options": "nosniff"
38+
},
39+
"status": {
40+
"code": 200,
41+
"message": "OK"
42+
},
43+
"url": "https://review.gerrithub.io/a/config/server/version"
44+
}
45+
},
46+
{
47+
"recorded_at": "2017-12-15T14:53:08",
48+
"request": {
49+
"body": {
50+
"encoding": "utf-8",
51+
"string": ""
52+
},
53+
"headers": {
54+
"Accept": "application/json",
55+
"Accept-Encoding": "identity",
56+
"Authorization": "Basic UGhhbnRvbS00MjovRk45NTI2TE84MkxYTXJucWJUNWE3Y25wSkY4b2hVTVFRQ1l6TkgzTVE=",
57+
"Connection": "keep-alive",
58+
"Content-Type": "application/json",
59+
"Cookie": "JSESSIONID=30vs3del55hzzd9bl35gjmm8",
60+
"User-Agent": "python-requests/2.18.2"
61+
},
62+
"method": "GET",
63+
"uri": "https://review.gerrithub.io/a/projects/TestUser%2FDemoRepository"
64+
},
65+
"response": {
66+
"body": {
67+
"encoding": "utf-8",
68+
"string": ")]}'\n{\"id\":\"TestUser%2FDemoRepository\",\"name\":\"TestUser/DemoRepository\",\"parent\":\"All-Projects\",\"description\":\"Just a demo repository for some testing\",\"state\":\"ACTIVE\",\"web_links\":[{\"name\":\"GitHub\",\"url\":\"https://github.com/TestUser/DemoRepository\"}]}\n"
69+
},
70+
"headers": {
71+
"Cache-Control": "no-cache, no-store, max-age=0, must-revalidate",
72+
"Connection": "close",
73+
"Content-Disposition": "attachment",
74+
"Content-Length": "259",
75+
"Content-Type": "application/json;charset=utf-8",
76+
"Date": "Fri, 15 Dec 2017 14:53:08 GMT",
77+
"Expires": "Mon, 01 Jan 1990 00:00:00 GMT",
78+
"Pragma": "no-cache",
79+
"Server": "Apache/2.4.6 (CentOS)",
80+
"X-Content-Type-Options": "nosniff"
81+
},
82+
"status": {
83+
"code": 200,
84+
"message": "OK"
85+
},
86+
"url": "https://review.gerrithub.io/a/projects/TestUser%2FDemoRepository"
87+
}
88+
},
89+
{
90+
"recorded_at": "2017-12-15T14:53:09",
91+
"request": {
92+
"body": {
93+
"encoding": "utf-8",
94+
"string": ""
95+
},
96+
"headers": {
97+
"Accept": "application/json",
98+
"Accept-Encoding": "identity",
99+
"Authorization": "Basic UGhhbnRvbS00MjovRk45NTI2TE84MkxYTXJucWJUNWE3Y25wSkY4b2hVTVFRQ1l6TkgzTVE=",
100+
"Connection": "keep-alive",
101+
"Content-Type": "application/json",
102+
"Cookie": "JSESSIONID=30vs3del55hzzd9bl35gjmm8",
103+
"User-Agent": "python-requests/2.18.2"
104+
},
105+
"method": "GET",
106+
"uri": "https://review.gerrithub.io/a/projects/TestUser%2FDemoRepository/branches"
107+
},
108+
"response": {
109+
"body": {
110+
"encoding": "utf-8",
111+
"string": ")]}'\n[{\"ref\":\"HEAD\",\"revision\":\"master\"},{\"web_links\":[{\"name\":\"GitHub\",\"url\":\"https://github.com/TestUser/DemoRepository/tree/refs/meta/config\"}],\"ref\":\"refs/meta/config\",\"revision\":\"3d3d58c5516834d9fcd92d4d10efe5d3b878bdb4\"},{\"web_links\":[{\"name\":\"GitHub\",\"url\":\"https://github.com/TestUser/DemoRepository/tree/refs/heads/master\"}],\"ref\":\"refs/heads/master\",\"revision\":\"734a6e38bf82c9f1bd5e0d66d3fe06b9010a9b37\"},{\"web_links\":[{\"name\":\"GitHub\",\"url\":\"https://github.com/TestUser/DemoRepository/tree/refs/heads/second_branch\"}],\"ref\":\"refs/heads/second_branch\",\"revision\":\"734a6e38bf82c9f1bd5e0d66d3fe06b9010a9b37\",\"can_delete\":true}]\n"
112+
},
113+
"headers": {
114+
"Cache-Control": "no-cache, no-store, max-age=0, must-revalidate",
115+
"Connection": "close",
116+
"Content-Disposition": "attachment",
117+
"Content-Length": "642",
118+
"Content-Type": "application/json;charset=utf-8",
119+
"Date": "Fri, 15 Dec 2017 14:53:09 GMT",
120+
"Expires": "Mon, 01 Jan 1990 00:00:00 GMT",
121+
"Pragma": "no-cache",
122+
"Server": "Apache/2.4.6 (CentOS)",
123+
"X-Content-Type-Options": "nosniff"
124+
},
125+
"status": {
126+
"code": 200,
127+
"message": "OK"
128+
},
129+
"url": "https://review.gerrithub.io/a/projects/TestUser%2FDemoRepository/branches"
130+
}
131+
}
132+
],
133+
"recorded_with": "betamax/0.5.1"
134+
}

tests/integration/test_gerrit.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env python
2+
3+
import logging
4+
5+
#################################################################################
6+
# Enable logging
7+
8+
log = logging.getLogger('test.gerrit')
9+
10+
#################################################################################
11+
12+
from tests.helpers import GitRepoTestCase
13+
14+
from git_repo.services.service import gerrit
15+
16+
class Test_Gerrit(GitRepoTestCase):
17+
log = log
18+
19+
def get_service(self):
20+
return gerrit.GerritService(c={
21+
'__name__': 'gitrepo "gerrithub"',
22+
'fqdn': 'review.gerrithub.io',
23+
'username': 'TestUser',
24+
'token': 'test_token'
25+
})
26+
27+
def get_requests_session(self):
28+
return self.service.session
29+
30+
def test_00_clone(self):
31+
self.action_clone(namespace='TestUser',
32+
repository='DemoRepository')

0 commit comments

Comments
 (0)