-
-
Save asakasinsky/b801cb11ce3276134b4351e20d729efa to your computer and use it in GitHub Desktop.
Script for mirroring repositories
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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