Skip to content

Instantly share code, notes, and snippets.

@tklee1975
Created January 20, 2025 02:36
Show Gist options
  • Save tklee1975/aa2c29587a05cafc5bff8463113ca046 to your computer and use it in GitHub Desktop.
Save tklee1975/aa2c29587a05cafc5bff8463113ca046 to your computer and use it in GitHub Desktop.
Script for GitLab to Github Repository Migration
gitlab_username: <your-gitlab-username>
gitlab_access_token: <your-gitlab-access-token>
github_username: <your-github-username>
github_access_token: <your-github-access-token>
github_repo_owner: <your-github-repo-owner username or organization name>
# Pre-requisites:
# 1. Install GitHub CLI: https://cli.github.com/
# 2. Install Git: https://git-scm.com/
# 3. Install PyYAML: pip3 install pyyaml
# 4. Run 'gh auth login' to login to GitHub CLI
# 5. Prepare the configuration file with the following fields:
# gitlab_username: <GitLab username>
# gitlab_access_token: <GitLab access token>
# github_username: <GitHub username>
# github_access_token: <GitHub access token>
# github_repo_owner: <GitHub repository owner>
# 6. Get ready the GitLab project ID and GitHub repository name
# 7. Get ready the GitLab and Github access tokens
# 8. Run the script with the following command:
# python gitlab2github_migrate.py <config_file> <gitlab_project_id> <github_repo_name>
import subprocess
import yaml
import sys
import os
root_dir = os.path.dirname(os.path.realpath(__file__))
def is_github_cli_logged_in():
try:
result = subprocess.run(
["gh", "auth", "status"], capture_output=True, text=True
)
if "Logged in to github.com" in result.stdout:
return True
else:
return False
except FileNotFoundError:
print("GitHub CLI is not installed.")
return False
def load_config(config_file):
with open(config_file, "r") as file:
config = yaml.safe_load(file)
return config
def check_config(config):
required_fields = [
"gitlab_username",
"gitlab_access_token",
"github_username",
"github_access_token",
"github_repo_owner",
]
result = True
for field in required_fields:
if field not in config:
print(f"Configuration file is missing {field}")
result = False
return result
def try_command(command):
try:
result = subprocess.run(
command,
capture_output=False,
text=True,
)
# if "Error" in result.stdout:
# return False
# else:
return True
except FileNotFoundError:
print("Command not found.")
return False
def get_github_repo_url(config, github_repo_name):
github_repo_owner = config.get("github_repo_owner")
github_access_token = config.get("github_access_token")
return f"https://{github_access_token}@github.com/{github_repo_owner}/{github_repo_name}.git"
def clone_repo_to_github(config, gitlab_project_id, github_repo_name):
folder_name = gitlab_project_id.split("/")[-1] + ".git"
full_folder_name = os.path.join(root_dir, folder_name)
github_repo_url = get_github_repo_url(config, github_repo_name)
print(f"folder_name: {folder_name}")
print(f"github_repo_url: {github_repo_url}")
try:
os.chdir(full_folder_name)
except FileNotFoundError:
print(f"Directory {folder_name} not found.")
return False
# try_command(["pwd"])
if not try_command(["git", "remote", "remove", "origin"]):
print(f"Error removing remote origin")
return False
if not try_command(["git", "remote", "add", "origin", github_repo_url]):
print(f"Error adding remote origin")
return False
if not try_command(["git", "push", "--mirror", "origin"]):
print(f"Error pushing to remote origin")
return False
try:
os.chdir(root_dir)
except FileNotFoundError:
print(f"Directory {root_dir} not found.")
# return Falseif
# try_command(["pwd"])
try:
os.system(f"rm -rf {folder_name}")
except FileNotFoundError:
print(f"Error removing directory {folder_name}")
# return False
print(f"Repository {folder_name} migrated to GitHub repository {github_repo_name}")
def get_gitlab_repo_url(config, gitlab_project_id):
gitlab_username = config.get("gitlab_username")
gitlab_access_token = config.get("gitlab_access_token")
return f"https://{gitlab_username}:{gitlab_access_token}@gitlab.com/{gitlab_project_id}.git"
def download_gitlab_repo(config, gitlab_project_id):
repo_url = get_gitlab_repo_url(config, gitlab_project_id)
print(f"repo_url: {repo_url}")
try:
result = subprocess.run(
[
"git",
"clone",
"--bare",
repo_url,
],
capture_output=True,
text=True,
)
if "Error" in result.stdout:
print(f"Error cloning GitLab repository {repo_url}")
return False
else:
print(f"GitLab repository {repo_url} cloned successfully")
return True
except FileNotFoundError:
print("Git is not installed.")
return False
def create_github_repo(config, repo_name):
owner = config.get("github_repo_owner")
if owner == None:
repo_location = repo_name
else:
repo_location = owner + "/" + repo_name
try:
result = subprocess.run(
["gh", "repo", "create", repo_location, "--private", "--confirm"],
capture_output=True,
text=True,
)
if "Error" in result.stdout:
print(f"Error creating GitHub repository {repo_location}")
return False
else:
print(f"GitHub repository {repo_location} created successfully")
return True
except FileNotFoundError:
print("GitHub CLI is not installed.")
return False
# Example usage
if __name__ == "__main__":
if len(sys.argv) != 4:
print(
"Usage: python gitlab2github_migrate.py <config_file> <gitlab_project_id> <github_repo_name>"
)
exit(1)
config_file = sys.argv[1]
gitlab_project_id = sys.argv[2]
github_repo_name = sys.argv[3]
config = load_config(config_file)
if not check_config(config):
exit(1)
if not is_github_cli_logged_in():
print("GitHub CLI is not logged in. Please run 'gh auth login'")
exit(1)
print("Migration Config")
print(yaml.dump(config, default_flow_style=False))
# Example usage
if __name__ == "__main__":
# Output
print("Begin migration...")
print("Create GitHub repository")
create_github_repo(config, github_repo_name)
print(get_gitlab_repo_url(config, gitlab_project_id))
result = download_gitlab_repo(config, gitlab_project_id)
if not result:
print("Error downloading GitLab repository")
exit(1)
clone_repo_to_github(config, gitlab_project_id, github_repo_name)
print("Migration complete.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment