-
Notifications
You must be signed in to change notification settings - Fork 24
/
migrate_gitlab_to_gogs.py
executable file
·154 lines (128 loc) · 6.73 KB
/
migrate_gitlab_to_gogs.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#!/usr/bin/env python3
import requests
import json
import subprocess
import os
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--source_namespace',
help='The namespace in gitlab as it appears in URLs. For example, given the repository address http://mygitlab.com/harry/my-awesome-repo.git, it shows that this repository lies within my personal namespace "harry". Hence I would pass harry as parameter.',
required=True)
parser.add_argument('--add_to_private',default=None, action='store_true',help='If you want to add the repositories under your own name, ie. not in any organisation, use this flag.')
parser.add_argument('--add_to_organization',default=None, metavar='organization_name', help='If you want to add all the repositories to an exisiting organisation, please pass the name to this parameter. Organizations correspond to groups in Gitlab. The name can be taken from the URL, for example, if your organization is http://mygogs-repo.com/org/my-awesome-organisation/dashboard then pass my-awesome-organisation here')
parser.add_argument('--source_repo',
help='URL to your gitlab repo in the format http://mygitlab.com/',
required=True)
parser.add_argument('--target_repo',
help='URL to your gogs / gitea repo in the format http://mygogs.com/',
required=True)
parser.add_argument('--no_confirm',
help='Skip user confirmation of each single step',
action='store_true')
parser.add_argument('--skip_existing',
help='Skip repositories that already exist on remote without asking the user',
action='store_true')
args = parser.parse_args()
assert args.add_to_private or args.add_to_organization is not None, 'Please set either add_to_private or provide a target oranization name!'
print('In the following, we will check out all repositories from ')
print('the namespace %s to the current directory and push it to '%args.source_namespace)
if args.add_to_private:
print('your personal account', end='')
else:
print('to the organisation %s'%args.add_to_organization, end='')
print(' as private repositories.')
if not args.no_confirm:
input('Hit any key to continue!')
gogs_url = args.target_repo + "/api/v1"
gitlab_url = args.source_repo + '/api/v4'
if 'gogs_token' in os.environ:
gogs_token=os.environ['gogs_token']
else:
gogs_token = input(("\n\nPlease provide the gogs access token which we use to access \n"
"your account. This is NOT your password! Go to \n"
"/user/settings/applications\n"
"and click on 'Create new token', and copy and paste the \n"
"resulting token which is shown afterwards. It should look \n"
"like 3240823dfsaefwio328923490832a.\n\ngogs_token=").format(args.target_repo))
assert len(gogs_token)>0, 'The gogs token cannot be empty!'
if 'gitlab_token' in os.environ:
gitlab_token=os.environ['gitlab_token']
else:
gitlab_token = input(("\n\nToken to access your GITLAB account. This is NOT your password! Got to \n"
"{}/profile/account \n"
"and copy the value in section 'Private token'. It should \n"
"look like du8dfsJlfEWFJAFhs\n"
"\ngitlab_token=").format(args.source_repo))
assert len(gitlab_token)>0, 'The gitlab token cannot be empty!'
#tmp_dir = '/home/simon/tmp/gitlab_gogs_migration'
#print('Using temporary directory %s'%tmp_dir)
## Create temporary directory
#try:
#os.makedirs(tmp_dir)
#print('Created temporary directory %s'%tmp_dir)
#except FileExistsError as e:
#pass
#except Exception as e:
#raise e
#os.chdir(tmp_dir)
print('Getting existing projects from namespace %s...'%args.source_namespace)
s = requests.Session()
page_id = 1
finished = False
project_list = []
while not finished:
print('Getting page %s'%page_id)
res = s.get(gitlab_url + '/projects?private_token=%s&page=%s'%(gitlab_token,page_id))
assert res.status_code == 200, 'Error when retrieving the projects. The returned html is %s'%res.text
project_list += json.loads(res.text)
if len(json.loads(res.text)) < 1:
finished = True
else:
page_id += 1
filtered_projects = list(filter(lambda x: x['path_with_namespace'].split('/')[0]==args.source_namespace, project_list))
print('\n\nFinished preparations. We are about to migrate the following projects:')
print('\n'.join([p['path_with_namespace'] for p in filtered_projects]))
if not args.no_confirm:
if 'yes' != input('Do you want to continue? (please answer yes or no) '):
print('\nYou decided to cancel...')
for i in range(len(filtered_projects)):
src_name = filtered_projects[i]['name']
src_url = filtered_projects[i]['ssh_url_to_repo']
src_description = filtered_projects[i]['description']
dst_name = src_name.replace(' ','-')
print('\n\nMigrating project %s to project %s now.'%(src_url,dst_name))
if not args.no_confirm:
if 'yes' != input('Do you want to continue? (please answer yes or no) '):
print('\nYou decided to cancel...')
# Create repo
if args.add_to_private:
create_repo = s.post(gogs_url+'/user/repos', data=dict(token=gogs_token, name=dst_name, private=True))
elif args.add_to_organization:
create_repo = s.post(gogs_url+'/org/%s/repos'%args.add_to_organization,
data=dict(token=gogs_token, name=dst_name, private=True, description=src_description))
if create_repo.status_code != 201:
print('Could not create repo %s because of %s'%(src_name,json.loads(create_repo.text)['message']))
if args.skip_existing:
print('\nSkipped')
else:
if 'yes' != input('Do you want to skip this repo and continue with the next? (please answer yes or no) '):
print('\nYou decided to cancel...')
exit(1)
continue
dst_info = json.loads(create_repo.text)
dst_url = dst_info['ssh_url']
# Git pull and push
subprocess.check_call(['git','clone','--bare',src_url])
os.chdir(src_url.split('/')[-1])
branches=subprocess.check_output(['git','branch','-a'])
if len(branches) == 0:
print('\n\nThis repository is empty - skipping push')
else:
subprocess.check_call(['git','push','--mirror',dst_url])
os.chdir('..')
subprocess.check_call(['rm','-rf',src_url.split('/')[-1]])
print('\n\nFinished migration. New project URL is %s'%dst_info['html_url'])
print('Please open the URL and check if everything is fine.')
if not args.no_confirm:
input('Hit any key to continue!')
print('\n\nEverything finished!\n')