Skip to content

Commit 4fa1a3c

Browse files
committed
Update GitLab manifest provider to support auth, self hosting
1 parent 4112153 commit 4fa1a3c

File tree

1 file changed

+56
-37
lines changed

1 file changed

+56
-37
lines changed

src/rosdistro/manifest_provider/gitlab.py

Lines changed: 56 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -31,37 +31,49 @@
3131
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3232
# POSSIBILITY OF SUCH DAMAGE.
3333

34-
try:
35-
from urllib.request import urlopen, Request
36-
from urllib.error import URLError
37-
from urllib.parse import quote as urlquote
38-
except ImportError:
39-
from urllib2 import urlopen, Request
40-
from urllib2 import URLError
41-
from urllib2.parse import quote as urlquote
42-
4334
import json
4435
import os
4536
import re
37+
from urllib.request import urlopen, Request
38+
from urllib.error import URLError
39+
from urllib.parse import quote as urlquote
4640

4741
from catkin_pkg.package import parse_package_string
4842

4943
from rosdistro.source_repository_cache import SourceRepositoryCache
5044
from rosdistro import logger
5145

46+
GITLAB_PRIVATE_TOKEN = os.getenv('GITLAB_PRIVATE_TOKEN', None)
47+
48+
def _gitlab_urlopen(url):
49+
req = Request(url)
50+
if GITLAB_PRIVATE_TOKEN:
51+
req.add_header('Private-Token', GITLAB_PRIVATE_TOKEN)
52+
logger.warn('Performing GitLab API query "%s"' % (url,))
53+
return urlopen(req)
54+
55+
56+
def _gitlab_api_query(server, path, resource, attrs):
57+
url = 'https://%s/api/v4/projects/%s/%s' % (server, urlquote(path, safe=''), resource)
58+
if attrs:
59+
url += '?' + '&'.join(k + '=' + urlquote(str(v), safe='') for k, v in attrs.items())
60+
return _gitlab_urlopen(url)
5261

53-
def _gitlab_paged_api_query(path, resource, attrs):
54-
_attrs = {'per_page': 50}
55-
_attrs.update(attrs)
56-
_attrs.pop('pagination', None)
57-
_attrs.pop('page', None)
5862

59-
url = 'https://gitlab.com/api/v4/projects/%s/%s?pagination=keyset' % (urlquote(path, safe=''), resource)
60-
for k, v in _attrs.items():
61-
url += '&%s=%s' % (k, urlquote(str(v), safe=''))
63+
def _gitlab_paged_api_query(server, path, resource, attrs):
64+
_attrs = {
65+
'per_page': 50,
66+
**attrs,
67+
'pagination': 'keyset',
68+
'page': '1',
69+
}
70+
71+
url = 'https://%s/api/v4/projects/%s/%s' % (server, urlquote(path, safe=''), resource)
72+
if _attrs:
73+
url += '?' + '&'.join(k + '=' + urlquote(str(v), safe='') for k, v in _attrs.items())
6274

6375
while True:
64-
with urlopen(url) as res:
76+
with _gitlab_urlopen(url) as res:
6577
for result in json.loads(res.read().decode('utf-8')):
6678
yield result
6779

@@ -78,37 +90,43 @@ def _gitlab_paged_api_query(path, resource, attrs):
7890
def gitlab_manifest_provider(_dist_name, repo, pkg_name):
7991
assert repo.version
8092
server, path = repo.get_url_parts()
81-
if not server.endswith('gitlab.com'):
93+
if not server.startswith('gitlab.'):
8294
logger.debug('Skip non-gitlab url "%s"' % repo.url)
8395
raise RuntimeError('can not handle non gitlab urls')
8496

85-
release_tag = repo.get_release_tag(pkg_name)
86-
87-
if not repo.has_remote_tag(release_tag):
88-
raise RuntimeError('specified tag "%s" is not a git tag' % release_tag)
89-
90-
url = 'https://gitlab.com/%s/-/raw/%s/package.xml' % (path, release_tag)
97+
resource = 'repository/files/package.xml/raw'
98+
attrs = {
99+
'ref': repo.get_release_tag(pkg_name),
100+
}
91101
try:
92-
logger.debug('Load package.xml file from url "%s"' % url)
93-
return urlopen(url).read().decode('utf-8')
102+
with _gitlab_api_query(server, path, resource, attrs) as res:
103+
return res.read().decode('utf-8')
94104
except URLError as e:
95-
logger.debug('- failed (%s), trying "%s"' % (e, url))
96-
raise RuntimeError()
105+
logger.debug('- failed (%s), trying "%s"' % (e, e.filename))
106+
raise
97107

98108

99109
def gitlab_source_manifest_provider(repo):
100110
assert repo.version
101111
server, path = repo.get_url_parts()
102-
if not server.endswith('gitlab.com'):
112+
if not server.startswith('gitlab.'):
103113
logger.debug('Skip non-gitlab url "%s"' % repo.url)
104114
raise RuntimeError('can not handle non gitlab urls')
105115

106-
# Resolve the version ref to a sha
107-
sha = next(_gitlab_paged_api_query(path, 'repository/commits', {'per_page': 1, 'ref_name': repo.version}))['id']
116+
# Resolve the version ref to a sha since we need to make multiple queries
117+
attrs = {
118+
'per_page': 1,
119+
'ref_name': repo.version,
120+
}
121+
sha = next(_gitlab_paged_api_query(server, path, 'repository/commits', attrs))['id']
108122

109123
# Look for package.xml files in the tree
124+
attrs = {
125+
'recursive': 'true',
126+
'ref': sha,
127+
}
110128
package_xml_paths = set()
111-
for obj in _gitlab_paged_api_query(path, 'repository/tree', {'recursive': 'true', 'ref': sha}):
129+
for obj in _gitlab_paged_api_query(server, path, 'repository/tree', attrs):
112130
if obj['path'].split('/')[-1] == 'package.xml':
113131
package_xml_paths.add(os.path.dirname(obj['path']))
114132

@@ -127,10 +145,11 @@ def package_xml_in_parent(path):
127145

128146
cache = SourceRepositoryCache.from_ref(sha)
129147
for package_xml_path in package_xml_paths:
130-
url = 'https://gitlab.com/%s/-/raw/%s/%s' % \
131-
(path, sha, package_xml_path + '/package.xml' if package_xml_path else 'package.xml')
132-
logger.debug('- load package.xml from %s' % url)
133-
package_xml = urlopen(url).read().decode('utf-8')
148+
resource_path = urlquote(
149+
package_xml_path + '/package.xml' if package_xml_path else 'package.xml', safe='')
150+
resource = 'repository/files/' + resource_path + '/raw'
151+
with _gitlab_api_query(server, path, resource, {'ref': sha}) as res:
152+
package_xml = res.read().decode('utf-8')
134153
name = parse_package_string(package_xml).name
135154
cache.add(name, package_xml_path, package_xml)
136155

0 commit comments

Comments
 (0)