import requests | |
from requests.auth import HTTPBasicAuth | |
import re | |
from StringIO import StringIO | |
JIRA_URL = 'https://your-jira-url.tld/' | |
JIRA_ACCOUNT = ('jira-username', 'jira-password') | |
# the JIRA project ID (short) | |
JIRA_PROJECT = 'PRO' | |
GITLAB_URL = 'http://your-gitlab-url.tld/' | |
# this token will be used whenever the API is invoked and | |
# the script will be unable to match the jira's author of the comment / attachment / issue | |
# this identity will be used instead. | |
GITLAB_TOKEN = 'get-this-token-from-your-profile' | |
# the project in gitlab that you are importing issues to. | |
GITLAB_PROJECT = 'namespaced/project/name' | |
# the numeric project ID. If you don't know it, the script will search for it | |
# based on the project name. | |
GITLAB_PROJECT_ID = None | |
# set this to false if JIRA / Gitlab is using self-signed certificate. | |
VERIFY_SSL_CERTIFICATE = True | |
# IMPORTANT !!! | |
# make sure that user (in gitlab) has access to the project you are trying to | |
# import into. Otherwise the API request will fail. | |
# jira user name as key, gitlab as value | |
# if you want dates and times to be correct, make sure every user is (temporarily) admin | |
GITLAB_USER_NAMES = { | |
'jira': 'gitlab', | |
} | |
jira_issues = requests.get( | |
JIRA_URL + 'rest/api/2/search?jql=project=%s+&maxResults=10000' % JIRA_PROJECT, | |
auth=HTTPBasicAuth(*JIRA_ACCOUNT), | |
verify=VERIFY_SSL_CERTIFICATE, | |
headers={'Content-Type': 'application/json'} | |
) | |
if not GITLAB_PROJECT_ID: | |
# find out the ID of the project. | |
for project in requests.get( | |
GITLAB_URL + 'api/v3/projects', | |
headers={'PRIVATE-TOKEN': GITLAB_TOKEN}, | |
).json(): | |
if project['path_with_namespace'] == GITLAB_PROJECT: | |
GITLAB_PROJECT_ID = project['id'] | |
break | |
if not GITLAB_PROJECT_ID: | |
raise Exception("Unable to find %s in gitlab!" % GITLAB_PROJECT) | |
for issue in jira_issues.json()['issues']: | |
reporter = issue['fields']['reporter']['name'] | |
gl_issue = requests.post( | |
GITLAB_URL + 'api/v3/projects/%s/issues' % GITLAB_PROJECT_ID, | |
headers={'PRIVATE-TOKEN': GITLAB_TOKEN,'SUDO': GITLAB_USER_NAMES.get(reporter, reporter)}, | |
verify=VERIFY_SSL_CERTIFICATE, | |
data={ | |
'title': issue['fields']['summary'], | |
'description': issue['fields']['description'], | |
'created_at': issue['fields']['created'] | |
} | |
).json()['id'] | |
# get comments and attachments | |
issue_info = requests.get( | |
JIRA_URL + 'rest/api/2/issue/%s/?fields=attachment,comment' % issue['id'], | |
auth=HTTPBasicAuth(*JIRA_ACCOUNT), | |
verify=VERIFY_SSL_CERTIFICATE, | |
headers={'Content-Type': 'application/json'} | |
).json() | |
for comment in issue_info['fields']['comment']['comments']: | |
author = comment['author']['name'] | |
note_add = requests.post( | |
GITLAB_URL + 'api/v3/projects/%s/issues/%s/notes' % (GITLAB_PROJECT_ID, gl_issue), | |
headers={'PRIVATE-TOKEN': GITLAB_TOKEN,'SUDO': GITLAB_USER_NAMES.get(author, author)}, | |
verify=VERIFY_SSL_CERTIFICATE, | |
data={ | |
'body': comment['body'], | |
'created_at': comment['created'] | |
} | |
) | |
if len(issue_info['fields']['attachment']): | |
for attachment in issue_info['fields']['attachment']: | |
author = attachment['author']['name'] | |
_file = requests.get( | |
attachment['content'], | |
auth=HTTPBasicAuth(*JIRA_ACCOUNT), | |
verify=VERIFY_SSL_CERTIFICATE, | |
) | |
_content = StringIO(_file.content) | |
file_info = requests.post( | |
GITLAB_URL + 'api/v3/projects/%s/uploads' % GITLAB_PROJECT_ID, | |
headers={'PRIVATE-TOKEN': GITLAB_TOKEN,'SUDO': GITLAB_USER_NAMES.get(author, author)}, | |
files={ | |
'file': ( | |
attachment['filename'], | |
_content | |
) | |
}, | |
verify=VERIFY_SSL_CERTIFICATE | |
) | |
del _content | |
# now we got the upload URL. Let's post the comment with an | |
# attachment | |
requests.post( | |
GITLAB_URL + 'api/v3/projects/%s/issues/%s/notes' % (GITLAB_PROJECT_ID, gl_issue), | |
headers={'PRIVATE-TOKEN': GITLAB_TOKEN,'SUDO': GITLAB_USER_NAMES.get(author, author)}, | |
verify=VERIFY_SSL_CERTIFICATE, | |
data={ | |
'body': file_info.json()['markdown'], | |
'created_at': attachment['created'] | |
} | |
) | |
print "created issue #%s" % gl_issue | |
print "imported %s issues from project %s" % (len(jira_issues.json()['issues']), JIRA_PROJECT) |
@artasoftware, by using PY3 instead of 2
It's easy enough to convert this to gitlab api v4, just one important remark, you need iid instead of id from the gitlab issue!
@patvdleer but script is written in python 2, right? Because those print call in the end looks like v2?
I keep getting this issue, and I have no idea why. Can anyone lend me their 2 cents.
File "move-issues-from-jira-to-gitlab.py", line 107, in
if user['username'] == assignee:
Jira changed maxResults behaviour https://community.atlassian.com/t5/Jira-discussions/Jira-max-results-is-100/m-p/642338#M1137
Gitlab API version v3 is outdated. Change v3 to v4 in the request strings.
Hahaha/ i got that error :::
print, request,.....
after update print "" - v2
to print("") - v3
still having alot of errors !!!
Hi. I have an error while trying to move issues from Jira to Gitlab.
Traceback (most recent call last):
File "movefromjira2.py", line 66, in
'created_at': issue['fields']['created']
File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 110, in post
return request('post', url, data=data, json=json, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 56, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 488, in request
resp = self.send(prep, **send_kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 609, in send
r = adapter.send(request, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/adapters.py", line 423, in send
timeout=timeout
File "/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/connectionpool.py", line 594, in urlopen
chunked=chunked)
File "/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/connectionpool.py", line 361, in _make_request
conn.request(method, url, **httplib_request_kw)
File "/usr/lib/python2.7/httplib.py", line 1001, in request
self._send_request(method, url, body, headers)
File "/usr/lib/python2.7/httplib.py", line 1034, in _send_request
self.putheader(hdr, value)
File "/usr/lib/python2.7/httplib.py", line 981, in putheader
hdr = '%s: %s' % (header, '\r\n\t'.join([str(v) for v in values]))
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-8: ordinal not in range(128)
Any ideas how to pass it?