add: --create-missing-projects; started working on user migration; blueprinted further migration functions
This commit is contained in:
parent
b4eacc471b
commit
6b1b522f20
@ -15,8 +15,9 @@
|
|||||||
# --gitea-url <GITEA_URL> Gitea URL
|
# --gitea-url <GITEA_URL> Gitea URL
|
||||||
# --gitea-api-version <GITEA_API_VERSION> Gitea API version (default: v1)
|
# --gitea-api-version <GITEA_API_VERSION> Gitea API version (default: v1)
|
||||||
#
|
#
|
||||||
# --create-missing-groups Create missing groups on Gitea (default: False)
|
# --create-missing-groups Create missing groups on Gitea (default: True)
|
||||||
# --create-missing-users Create missing users on Gitea (default: False)
|
# --create-missing-users Create missing users on Gitea (default: True)
|
||||||
|
# --create-missing-projects Create missing projects on Gitea (default: True)
|
||||||
#
|
#
|
||||||
# --quiet Enable quiet mode (default: False)
|
# --quiet Enable quiet mode (default: False)
|
||||||
# --debug Enable debug mode (default: False)
|
# --debug Enable debug mode (default: False)
|
||||||
@ -47,8 +48,9 @@ GITEA_API_VERSION = 'v1'
|
|||||||
|
|
||||||
# Settings - General Repository
|
# Settings - General Repository
|
||||||
|
|
||||||
CREATE_MISSING_GROUPS = False
|
CREATE_MISSING_GROUPS = True
|
||||||
CREATE_MISSING_USERS = False
|
CREATE_MISSING_USERS = True
|
||||||
|
CREATE_MISSING_PROJECTS = True
|
||||||
|
|
||||||
# Settings - General
|
# Settings - General
|
||||||
|
|
||||||
@ -65,6 +67,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
import requests
|
import requests
|
||||||
|
import traceback
|
||||||
|
|
||||||
# Set cwd to script directory
|
# Set cwd to script directory
|
||||||
|
|
||||||
@ -95,6 +98,9 @@ if 'CREATE_MISSING_GROUPS' in os.environ:
|
|||||||
if 'CREATE_MISSING_USERS' in os.environ:
|
if 'CREATE_MISSING_USERS' in os.environ:
|
||||||
CREATE_MISSING_USERS = bool(os.environ['CREATE_MISSING_USERS'])
|
CREATE_MISSING_USERS = bool(os.environ['CREATE_MISSING_USERS'])
|
||||||
|
|
||||||
|
if 'CREATE_MISSING_PROJECTS' in os.environ:
|
||||||
|
CREATE_MISSING_PROJECTS = bool(os.environ['CREATE_MISSING_PROJECTS'])
|
||||||
|
|
||||||
if 'QUIET' in os.environ:
|
if 'QUIET' in os.environ:
|
||||||
QUIET = bool(os.environ['QUIET'])
|
QUIET = bool(os.environ['QUIET'])
|
||||||
|
|
||||||
@ -150,6 +156,10 @@ if os.path.exists('.env'):
|
|||||||
if value.lower() == 'true' or value == '1':
|
if value.lower() == 'true' or value == '1':
|
||||||
CREATE_MISSING_USERS = True
|
CREATE_MISSING_USERS = True
|
||||||
|
|
||||||
|
if key == 'CREATE_MISSING_PROJECTS':
|
||||||
|
if value.lower() == 'true' or value == '1':
|
||||||
|
CREATE_MISSING_PROJECTS = True
|
||||||
|
|
||||||
if key == 'QUIET':
|
if key == 'QUIET':
|
||||||
QUIET = bool(value)
|
QUIET = bool(value)
|
||||||
|
|
||||||
@ -183,6 +193,7 @@ parser.add_argument('--gitea-url', help='Gitea URL')
|
|||||||
parser.add_argument('--gitea-api-version', help='Gitea API version', default='v1')
|
parser.add_argument('--gitea-api-version', help='Gitea API version', default='v1')
|
||||||
parser.add_argument('--create-missing-groups', help='Create missing groups on Gitea', action='store_true')
|
parser.add_argument('--create-missing-groups', help='Create missing groups on Gitea', action='store_true')
|
||||||
parser.add_argument('--create-missing-users', help='Create missing users on Gitea', action='store_true')
|
parser.add_argument('--create-missing-users', help='Create missing users on Gitea', action='store_true')
|
||||||
|
parser.add_argument('--create-missing-projects', help='Create missing projects on Gitea', action='store_true')
|
||||||
parser.add_argument('--quiet', help='Enable quiet mode', action='store_true')
|
parser.add_argument('--quiet', help='Enable quiet mode', action='store_true')
|
||||||
parser.add_argument('--debug', help='Enable debug mode', action='store_true')
|
parser.add_argument('--debug', help='Enable debug mode', action='store_true')
|
||||||
parser.add_argument('--trace', help='Enable trace mode', action='store_true')
|
parser.add_argument('--trace', help='Enable trace mode', action='store_true')
|
||||||
@ -216,6 +227,9 @@ if args.create_missing_groups:
|
|||||||
if args.create_missing_users:
|
if args.create_missing_users:
|
||||||
CREATE_MISSING_USERS = True
|
CREATE_MISSING_USERS = True
|
||||||
|
|
||||||
|
if args.create_missing_projects:
|
||||||
|
CREATE_MISSING_PROJECTS = True
|
||||||
|
|
||||||
if args.quiet:
|
if args.quiet:
|
||||||
QUIET = True
|
QUIET = True
|
||||||
|
|
||||||
@ -278,6 +292,27 @@ def _error(message):
|
|||||||
with open(LOG_FILE, 'a') as log_file:
|
with open(LOG_FILE, 'a') as log_file:
|
||||||
log_file.write(f'[ERR] {message}\n')
|
log_file.write(f'[ERR] {message}\n')
|
||||||
|
|
||||||
|
def _exception(exception, custom_message=None):
|
||||||
|
exc_type, exc_obj, exc_tb = sys.exc_info()
|
||||||
|
filename = exc_tb.tb_frame.f_code.co_filename
|
||||||
|
lineno = exc_tb.tb_lineno
|
||||||
|
formatted_traceback = traceback.format_exc()
|
||||||
|
|
||||||
|
# Prepare the exception message
|
||||||
|
exception_message = (f'{custom_message}\n' if custom_message else '') + (
|
||||||
|
f'\033[1m\033[31m[EXC]\033[0m {exception} '
|
||||||
|
f'(file: {filename}, line: {lineno})\n'
|
||||||
|
f'{formatted_traceback}\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Print the exception message to the console
|
||||||
|
print(exception_message)
|
||||||
|
|
||||||
|
# Write the exception message to the log file if defined
|
||||||
|
if LOG_FILE:
|
||||||
|
with open(LOG_FILE, 'a') as log_file:
|
||||||
|
log_file.write(f'[EXC] {exception_message}\n')
|
||||||
|
|
||||||
# PROGRAM
|
# PROGRAM
|
||||||
|
|
||||||
def gitlab2gitea_visibility(visibility: str) -> str:
|
def gitlab2gitea_visibility(visibility: str) -> str:
|
||||||
@ -668,10 +703,146 @@ def cmp_gitlab_gitea_groups(gitlab_groups: list, gitea_groups: list) -> dict:
|
|||||||
return compare_result, missing_matches
|
return compare_result, missing_matches
|
||||||
|
|
||||||
def cmp_gitlab_gitea_users(gitlab_users: list, gitea_users: list) -> dict:
|
def cmp_gitlab_gitea_users(gitlab_users: list, gitea_users: list) -> dict:
|
||||||
pass
|
|
||||||
|
# 0 = exists on both
|
||||||
|
# 1 = exists on GitLab only
|
||||||
|
# 2 = exists on Gitea only
|
||||||
|
# planned structure:
|
||||||
|
# {
|
||||||
|
# 'username' : 0,
|
||||||
|
# 'username2' : 1,
|
||||||
|
# 'username3' : 2
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Structure on Gitlab
|
||||||
|
# [
|
||||||
|
# {
|
||||||
|
# "id": 3,
|
||||||
|
# "username": "user.name",
|
||||||
|
# "name": "user.name",
|
||||||
|
# "state": "active",
|
||||||
|
# "locked": false,
|
||||||
|
# "avatar_url": "https://git.example.com/uploads/-/system/user/avatar/3/avatar.png",
|
||||||
|
# "web_url": "https://git.example.com/user.name",
|
||||||
|
# "created_at": "2020-07-16T14:43:36.801Z",
|
||||||
|
# "bio": "",
|
||||||
|
# "location": "",
|
||||||
|
# "public_email": "",
|
||||||
|
# "skype": "",
|
||||||
|
# "linkedin": "",
|
||||||
|
# "twitter": "",
|
||||||
|
# "discord": "",
|
||||||
|
# "website_url": "",
|
||||||
|
# "organization": "",
|
||||||
|
# "job_title": "",
|
||||||
|
# "pronouns": null,
|
||||||
|
# "bot": false,
|
||||||
|
# "work_information": null,
|
||||||
|
# "local_time": "10:25 AM",
|
||||||
|
# "last_sign_in_at": "2024-06-30T20:05:29.531Z",
|
||||||
|
# "confirmed_at": "2020-07-16T14:43:36.692Z",
|
||||||
|
# "last_activity_on": "2024-07-14",
|
||||||
|
# "email": "user.name@example.com",
|
||||||
|
# "theme_id": 11,
|
||||||
|
# "color_scheme_id": 2,
|
||||||
|
# "projects_limit": 100000,
|
||||||
|
# "current_sign_in_at": "2024-07-13T09:14:00.499Z",
|
||||||
|
# "identities": [
|
||||||
|
# {
|
||||||
|
# "provider": "ldapmain",
|
||||||
|
# "extern_uid": "cn=user.name,ou=internal,ou=users,ou=org,dc=example,dc=com",
|
||||||
|
# "saml_provider_id": null
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
# "can_create_group": true,
|
||||||
|
# "can_create_project": true,
|
||||||
|
# "two_factor_enabled": true,
|
||||||
|
# "external": false,
|
||||||
|
# "private_profile": false,
|
||||||
|
# "commit_email": "user.name@example.com",
|
||||||
|
# "shared_runners_minutes_limit": null,
|
||||||
|
# "extra_shared_runners_minutes_limit": null,
|
||||||
|
# "scim_identities": [],
|
||||||
|
# "is_admin": true,
|
||||||
|
# "note": "",
|
||||||
|
# "namespace_id": 3,
|
||||||
|
# "created_by": null,
|
||||||
|
# "email_reset_offered_at": null,
|
||||||
|
# "using_license_seat": false
|
||||||
|
# }
|
||||||
|
# ]
|
||||||
|
|
||||||
|
# Structure on Gitea
|
||||||
|
# {
|
||||||
|
# "data": [
|
||||||
|
# {
|
||||||
|
# "id": 1,
|
||||||
|
# "login": "user.name",
|
||||||
|
# "login_name": "",
|
||||||
|
# "source_id": 0,
|
||||||
|
# "full_name": "",
|
||||||
|
# "email": "user.name@example.com",
|
||||||
|
# "avatar_url": "http://git.example.com/avatars/a81823ace1c9fa7ab59a61ca6e2c34b0",
|
||||||
|
# "html_url": "http://git.example.com/user.name",
|
||||||
|
# "language": "en-US",
|
||||||
|
# "is_admin": true,
|
||||||
|
# "last_login": "1970-01-01T01:00:00+01:00",
|
||||||
|
# "created": "2024-07-13T11:04:57+02:00",
|
||||||
|
# "restricted": false,
|
||||||
|
# "active": true,
|
||||||
|
# "prohibit_login": false,
|
||||||
|
# "location": "",
|
||||||
|
# "website": "",
|
||||||
|
# "description": "",
|
||||||
|
# "visibility": "private",
|
||||||
|
# "followers_count": 0,
|
||||||
|
# "following_count": 0,
|
||||||
|
# "starred_repos_count": 0,
|
||||||
|
# "username": "user.name"
|
||||||
|
# }
|
||||||
|
# ],
|
||||||
|
# "ok": true
|
||||||
|
# }
|
||||||
|
|
||||||
|
compare_result = {}
|
||||||
|
missing_matches = 0
|
||||||
|
|
||||||
|
for gitlab_user in gitlab_users:
|
||||||
|
name = gitlab_user['username']
|
||||||
|
exists = False
|
||||||
|
|
||||||
|
for gitea_user in gitea_users:
|
||||||
|
if name == gitea_user['login']:
|
||||||
|
exists = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if exists:
|
||||||
|
_info(f'GITLAB: User "{name}" exists on both GitLab and Gitea')
|
||||||
|
else:
|
||||||
|
_warn(f'GITLAB: User "{name}" exists on GitLab only')
|
||||||
|
missing_matches += 1
|
||||||
|
|
||||||
|
compare_result[name] = 0 if exists else 1
|
||||||
|
|
||||||
|
for gitea_user in gitea_users:
|
||||||
|
name = gitea_user['login']
|
||||||
|
exists = False
|
||||||
|
|
||||||
|
for gitlab_user in gitlab_users:
|
||||||
|
if name == gitlab_user['username']:
|
||||||
|
exists = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not exists:
|
||||||
|
_warn(f'GITEA: User "{name}" exists on Gitea only')
|
||||||
|
compare_result[name] = 2
|
||||||
|
|
||||||
|
return compare_result, missing_matches
|
||||||
|
|
||||||
|
|
||||||
def cmp_gitlab_gitea_projects(gitlab_projects: list, gitea_projects: list) -> dict:
|
def cmp_gitlab_gitea_projects(gitlab_projects: list, gitea_projects: list) -> dict:
|
||||||
pass
|
|
||||||
|
return {}, 0
|
||||||
|
|
||||||
def create_missing_groups(gitlab_groups: list, gitea_groups: list):
|
def create_missing_groups(gitlab_groups: list, gitea_groups: list):
|
||||||
|
|
||||||
@ -690,7 +861,13 @@ def create_missing_groups(gitlab_groups: list, gitea_groups: list):
|
|||||||
try:
|
try:
|
||||||
migrate_gitlab_group_to_gitea(gitlab_group)
|
migrate_gitlab_group_to_gitea(gitlab_group)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_error(f'Failed to create Gitea group "{name}": {e}')
|
_exception(f'Failed to create Gitea group "{name}": {e}', e)
|
||||||
|
|
||||||
|
def create_missing_users(gitlab_users: list, gitea_users: list):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def create_missing_projects(gitlab_projects: list, gitea_projects: list):
|
||||||
|
pass
|
||||||
|
|
||||||
def update_existing_groups(gitlab_groups: list, gitea_groups: list):
|
def update_existing_groups(gitlab_groups: list, gitea_groups: list):
|
||||||
for gitlab_group in gitlab_groups:
|
for gitlab_group in gitlab_groups:
|
||||||
@ -713,7 +890,10 @@ def update_existing_groups(gitlab_groups: list, gitea_groups: list):
|
|||||||
'full_name': gitlab_group['full_name']
|
'full_name': gitlab_group['full_name']
|
||||||
})
|
})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_error(f'Failed to update Gitea group "{name}": {e}')
|
_exception(f'Failed to update Gitea group "{name}": {e}', e)
|
||||||
|
|
||||||
|
def update_existing_users(gitlab_users: list, gitea_users: list):
|
||||||
|
pass
|
||||||
|
|
||||||
def migrate_groups():
|
def migrate_groups():
|
||||||
gitlab_groups = get_gitlab_groups()
|
gitlab_groups = get_gitlab_groups()
|
||||||
@ -724,7 +904,11 @@ def migrate_groups():
|
|||||||
_info(f'Groups on Gitea: {len(gitea_groups)}')
|
_info(f'Groups on Gitea: {len(gitea_groups)}')
|
||||||
_trace(f'Groups on Gitea: {gitea_groups}')
|
_trace(f'Groups on Gitea: {gitea_groups}')
|
||||||
|
|
||||||
|
try:
|
||||||
group_result, missing_matches = cmp_gitlab_gitea_groups(gitlab_groups, gitea_groups)
|
group_result, missing_matches = cmp_gitlab_gitea_groups(gitlab_groups, gitea_groups)
|
||||||
|
except Exception as e:
|
||||||
|
_exception(f'Failed to compare GitLab and Gitea groups: {e}', e)
|
||||||
|
return
|
||||||
|
|
||||||
if missing_matches > 0:
|
if missing_matches > 0:
|
||||||
_warn(f'{missing_matches} groups are missing on Gitea!')
|
_warn(f'{missing_matches} groups are missing on Gitea!')
|
||||||
@ -733,7 +917,10 @@ def migrate_groups():
|
|||||||
_info('Creating missing groups on Gitea...')
|
_info('Creating missing groups on Gitea...')
|
||||||
|
|
||||||
if not DRY_RUN:
|
if not DRY_RUN:
|
||||||
|
try:
|
||||||
create_missing_groups(gitlab_groups, gitea_groups)
|
create_missing_groups(gitlab_groups, gitea_groups)
|
||||||
|
except Exception as e:
|
||||||
|
_exception(f'Failed to create missing groups: {e}', e)
|
||||||
else:
|
else:
|
||||||
_warn('Dry-run mode enabled, skipping creation of missing groups on Gitea...')
|
_warn('Dry-run mode enabled, skipping creation of missing groups on Gitea...')
|
||||||
|
|
||||||
@ -745,7 +932,7 @@ def migrate_groups():
|
|||||||
else:
|
else:
|
||||||
_warn('Dry-run mode enabled, skipping update of existing groups on Gitea...')
|
_warn('Dry-run mode enabled, skipping update of existing groups on Gitea...')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_error(f'Failed to update existing groups: {e}')
|
_exception(f'Failed to update existing groups: {e}', e)
|
||||||
|
|
||||||
def migrate_users():
|
def migrate_users():
|
||||||
gitlab_users = get_gitlab_users()
|
gitlab_users = get_gitlab_users()
|
||||||
@ -756,7 +943,33 @@ def migrate_users():
|
|||||||
_info(f'Users on Gitea: {len(gitea_users)}')
|
_info(f'Users on Gitea: {len(gitea_users)}')
|
||||||
_trace(f'Users on Gitea: {gitea_users}')
|
_trace(f'Users on Gitea: {gitea_users}')
|
||||||
|
|
||||||
cmp_gitlab_gitea_users(gitlab_users, gitea_users)
|
try:
|
||||||
|
user_result, missing_matches = cmp_gitlab_gitea_users(gitlab_users, gitea_users['data'])
|
||||||
|
except Exception as e:
|
||||||
|
_exception(f'Failed to compare GitLab and Gitea users: {e}', e)
|
||||||
|
return
|
||||||
|
|
||||||
|
if missing_matches > 0:
|
||||||
|
_warn(f'{missing_matches} users are missing on Gitea!')
|
||||||
|
|
||||||
|
if missing_matches > 0 and CREATE_MISSING_USERS:
|
||||||
|
_info('Creating missing users on Gitea...')
|
||||||
|
|
||||||
|
if not DRY_RUN:
|
||||||
|
create_missing_users(gitlab_users, gitea_users)
|
||||||
|
else:
|
||||||
|
_warn('Dry-run mode enabled, skipping creation of missing users on Gitea...')
|
||||||
|
|
||||||
|
_info('Updating existing users on Gitea...')
|
||||||
|
|
||||||
|
try:
|
||||||
|
if not DRY_RUN:
|
||||||
|
update_existing_users(gitlab_users, gitea_users)
|
||||||
|
else:
|
||||||
|
_warn('Dry-run mode enabled, skipping update of existing users on Gitea...')
|
||||||
|
except Exception as e:
|
||||||
|
_exception(f'Failed to update existing users: {e}', e)
|
||||||
|
|
||||||
|
|
||||||
def migrate_projects():
|
def migrate_projects():
|
||||||
gitlab_projects = get_gitlab_projects()
|
gitlab_projects = get_gitlab_projects()
|
||||||
@ -767,7 +980,22 @@ def migrate_projects():
|
|||||||
_info(f'Projects on Gitea: {len(gitea_projects)}')
|
_info(f'Projects on Gitea: {len(gitea_projects)}')
|
||||||
_trace(f'Projects on Gitea: {gitea_projects}')
|
_trace(f'Projects on Gitea: {gitea_projects}')
|
||||||
|
|
||||||
cmp_gitlab_gitea_projects(gitlab_projects, gitea_projects)
|
try:
|
||||||
|
project_result, missing_matches = cmp_gitlab_gitea_projects(gitlab_projects, gitea_projects)
|
||||||
|
except Exception as e:
|
||||||
|
_exception(f'Failed to compare GitLab and Gitea projects: {e}', e)
|
||||||
|
return
|
||||||
|
|
||||||
|
if missing_matches > 0:
|
||||||
|
_warn(f'{missing_matches} projects are missing on Gitea!')
|
||||||
|
|
||||||
|
if missing_matches > 0 and CREATE_MISSING_PROJECTS:
|
||||||
|
_info('Creating missing projects on Gitea...')
|
||||||
|
|
||||||
|
if not DRY_RUN:
|
||||||
|
create_missing_projects(gitlab_projects, gitea_projects)
|
||||||
|
else:
|
||||||
|
_warn('Dry-run mode enabled, skipping creation of missing projects on Gitea...')
|
||||||
|
|
||||||
def run_migration():
|
def run_migration():
|
||||||
|
|
||||||
@ -816,7 +1044,7 @@ def main():
|
|||||||
check_gitlab()
|
check_gitlab()
|
||||||
check_gitea()
|
check_gitea()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_error(f'An error occurred: {e}')
|
_exception(f'An error occurred: {e}', e)
|
||||||
return
|
return
|
||||||
|
|
||||||
_info('Starting migration...')
|
_info('Starting migration...')
|
||||||
@ -824,7 +1052,7 @@ def main():
|
|||||||
try:
|
try:
|
||||||
run_migration()
|
run_migration()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_error(f'An error occurred: {e}')
|
_exception(f'An error occurred: {e}', e)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
Reference in New Issue
Block a user