Download gitlab private repository's raw link using CLI
GitLab 11.5.1から、PRIVATE-TOKENヘッダを使用してrawリンクのダウンロードができなくなりました (cf https://about.gitlab.com/releases/2018/11/28/security-release-gitlab-11-dot-5-dot-1-released/ Improper Enforcement of Token Scope)。
rawリンクが渡されたらURLをパース・変換して、ついでにファイル自体もダウンロードもできるようにしてみました。
#!/usr/bin/python
#gitlab_download
import os
import sys
import json
import shutil
from contextlib import closing
if sys.version_info[0]>=3:
import http.client as httplib
from urllib.request import urlparse
binstdout = sys.stdout.buffer
else:
import httplib
from urlparse import urlparse
binstdout = sys.stdout
def parse_gitlaburl(urlstr):
url = urlparse(urlstr)
a=url.path[1:].split('/')
projname='/'.join([a[0],a[1]])
if a[2]=='-':
a.pop(2)
if a[2]=='raw' or a[2]=='blob':
revision=a[3]
filepath='%2F'.join(a[4:])
url_suffix='/repository/files/'+filepath+'/raw?ref='+revision
elif a[2]=='jobs':
assert a[4]=='artifacts'
jobID=a[3]
if a[5]=='download':
url_suffix='/jobs/'+jobID+'/artifacts'
elif a[5]=='raw' or a[5]=='file':
filepath='/'.join(a[6:])
url_suffix='/jobs/'+jobID+'/artifacts/'+filepath
else:
assert False
else:
raise Exception('unknown URL type %s'%a[2])
return projname, url_suffix
def download_file(urlstr, token, fout):
projname, url_suffix = parse_gitlaburl(urlstr)
url = urlparse(urlstr)
with closing(httplib.HTTPSConnection(url.hostname,port=url.port)) as https:
https.request('GET','/api/v4/projects?search_namespaces=true&search='+projname,None,{'Authorization':'Bearer '+token})
resp = https.getresponse()
jso = json.loads(resp.read())
proj = next(e for e in jso if e['path_with_namespace']==projname)
resolvedPath = '/api/v4/projects/'+str(proj['id'])+url_suffix
sys.stderr.write('resolved: https://%s%s\n'%(url.netloc,resolvedPath))
https.request('GET',resolvedPath,None,{'Authorization':'Bearer '+token})
resp = https.getresponse()
#print(resp.getheaders())
shutil.copyfileobj(resp,fout)
def get_token(**kwargs):
url = urlparse(kwargs['url'])
token = os.environ.get('gitlab_token_'+url.hostname.replace('.','_'),'')
if not token:
### custom logic comes here
pass
return token
if __name__ == "__main__":
token = get_token(url=sys.argv[1])
download_file(sys.argv[1], token, binstdout)
200602
プロジェクト名からプロジェクトIDに変換する際、search_namespaces=true
を与えるようにしました。
210511
ci artifactをダウンロードできるようにしました。あと、再利用しやすくしました。