import os import subprocess import argparse class Colors: HEADER = '\033[95m' BLUE = '\033[94m' GREEN = '\033[92m' YELLOW = '\033[93m' RED = '\033[91m' ENDC = '\033[0m' BOLD = '\033[1m' def print_colored(message, color, bold=False): """ Print a colored message to the terminal """ if bold: print(f"{Colors.BOLD}{color}{message}{Colors.ENDC}") else: print(f"{color}{message}{Colors.ENDC}") def create_new_branch(repo_path, branch_name): """ Create a new branch from 'develop' branch in the repository """ try: os.chdir(repo_path) print_colored(f"\n=== Creating new branch in repository: {repo_path} ===", Colors.HEADER, bold=True) if not os.path.exists('.git'): print_colored(f"The folder {repo_path} is not a git repository!", Colors.RED) return False current_branch = subprocess.check_output(['git', 'branch', '--show-current']).decode().strip() print_colored(f"Current branch: {current_branch}", Colors.BLUE) # Check if develop branch exists branches = subprocess.check_output(['git', 'branch', '-a']).decode() if 'develop' not in branches and 'origin/develop' not in branches: print_colored("The 'develop' branch does not exist!", Colors.RED) return False # First checkout develop branch subprocess.run(['git', 'checkout', 'develop'], check=True) print_colored("Switched to the 'develop' branch", Colors.GREEN) # Pull latest changes from develop print_colored("Pulling latest changes from develop...", Colors.BLUE) subprocess.run(['git', 'pull'], check=True) # Check if the new branch already exists if branch_name in branches: print_colored(f"Branch '{branch_name}' already exists!", Colors.YELLOW) return False # Create new branch from develop subprocess.run(['git', 'checkout', '-b', branch_name], check=True) print_colored(f"Successfully created and switched to branch: {branch_name}", Colors.GREEN) try: subprocess.run(['git', 'push', '-u', 'origin', branch_name], check=True) print_colored("Successfully pushed new branch to remote", Colors.GREEN) except subprocess.CalledProcessError: print_colored("Failed to push branch to remote. Branch created locally only.", Colors.YELLOW) return True except subprocess.CalledProcessError as e: print_colored(f"Error while working with git: {str(e)}", Colors.RED) return False except Exception as e: print_colored(f"An unexpected error occurred: {str(e)}", Colors.RED) return False def git_checkout_and_pull(repo_path): """ Switch to the 'develop' branch and pull the latest changes for the given repository. """ try: os.chdir(repo_path) print_colored(f"\n=== Processing repository: {repo_path} ===", Colors.HEADER, bold=True) if not os.path.exists('.git'): print_colored(f"The folder {repo_path} is not a git repository!", Colors.RED) return False current_branch = subprocess.check_output(['git', 'branch', '--show-current']).decode().strip() print_colored(f"Current branch: {current_branch}", Colors.BLUE) branches = subprocess.check_output(['git', 'branch', '-a']).decode() if 'develop' not in branches and 'origin/develop' not in branches: print_colored("The 'develop' branch does not exist!", Colors.RED) return False subprocess.run(['git', 'checkout', 'develop'], check=True) print_colored("Switched to the 'develop' branch", Colors.GREEN) subprocess.run(['git', 'pull'], check=True) print_colored("Successfully pulled the latest changes", Colors.GREEN) return True except subprocess.CalledProcessError as e: print_colored(f"Error while working with git: {str(e)}", Colors.RED) return False except Exception as e: print_colored(f"An unexpected error occurred: {str(e)}", Colors.RED) return False def load_repositories(config_file): """ Load repository paths from a configuration file. """ try: with open(config_file, 'r') as file: repositories = [line.strip() for line in file if line.strip()] return repositories except FileNotFoundError: print_colored(f"Configuration file '{config_file}' not found!", Colors.RED) return [] except Exception as e: print_colored(f"An error occurred while reading the configuration file: {str(e)}", Colors.RED) return [] def main(): # Setup argument parser with detailed help parser = argparse.ArgumentParser( prog='mob_repos.py', description=''' Git repository management script for multiple repositories. This script helps manage multiple Git repositories defined in repos.txt file. It can perform bulk operations like switching to develop branch, pulling latest changes, or creating new branches across all repositories. ''', epilog=''' Examples: python3 mob_repos.py # Switch to develop and pull in all repos python3 mob_repos.py -bc feature/GND1111-testing-repo # Create new branch from develop in all repos python3 mob_repos.py --help # Show this help message ''', formatter_class=argparse.RawDescriptionHelpFormatter ) parser.add_argument( '-bc', '--branch-create', help='Create a new branch from develop in all repositories (e.g., feature/GND1111-testing-repo)', metavar='BRANCH_NAME' ) parser.add_argument( '-c', '--config', help='Path to configuration file (default: repos.txt)', default='repos.txt', metavar='CONFIG_FILE' ) args = parser.parse_args() # Load repository paths print_colored("Loading repositories from configuration file...", Colors.BLUE) repositories = load_repositories(args.config) if not repositories: print_colored("No repositories found in the configuration file. Exiting.", Colors.RED) return print_colored(f"Found {len(repositories)} repositories", Colors.GREEN) # Save the original working directory original_dir = os.getcwd() # Process each repository success_count = 0 fail_count = 0 for repo in repositories: if not os.path.exists(repo): print_colored(f"Repository {repo} does not exist!", Colors.RED) fail_count += 1 continue if args.branch_create: success = create_new_branch(repo, args.branch_create) else: success = git_checkout_and_pull(repo) if success: success_count += 1 else: fail_count += 1 os.chdir(original_dir) # Print summary print_colored("\n=== Summary ===", Colors.HEADER, bold=True) print_colored(f"Successfully processed: {success_count} repositories", Colors.GREEN) if fail_count > 0: print_colored(f"Failed: {fail_count} repositories", Colors.RED) print_colored("Script execution completed!", Colors.GREEN) if __name__ == "__main__": main()