def main(): args = create_parser().parse_args() threads = int(args.threads) EXEC = threadly.Scheduler(threads) server_domain = args.server_url if args.server_url[:8] == "https://": server_domain = args.server_url[8:] elif args.server_url[:7] == "http://": server_domain = args.server_url[7:] if os.environ.get('BBMIGRATE_IN_DOCKER') == "true": open("{}/.gitconfig".format(str(Path.home())), "w").write("[credential]\n helper = store\n") open("{}/.git-credentials".format(str(Path.home())), "w").write("https://{}:{}@{}\nhttps://{}:{}@{}\n".format( args.server_user, urllib.parse.quote(args.server_pass), server_domain, args.cloud_user, urllib.parse.quote(args.cloud_pass), "bitbucket.org")) # setting up directory for repo clones dir_name = os.path.abspath(args.repo_path) clone_dir = dir_name try: if not os.path.isdir(clone_dir): os.mkdir(clone_dir) except OSError: logger.exception(f'Failed to create directory {clone_dir}') sys.exit(1) logger.info("Saving repos to path:{}".format(clone_dir)) # initializing Bitbucket Server instance try: bitbucket_server = Bitbucket(url=args.server_url, username=args.server_user, password=args.server_pass) except Error: logger.exception( f'Unable to instantiate Bitbucker Server connection! One or more parameters may be missing or malformed.' ) sys.exit(1) try: projects_gen = bitbucket_server.project_list() except Error: logger.exception( f'Failed to retrieve data from Bitbucket Server {args.server_url}') sys.exit(1) projects = [] logger.info( f'Retrieving projects and repos from Bitbucket Server {args.server_url}' ) for p in projects_gen: new_project_key = p['key'].replace("-", "") project_dir = os.path.join(clone_dir, new_project_key) p['project_dir'] = project_dir p['new_project_key'] = new_project_key projects.append(p) try: repos = bitbucket_server.repo_list(project_key=p['key']) except Error: logger.exception( "Failed to gather repository list from Bitbucket Server project {}" .format(p['name'])) sys.exit(1) logger.info( "Retrieving repositories from Bitbucket Server project {}".format( p['name'])) p['repos'] = [] for r in repos: new_repo_name = new_project_key.lower() + "." + r['slug'].lower() repo_dir = os.path.join(project_dir, r['slug']) new_repo_git = "https://bitbucket.org/" + args.workspace + "/" + new_repo_name + ".git" old_repo_git = "" for href in r['links']['clone']: if href['href'][:8] == "https://": old_repo_git = href['href'] break r['old_repo_git'] = old_repo_git r['new_repo_git'] = new_repo_git r['new_repo_name'] = new_repo_name r['repo_dir'] = repo_dir p['repos'].append(r) p['repos'] = sorted(p['repos'], key=lambda k: k['slug']) projects = sorted(projects, key=lambda k: k['key']) processing = [] logger.info("Duplicating projects on BBCloud") for p in projects: proj = p f = EXEC.schedule_with_future(bbcloud.duplicate_project, args=(args.cloud_user, args.cloud_pass, args.workspace, proj)) processing.append(f) for lf in processing: lf.get() processing = [] logger.info("Duplicating repos and cloning them on BBCloud") for project in projects: project_name = project['name'] project_dir = project['project_dir'] try: os.mkdir(project_dir) except: pass for repo in project['repos']: p = project r = repo f = EXEC.schedule_with_future( git.backupRepo, args=(args.cloud_user, args.cloud_pass, args.workspace, p, r, clone_dir, args.no_remove_repos)) processing.append(f) if len(processing) > 10: for lf in processing: lf.get() processing = [] for lf in processing: lf.get() # When it's all over, remove the tmp dir to keep things tidy if not args.no_remove_repos: try: os_system_string = "rm -rf " + clone_dir os.system(os_system_string) except OSError: logger.exception(f'Failed to remove temp directory {clone_dir}') sys.exit(1)
def main(): parser = create_parser() parser_namespace = parser.parse_args(sys.argv[1:]) bitbucket_url = parser_namespace.bitbucket bitbucket_user = parser_namespace.user bitbucket_pass = parser_namespace.passwd project_model_path = parser_namespace.file project_key = ntpath.basename(project_model_path).replace('_meta.yaml', '') project_map = yaml_read(project_model_path) if project_map['READY']: project_map = yaml_read(project_model_path) if project_map['RESOURCES'] and project_map['RESOURCES']['bitbucket']: project_model_bitbucket = project_map['RESOURCES']['bitbucket'] project_name = project_model_bitbucket['name'] project_description = project_model_bitbucket['description'] bitbucket = Bitbucket(url=bitbucket_url, username=bitbucket_user, password=bitbucket_pass) bb_projects = bitbucket.project_list(limit=9999) if next( (i for i in bb_projects if i['key'] == project_key.upper()), None): print(f'INFO: BitBucket project {project_key} already exists') else: bitbucket.create_project(project_key, project_name, description=project_description) print(f'INFO: BitBucket project {project_key} created') for group in project_model_bitbucket['privileges']: if 'delete' in project_model_bitbucket['privileges'][group]: bitbucket.project_grant_group_permissions( project_key, f'rb-{project_key}-{group}', 'PROJECT_ADMIN') print( f'INFO: rb-{project_key}-{group} PROJECT_ADMIN granted' ) elif 'write' in project_model_bitbucket['privileges'][group]: bitbucket.project_grant_group_permissions( project_key, f'rb-{project_key}-{group}', 'PROJECT_WRITE') print( f'INFO: rb-{project_key}-{group} PROJECT_WRITE granted' ) elif 'read' in project_model_bitbucket['privileges'][group]: bitbucket.project_grant_group_permissions( project_key, f'rb-{project_key}-{group}', 'PROJECT_READ') print( f'INFO: rb-{project_key}-{group} PROJECT_READ granted') else: print('MAP NOT READY')
# coding=utf-8 from atlassian import Bitbucket from pprint import pprint bitbucket = Bitbucket(url='http://localhost:7990', username='******', password='******') pprint(bitbucket.project_list())
class Server: """ Class that represents the BitBucket server. Has methods to perform queries on the server. """ def __init__(self, url: str, user: str, password: str): """ C'tor of Server. :param str url: URL of the BitBucket server :param str user: Login username :param str password: Login password or token """ self.server_url = url self.user = user self.password = password self.api = Bitbucket(self.server_url, self.user, self.password) def project_list(self) -> List[str]: """ Get the list of projects from the server. :return: List of project names """ query = self.api.project_list() return query def pr_approved(self, project: str, repo: str, pr: int) -> bool: """ Return True if at least one reviewer approved the pull request, otherwise False. :param: project Project ID of the repository :param: repo Repository slug of the pull request :param: pr Pull request ID :returns: True if one reviewer approved the pull request, otherwise False """ query = self.api.get_pull_request(project, repo, pr) for reviewer in query["reviewers"]: if reviewer["approved"]: return True return False def open_pr_in_repo( self, project: str, repo: str, src_branch: str, dst_branch: str, title: str, desc: str, reviewers: str = None, ): """ Open a new pull request in a repository. :param project: Project name :param repo: Repository name :param src_branch: Source branch name :param dst_branch: Destination branch name :param title: Title of the pull request :param desc: Description text of the pull request :param reviewers: UUIDs of reviewers (default None) """ self.open_pr(project, repo, src_branch, project, repo, dst_branch, title, desc, reviewers) def open_pr( self, src_project: str, src_repo: str, src_branch: str, dst_project: str, dst_repo: str, dst_branch: str, title: str, desc: str, reviewers: str = None, ): """ Open a new pull request. :param src_project: Source project name :param src_repo: Source repository name :param src_branch: Source branch name :param dst_project: Destination project name :param dst_repo: Destination repository name :param dst_branch: Destination branch name :param title: Title of the pull request :param desc: Description text of the pull request :param reviewers: UUIDs of reviewers (default None) """ logging.info("Attempting to open a pull request:") logging.info(title) logging.info(desc) if self._confirm("Open pull request " + src_project + "/" + src_repo + "/" + src_branch + "->" + dst_project + "/" + dst_repo + "/" + dst_branch): self.api.open_pull_request( src_project, src_repo, dst_project, dst_repo, src_branch, dst_branch, title, desc, reviewers, ) print("Success") else: print("Action aborted") @staticmethod def _confirm(question: str) -> bool: """Ask for user decision on question.""" reply = str(input(question + " (y/n): ")).lower().strip() return reply[0] == "y"