Skip to content

Instantly share code, notes, and snippets.

@asakasinsky
Forked from pcheng17/gh-mirror.py
Created August 20, 2024 20:47
Show Gist options
  • Save asakasinsky/b801cb11ce3276134b4351e20d729efa to your computer and use it in GitHub Desktop.
Save asakasinsky/b801cb11ce3276134b4351e20d729efa to your computer and use it in GitHub Desktop.
Script for mirroring repositories
import os
import subprocess
import requests
import logging
from logging.handlers import RotatingFileHandler
logger = logging.getLogger("gh-mirror.py")
logfile = os.path.join(os.path.dirname(__file__), "logs", "gh-mirror.log")
logdir = os.path.dirname(logfile)
if not os.path.exists(logdir):
os.makedirs(logdir)
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.StreamHandler(),
RotatingFileHandler(filename=logfile,
maxBytes=512000,
backupCount=4)
]
)
def load_dotenv(dotenv_file='.env'):
try:
with open(dotenv_file) as f:
for line in f:
line = line.strip()
if not line or line.startswith('#'):
continue
key, value = line.split('=', 1)
os.environ[key] = value
except FileNotFoundError:
logging.error(f"Error: '{dotenv_file}' file not found.")
def run_command(command):
try:
return subprocess.check_output(command, stderr=subprocess.STDOUT, shell=True, universal_newlines=True)
except subprocess.CalledProcessError as e:
logging.error(f"Command '{e.cmd}' returned non-zero exit status {e.returncode}. Output:\n{e.output}")
def get_github_repos(github_username, github_token):
"""Fetch a list of all GitHub repositories for the authenticated user with pagination."""
repos = []
page = 1
while True:
url = f"https://api.github.com/user/repos?visibility=all&per_page=100&page={page}"
headers = {'Authorization': f'token {github_token}'}
response = requests.get(url, headers=headers)
if response.status_code == 200:
page_repos = response.json()
if not page_repos:
break # No more repositories to fetch
repos.extend([repo for repo in page_repos if repo['owner']['login'] == github_username])
page += 1
else:
logging.error(f"Failed to fetch GitHub repos (HTTP status: {response.status_code}).")
break
return repos
def create_gitlab_repo(gitlab_token, repo_name, gitlab_group_id):
headers = {'PRIVATE-TOKEN': gitlab_token}
data = {'name': repo_name, 'namespace_id': gitlab_group_id}
response = requests.post('https://gitlab.com/api/v4/projects', headers=headers, data=data)
return response.status_code
def mirror_repo_to_gitlab(github_username, repo_name, gitlab_group_name):
run_command(f'git clone --mirror [email protected]:{github_username}/{repo_name}.git {repo_name}')
os.chdir(repo_name)
run_command(f'git remote add gitlab [email protected]:{gitlab_group_name}/{repo_name}.git')
run_command('git config --local --replace remote.origin.fetch "+refs/heads/*:refs/heads/*"')
run_command('git config --local --add remote.origin.fetch "+refs/tags/*:refs/tags/*"')
run_command('git config --local --add remote.origin.fetch "+refs/change/*:refs/change/*"')
run_command('git config --local --replace remote.gitlab.push "+refs/heads/*:refs/heads/*"')
run_command('git config --local --add remote.gitlab.push "+refs/tags/*:refs/tags/*"')
run_command('git config --local --add remote.gitlab.push "+refs/change/*:refs/change/*"')
run_command('git push --mirror gitlab')
os.chdir('..')
run_command(f'rm -rf {repo_name}')
def main():
load_dotenv()
github_username = os.environ.get('GITHUB_USERNAME', 'Github username not set')
# gitlab_username = os.environ.get('GITLAB_USERNAME', 'GitLab username not set')
github_token = os.environ.get('GITHUB_TOKEN', 'GitHub token not set')
gitlab_token = os.environ.get('GITLAB_TOKEN', 'GitLab token not set')
gitlab_group_id = os.environ.get('GITLAB_GROUP_ID', 'GitLab group ID not set')
gitlab_group_name = os.environ.get('GITLAB_GROUP_NAME', 'GitLab group name not')
repos = get_github_repos(github_username, github_token)
logging.info(f"Found {len(repos)} repositories on GitHub")
for repo in repos:
repo_name = repo['name']
logging.info(f"Mirroring {repo_name}")
status = create_gitlab_repo(gitlab_token, repo_name, gitlab_group_id)
if status == 201:
logging.debug(f"Repository {repo_name} created on GitLab")
elif status == 400:
logging.debug(f"Repository {repo_name} already exists on GitLab")
else:
logging.error(f"An unexpected error occurred while creating {repo_name} on GitLab (HTTP status: {status}).")
continue
mirror_repo_to_gitlab(github_username, repo_name, gitlab_group_name)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment