def get_forked_project(git_repository, clean, verbosity): """ Function to get the forked project based on the git repository name and id. :param git_repository: Name of the project :type git_repository: str :return: Returns the project dict. :rtype: dict """ forked_project = None projects = get_personal_projects() if verbosity: print("\n\n List of projects: ") fmt = '{:<20}{:<20}{}' print(fmt.format('', 'Owner', 'Project name'), "\n") for i, proj in enumerate(projects): if git_repository != proj['name']: print(fmt.format(i, proj['username'], proj['name'])) else: print(fmt.format(str(i)+' --->', proj['username'], proj['name'])) for project in projects: if ( project['username'] == get_username() and project['name'] == git_repository and 'forked_from_project' in project ): forked_project = project break if forked_project is None and not clean: raise gitutils_exception.GitutilsError( const.PROJECT_FOUND_NOT_FORK) return forked_project
def get_group_projects(group_name, pattern=None): """ Retrieves all the projects of a group, which is given as parameter. :param group_name: Name of the group of interest. :type group_id: str :param pattern: Pattern used to search projects :type pattern: str :return: List of the projects (for the specified group id) containing name, id, path and url (in a dictionary-type). :rtype: list """ if group_name == get_username(): group_id = 0 if pattern: group_projects = gl.projects.list( owned=True, all=True, search=pattern) else: group_projects = gl.projects.list(owned=True, all=True) return get_dict_from_own_projects(group_projects) # Retrieve the group's projects group_id = get_group_id(group_name) try: if pattern: group_projects = gl.groups.get( group_id).projects.list(all=True, search=pattern) else: group_projects = gl.groups.get(group_id).projects.list(all=True) except Exception as ex: try: user = gl.users.list(username=group_name, all=True)[0] group_projects = user.projects.list(all=True) except Exception as ex: raise gitutils_exception.GitutilsError(ex) return get_dict_from_own_projects(group_projects)
def connect_gl(access_token): global gl try: gl = gitlab.Gitlab(get_endpoint(), oauth_token=access_token, api_version=4) gl.auth() except Exception as ex: raise gitutils_exception.GitutilsError(ex)
def get_project_group_simplified(project_name): projects_list = gl.projects.list(search=project_name, all=True) list_of_groups = [] for project in projects_list: if project_name == project.attributes['name']: project_path = project.attributes['path_with_namespace'] # verify if it's a personal project groupFound = project_path.split('/')[0] list_of_groups.append(groupFound) if len(list_of_groups) == 1: return groupFound elif len(list_of_groups) >= 2: # if there is a personal group if get_username() in list_of_groups: print("\nGitutils warning: "+const.GROUP_NOT_SPECIFIED_ASSUME_USER) return get_username() raise gitutils_exception.GitutilsError( const.MULTIPLE_PROJECTS % (list_of_groups)) raise gitutils_exception.GitutilsError(const.PROJECT_NAME_NOT_FOUND)
def get_user_password(): global login global password login = input(const.LOGIN_REQUEST) password = getpass.getpass(prompt=const.PASSWORD_REQUEST) try: access_token = oauth_authentication()['access_token'] except Exception as ex: raise gitutils_exception.GitutilsError(ex) return access_token
def get_project_group(project_name, clean, merge, project_indication): """ Function to get the group of a project based on its name. :param project_name: Name of the project :type project_name: str :return: Returns the name of the group. :rtype: str """ projects_list = gl.projects.list(search=project_name, all=True) list_of_groups = [] for project in projects_list: if project_name == project.attributes['name']: if merge: if check_key(project.attributes, 'forked_from_project'): groupFound = \ project.attributes['path_with_namespace'].split('/')[0] list_of_groups.append(groupFound) else: project_path = project.attributes['path_with_namespace'] # verify if it's a personal project if project_path.split('/')[0] == get_username(): # if it's personal, it should be cleaned if clean: delete_project(project.attributes['id']) else: raise gitutils_exception.GitutilsError( const.GIT_FORK_PROBLEM_MULTIPLE) else: # not a personal project groupFound = project_path.split('/')[0] list_of_groups.append(groupFound) if len(list_of_groups) == 1 and project_indication: return groupFound elif len(list_of_groups) >= 2: # if there is a personal group if get_username() in list_of_groups: print("Gitutils warning: "+const.GROUP_NOT_SPECIFIED_ASSUME_USER) return get_username() raise gitutils_exception.GitutilsError( const.MULTIPLE_PROJECTS % (list_of_groups)) if not project_indication: raise gitutils_exception.GitutilsError(const.PROJECT_NAME_NOT_FOUND)
def delete_project(project_id): """ Deletes the project given as parameter :return: """ try: gl.projects.delete(project_id) except Exception as ex: raise gitutils_exception.GitutilsError(ex) print(const.DELETE_SUCCESS) time.sleep(2) return 0
def fork_project(project_id, fork_group_indication, group_name): """ Creates a fork of the project given as parameter. :param project_id: ID of the project that wants to be forked. :type project_id: int """ project = gl.projects.get(project_id) try: if fork_group_indication: fork = project.forks.create({'namespace': group_name}) else: fork = project.forks.create({}) except Exception as ex: if ex.error_message['path'][0] == const.GIT_PATHNAME_IS_TAKEN: raise gitutils_exception.GitutilsError(const.FORKED_EXISTS) raise gitutils_exception.GitutilsError(ex) logging.info( 'Adding 3 seconds of idle time after forking to let the server process the new fork.') time.sleep(4) logging.info('Forked project id %d' % project_id) return fork
def get_owned_projects(): """ Retrieves the projects owned by the current user. :return: List of projects containing name, path and url (in a dictionary-type). :rtype: dict """ try: own_projects = gl.projects.list(owned=True) except Exception as ex: raise gitutils_exception.GitutilsError(ex) return get_dict_from_own_projects(own_projects)
def get_project_http_url(project_name): """ Function to get the web_url attribute of a project based on its name. :param project_name: Name of the project :type project_name: str :return: Returns the web url to the project. :rtype: str """ projects_list = gl.projects.list(search=project_name, all=True) for project in projects_list: if project_name == project.attributes['name']: return project.attributes['http_url_to_repo'] raise gitutils_exception.GitutilsError(const.PROJECT_NAME_NOT_FOUND)
def check_existing_local_git(git_repository, verbosity): # verify if there is an previously existing local folder if os.path.exists('./' + git_repository): print(const.DELETING_LOCAL_STORAGE) if verbosity: print(" \t (-v) Gitutils fork detected a local folder with the same name.") if not click.confirm(const.DELETE_LOCAL_CONFIRMATION, default=True): raise gitutils_exception.GitutilsError( const.NO_PERMISSION_TO_DELETE_LOCAL_FOLDER) try: shutil.rmtree(git_repository) except OSError as e: print("Error: %s - %s." % (e.filename, e.strerror))
def add_ldap(git_group, ldap_cn, role): """ Assign ldap group sync to a git group :param ldap_cn: LDAP USER CN (common name) :type ldap_cn: str :param git_group: Git group that the ldap will be added :type git_group: str :param role: Role that will be given to the user :type role: str :return: """ print(const.ADDLDAP_INIT_MSG % ( const.bcolors.BOLD, ldap_cn, role, const.bcolors.ENDC, const.bcolors.BOLD, git_group, const.bcolors.ENDC, )) # verify if ldap_cn is a real ldap group list_of_ldap_cns = gitlab_utils.get_ldap_groups(ldap_cn) found = False # verifies if the ldap group is actually a ldap group for i in list_of_ldap_cns: if ldap_cn == i.attributes['cn']: found = True # gets group id group_id = -1 try: group_id = gitlab_utils.get_group_id(git_group) except Exception as ex: raise gitutils_exception.GitutilsError(ex) if found is True and group_id != -1: gitlab_utils.addldapgroup(git_group, group_id, ldap_cn, role) else: gitutils_exception.GitutilsError(const.ADDLDAP_LDAP_NAME_PROBLEM)
def get_project_id_without_group(project_name): """ Function to get the id attribute of a project without providing the group. project name. :param project_name: Name of the project :type project_name: str :return: Returns the id of the project. :rtype: str """ projects_list = gl.projects.list(search=project_name, all=True) for project in projects_list: if project.attributes['name'] == project_name: logging.info('Found the project id ( %s - %s ) : %s' % ( project.attributes['path_with_namespace'].split( '/')[0], project_name, project.attributes['id'])) return project.attributes['id'] raise gitutils_exception.GitutilsError(const.PROJECT_ID_NOT_FOUND)
def create_group(group_name, description): """ Creates a group based on the name given as parameter and its description. :param group_name: Name of the group that will be created. :type group_name: str :param description: Description of the group that will be created. :type description: str :return: Returns 0 if successful or -1 if a problem occurred. :rtype: int """ try: gl.groups.create({'name': group_name, 'path': group_name, 'description': description}) except Exception as ex: raise gitutils_exception.GitutilsError(ex) return 0
def get_group_id(group_name): """ Retrieves the group id based on the group name given as parameter. :param group_name: Name of the group of interest. :type group_name: str :return: ID of the group given as parameter or -1 in case of a problem. :rtype: int """ group_id = -1 # it could be a personal group -> group name == username try: group_id = gl.groups.get(group_name).attributes['id'] except Exception as ex: # group not found, it should be a personal group try: group_id = gl.users.list(username=group_name, all=True)[ 0].attributes['id'] except Exception as ex: raise gitutils_exception.GitutilsError("Group not found.") if group_id != -1: logging.info('Group name: %s (id %s)' % (group_name, group_id)) return group_id
def create_merge_request(source_tuple, target_tuple, merge_def): """ Creates a merge request based on the parameters given. :param source_tuple: Tuple from the source project containing id and source branch :type source_tuple: tuple :param target_tuple: Tuple from the target project containing id and source branch :type target_tuple: tuple :param merge_def: Definition of the new merge request containing title and description :type merge_def: tuepl :return: Returns 0 if successful or -1 if a problem occurred. :rtype: int """ project = gl.projects.get(source_tuple[0], lazy=True) try: mr = project.mergerequests.create({ 'source_branch': 'master', 'target_branch': 'master', 'title': merge_def[0], 'description': merge_def[1], 'target_project_id': target_tuple[0], }) except Exception as ex: if const.MERGE_DUPLICATED in ex.error_message[0]: raise gitutils_exception.GitutilsDebug(const.MERGE_DUPLICATED) raise gitutils_exception.GitutilsError(ex) logging.info('Creating merge request %s (Description: %s). Source project \ id/branch: %s - %s. Target project id/branch: %s - %s' % ( merge_def[0], merge_def[1], source_tuple[0], 'master', target_tuple[0], 'master')) return mr
def create_repo(repo_name, namespace): """ Creates a repository (project) with the name (given as parameter) under the specified namespace (also given as parameter). :param repo_name: Name of the repository that will be created. :type repo_name: str :param namespace: Namespace which the new repository will belong. :type namespace: str :return: Dictionary containing the details of the newly created repository, including name, path and url. :rtype: dict """ namespace_group = gl.groups.get(namespace, lazy=True) try: project = gl.projects.create({ 'name': repo_name, 'namespace_id': namespace_group.attributes['id']}) except Exception as ex: raise gitutils_exception.GitutilsError(ex) return {'name': project.attributes['name'], 'path': project.attributes['path_with_namespace'], 'url': project.attributes['ssh_url_to_repo']}
def get_branch(project_id): """ Function to check if there is a 'master' branch on the project. :param project_id: Id of the project :type project_id: int :return: Returns the name of the branch. :rtype: str """ # Get a project by ID project = gl.projects.get(project_id, lazy=True) # Verifies if there is a master branch to merge into branch = project.branches.get('master') if branch.attributes['name']: logging.info('Master branch found within project id %s. ' % project_id) return 'master' raise gitutils_exception.GitutilsError( const.GIT_UNABLE_TO_FIND_MASTER_BRANCH % project['name'])
def create_groups(group_names=[]): """ It create groups based on the list provided. : param group_name : List of name(s) of group to be created : type group_name : list """ total_group_names = len(group_names) if total_group_names < 1: gitutils_exception.GitutilsError(const.PROBLEM_CREATEGROUP_EMPTY) count = 1 print(const.CREATEGROUP_START) for group_name in group_names: # check if group exists if not gitlab_utils.group_exists(group_name): print(const.CREATEGROUP_CREATING % (count, group_name), end="") gitlab_utils.create_group(group_name, "-") time.sleep(1) group_id = gitlab_utils.get_group_id(group_name) if group_id != -1: print(const.CREATEGROUP_ID % group_id) count += 1 else: print(const.CREATEGROUP_TAKEN % group_name) print(const.CREATEGROUP_END % (count - 1, total_group_names))
def set_role(role, username, git_groups, project_flag): """ Sets a role to a specified user in a specified group or project :param role: Role that will be given to the user. :type role: int :param username: Username :type username: str :param git_group: Group or project names :type git_group: list :param project_flag: Flag to indicate project-level role. :type project_flag: bool :return: """ # gets user_id user_id = gitlab_utils.get_user_id(username) if user_id == -1: raise gitutils_exception.GitutilsError( const.ROLE_SETROLE_PROBLEM_USERID) ################# # GROUP SETROLE # ################# if not project_flag: for git_group in git_groups: group_id = gitlab_utils.get_group_id(git_group) print(const.SETROLE_INIT_MSG % ( const.bcolors.BOLD, role, const.bcolors.ENDC, const.bcolors.BOLD, username, user_id, const.bcolors.ENDC, const.bcolors.BOLD, git_group, group_id, const.bcolors.ENDC, ), end="") # gets group group = gitlab_utils.get_group(git_group) # adds member with the desired access level to the group group.members.create({'user_id': user_id, 'access_level': role}) # verification members = group.members.all(all=True) found = any(member.attributes['username'] == username for member in members) if not found: print(' ⨯') raise gitutils_exception.GitutilsError( const.SETROLE_PROJECT_VALIDATION_FAILS) print(' ✓') else: ################### # PROJECT SETROLE # ################### # git_groups has projects for project_name in git_groups: print(const.SETROLE_P_INIT_MSG % ( const.bcolors.BOLD, username, role, const.bcolors.ENDC, const.bcolors.BOLD, project_name, const.bcolors.ENDC, ), end="") # gets group name group_name = gitlab_utils.get_project_group_simplified( project_name) # gets project id project_id = gitlab_utils.get_project_id(group_name, project_name) # gets the project project = gitlab_utils.get_project(project_id) # adds member with the desired role to the project project.members.create({'user_id': user_id, 'access_level': role}) # verification members = project.members.all(all=True) found = any(member.attributes['username'] == username for member in members) if not found: print(' ⨯') raise gitutils_exception.GitutilsError( const.SETROLE_PROJECT_VALIDATION_FAILS) print(' ✓')
def merge(verbosity, git_repository='', git_repository_id='', description='', title=''): """ Creates a merge request to merge a forked repository. :param git_group_id: Id of the group to be pulled from. :type git_group_id: int :param git_repository: Name of the repository to be pulled. :type git_repository: str :param description: Description of the merge request. :type description: str :param title: Title of the merge request. :type title: str :return: """ if verbosity: print(" Verbose Gitutils: ") git_username = gitlab_utils.get_username() if verbosity: print(" \t (-v) Gitutils merge username: "******" \t (-v) Gitutils merge title: ", title) if forked_project is None: if verbosity: print(" \t (-v) Gitutils merge forked project not found.") raise gitutils_exception.GitutilsError(const.GIT_MERGE_PROBLEM_2) print(const.GIT_CREATE_MERGE_MSG) final_description = const.GIT_MERGE_DESCRIPTION_MSG \ % git_username if description is not None: final_description += ' User description: ' + description if verbosity: print(" \t (-v) Gitutils merge definition: ", title) # Merge will be from source and target masters branches source_branch = 'master' target_branch = 'master' try: forked_from_project_id = forked_project['forked_from_project']['id'] except: raise gitutils_exception.GitutilsError(const.GIT_MERGE_PROBLEM_3) try: if verbosity: print(" \t (-v) Gitutils forked project details: ", forked_from_project_id) merge_request = gitlab_utils.create_merge_request( (git_repository_id, source_branch), (forked_project['forked_from_project']['id'], target_branch), (title, final_description)) if merge_request.attributes['id']: print(const.GIT_MERGE_SUCCESS % (merge_request.attributes['id'], merge_request.attributes['created_at'])) except Exception as ex: raise gitutils_exception.GitutilsError(ex)
def fork(verbosity, fork_group_indication='', group_name='', git_repository_id=None, git_repository='', no_clone=False): """ Creates a fork repository of the repository given as parameter. :param git_repository_id: Id of the repository to be pulled. :type git_repository_id: int :param git_repository: Name of the repository to be pulled. :type git_repository: str :param no_clone: Flag to clone or not the forked repository. :type no_clone: bool :return: """ if verbosity: print(" Verbose Gitutils: ") # Message user about forking project print(const.FORK_PROJECT % (git_repository, git_repository_id)) # fork try: if verbosity: print(" \t (-v) Gitutils creating fork.") print(" \t (-v) settings: git_repository_id : ", git_repository_id, " fork_group_indication : ", fork_group_indication, " group_name :", group_name) new_project = gitlab_utils.fork_project(git_repository_id, fork_group_indication, group_name) time.sleep(2) info_msg = 'New project forked: [%s] (id: %s) - %s' % ( new_project.attributes['path_with_namespace'], new_project.attributes['id'], new_project.attributes['http_url_to_repo']) print(info_msg) except Exception as ex: raise gitutils_exception.GitutilsError(ex) if not no_clone: ssh_url_to_repo = new_project.attributes['ssh_url_to_repo'] http_url_to_original_repo = new_project.attributes[ 'forked_from_project']['http_url_to_repo'] # waiting another 2 seconds before cloning - AFS gitserver issue if verbosity: print(" \t (-v) settings: ssh_url_to_repo : ", ssh_url_to_repo, " http_url_to_original_repo : ", http_url_to_original_repo) time.sleep(2) # verify if there's a local folder and delete it gitlab_utils.check_existing_local_git(git_repository, verbosity) try: print(" \t (-v) Gitutils fork cloning (%s)..." % (ssh_url_to_repo)) os.system('git clone %s' % ssh_url_to_repo) time.sleep(2) os.chdir(git_repository) except Exception as ex: raise gitutils_exception.GitutilsError(ex) try: if verbosity: print(" \t (-v) Gitutils fork adding upstream...") os.system('git remote add upstream %s' % http_url_to_original_repo) time.sleep(2) except Exception as ex: print(const.GIT_UPLINK_PROBLEM % http_url_to_original_repo) else: print("\nGitutils warning: " + const.FORK_NO_CLONE) return None
def initialization(self, arguments): ########### # ADDLDAP # ########### if arguments.command == 'addldap': repo_name = 'all' group_name = arguments.group project_id = 'all' ############## # CLONEGROUP # ############## elif arguments.command == 'clonegroup': if not arguments.group: print(const.CLONEGROUP_PROBLEM) sys.exit(-1) repo_name = 'all' group_name = arguments.group[0] project_id = 'all' ################ # CREATEGROUPS # ################ elif arguments.command == 'creategroups': if not arguments.name: print(const.CREATEGROUP_PROBLEM) sys.exit(-1) repo_name = 'none' group_name = arguments.name project_id = 'none' ################## # CREATEPROJECTS # ################## elif arguments.command == 'createprojects': if not arguments.name: print(const.CREATEGROUP_PROBLEM) sys.exit(-1) repo_name = arguments.name group_name = arguments.group project_id = 'none' ######## # FIND # ######## elif arguments.command == 'find': repo_name = 'all' group_name = 'all' project_id = 'all' ######## # FORK # ######## elif arguments.command == 'fork': if arguments.project is None: print(const.PROBLEM_FETCHING_NAME_PROJECT) self.parser_fork.print_help() sys.exit(-1) if arguments.project.count('/') != 1: print(const.GROUP_PROJECT_BAD_FORMAT) self.parser_fork.print_help() sys.exit(-1) group_name = arguments.project.split('/')[0] repo_name = arguments.project.split('/')[1] if arguments.clean: forked_project = gitlab_utils.get_forked_project( repo_name, arguments.clean, arguments.verbosity) if forked_project is not None: project_id = forked_project['forked_from_project']['id'] gitlab_utils.delete_project(forked_project['id']) else: print(const.IGNORE_CLEAN % (group_name, repo_name)) project_id = gitlab_utils.get_project_id( group_name, repo_name) else: if not arguments.group: project_id = gitlab_utils.get_project_id( group_name, repo_name) else: project_id = gitlab_utils.get_project_id_without_group( repo_name) ######### # LOGIN # ######### elif arguments.command == 'login': # login/user has already been requested and token retrieved print(const.LOGIN_TEST) # verifies if access if correctly done gitlab_utils.verify_token() # exits sys.exit(-1) ######### # MERGE # ######### elif arguments.command == 'merge': group_name = None # Verify if project has been indicated project_indication = False repo_name = os.path.basename(os.getcwd()) if arguments.project: project_indication = True if arguments.project.count('/') != 1: print(const.GROUP_PROJECT_BAD_FORMAT) self.parser_mr.print_help() sys.exit(-1) group_name = arguments.project.split('/')[0] repo_name = arguments.project.split('/')[1] else: # Check to see the directory if os.path.isfile('.git/config'): next_line = False git_extracted_repo_name = None with open(".git/config") as git_search: for line in git_search: line = line.strip() if next_line is True and git_extracted_repo_name is None: if not line.startswith("url ="): # go to next line continue # Detect if ssh or http has been used to clone if const.SSH_GIT_GIT in line: try: group_name = line.split('=')[-1].split( '/')[0].split(':')[-1] git_extracted_repo_name = line.split( '=')[-1].split('/')[-1][:-4] except: raise gitutils_exception.GitutilsError( const.GIT_MERGE_PROBLEM_0) else: try: git_extracted_repo_name = line.split( '=')[-1].split('/')[-1].split( '.')[0] group_name = line.split('=')[-1].split( '/')[-2] except Exception: raise gitutils_exception.GitutilsError( const.GIT_MERGE_PROBLEM_0) break if "[remote \"origin\"]" in line: next_line = True if git_extracted_repo_name != repo_name: raise gitutils_exception.GitutilsError( const.GIT_INCONSISTENCY_NAME) else: raise gitutils_exception.GitutilsError( const.GIT_MERGE_PROBLEM_1) if group_name is None: group_name = gitlab_utils.get_project_group( repo_name, False, True, project_indication) project_id = gitlab_utils.get_project_id(group_name, repo_name) ########### # SETROLE # ########### elif arguments.command == 'setrole': role_access = None if not arguments.group: print(const.SETROLE_PROBLEM) sys.exit(-1) if arguments.role not in [ 'guest', 'reporter', 'dev', 'maintainer', 'owner' ]: print(const.ROLE_ADDLDAP_PROBLEM) sys.exit(-1) else: role_access = gitlab_utils.check_role(arguments.role) repo_name = 'all' group_name = arguments.group project_id = 'all' else: self.parser.print_help() sys.exit(-1) return (repo_name, group_name, project_id)
def check_group_exists(group_name): groups = gl.groups.list(search=group_name, all=True) if not groups: raise gitutils_exception.GitutilsError(const.GROUP_PARAMETER_EMPTY) return 0
def get_group(group_id): try: group = gl.groups.get(group_id) except Exception as e: raise gitutils_exception.GitutilsError(const.GROUP_PARAMETER_EMPTY) return group
def is_git_repo(): is_git_repo = subprocess.check_output( const.GIT_IS_REPO_PATH, shell=True).decode('UTF-8').split('\n')[0] if 'true' in is_git_repo: raise gitutils_exception.GitutilsError(const.FORK_PROBLEM_GIT_FOLDER)