tools/infra_scripts/migration/migration.py (115 lines of code) (raw):

import os import sys import subprocess import shutil from pathlib import Path def error(message): print(f"ERROR: {message}", file=sys.stderr) def check_git_filter_repo(): if shutil.which("git-filter-repo") is None: error("git-filter-repo is not installed or not in your PATH.") print("To install git-filter-repo, follow these steps:") print("0. On macOS simply run 'brew install git-filter-repo'") print("If you don't have homebrew installed, or not on macOS:") print("1. Ensure you have Python 3 installed.") print("2. Run: pip3 install git-filter-repo") print("3. Make sure the installation directory is in your PATH.") print("For more information, visit: https://github.com/newren/git-filter-repo") return False return True def setup_monorepo(monorepo): if monorepo.startswith(("http", "git@")): monorepo_dir = Path(monorepo).stem if not Path(monorepo_dir).is_dir(): result = subprocess.run(["git", "clone", monorepo, monorepo_dir], check=False) if result.returncode != 0: error(f"Failed to clone {monorepo}") return None else: monorepo_dir = monorepo.lstrip("./") if not Path(monorepo_dir).is_dir(): error(f"Directory {monorepo_dir} does not exist") return None return monorepo_dir def setup_unmerged_repo(unmerged_repo, unmerged_dir): if unmerged_repo.startswith(("http", "git@")): result = subprocess.run(["git", "clone", unmerged_repo, unmerged_dir], check=False) if result.returncode != 0: error(f"Failed to clone {unmerged_repo}") return False else: try: shutil.copytree(unmerged_repo, unmerged_dir) except shutil.Error: error(f"Failed to copy {unmerged_repo}") return False return True def get_subdirectory(repo_name): repo_name = Path(repo_name).stem subdirs = { "bazel-bsp": "server", "intellij-bsp": "plugin-bsp", "intellij-bazel": "plugin-bazel" } return subdirs.get(repo_name) def migrate_branch(monorepo, unmerged_repo, branch_name_to_migrate): subdir = get_subdirectory(unmerged_repo) if not subdir: error(f"Unknown repository name: {unmerged_repo}") return False repo_name = Path(unmerged_repo).stem base_dir = Path.cwd() monorepo_dir = setup_monorepo(monorepo) if not monorepo_dir: error("Failed to setup monorepo") return False unmerged_dir = base_dir / "temp_unmerged" if not setup_unmerged_repo(unmerged_repo, unmerged_dir): error("Failed to setup unmerged repo") return False os.chdir(unmerged_dir) result = subprocess.run(["git", "checkout", branch_name_to_migrate], check=False) if result.returncode != 0: error(f"Failed to checkout branch {branch_name_to_migrate}") return False print("Running git-filter-repo...") result = subprocess.run(["git-filter-repo", "--to-subdirectory-filter", subdir, "--force"], check=False) if result.returncode != 0: error("git-filter-repo failed") return False os.chdir(base_dir / monorepo_dir) subprocess.run(["git", "remote", "add", "unmerged", str(unmerged_dir)], check=True) subprocess.run(["git", "fetch", "unmerged"], check=True) new_branch = f"{subdir}/{branch_name_to_migrate}" subprocess.run(["git", "checkout", "-b", new_branch], check=True) result = subprocess.run([ "git", "merge", f"unmerged/{branch_name_to_migrate}", "--allow-unrelated-histories", "-m", f"Migrate {branch_name_to_migrate} from {repo_name} to {subdir}" ], check=False) if result.returncode != 0: error("Failed to merge branch") return False subprocess.run(["git", "remote", "remove", "unmerged"], check=True) print(f"Migration completed. New branch '{new_branch}' created in {monorepo_dir}") print("You can now push this branch to your fork of the monorepo.") os.chdir(base_dir) shutil.rmtree(unmerged_dir) return True def main(): if not check_git_filter_repo(): sys.exit(1) if len(sys.argv) != 4: error("Incorrect number of arguments") print("Usage: python script.py <monorepo> <unmerged_repo> <branch_name_to_migrate>") print("Examples:") print(" python script.py https://github.com/user/hirschgarten https://github.com/user/bazel-bsp branch_name_to_migrate") print(" python script.py git@github.com:user/hirschgarten.git git@github.com:user/bazel-bsp.git branch_name_to_migrate") print(" python script.py ./hirschgarten ./bazel-bsp branch_name_to_migrate") sys.exit(1) if not migrate_branch(sys.argv[1], sys.argv[2], sys.argv[3]): error("Migration failed") sys.exit(1) print("Migration completed successfully") if __name__ == "__main__": main()