使用Python脚本一次性并发拉取Gitlab中所有的仓库

使用Git图形化管理工具SourceTree好多年,去年起SourceTree越更新越辣鸡,简直不能用,转而投了Fork的怀抱,但是两者都没有批量拉取的功能.

然而负责的项目越来越多,而单个拉取仓库更新代码无异是痛苦的.

于是花了点功夫看了下官方的API文档,写了个用Python批量拉取所有仓库的脚本,使用了一个第三方的 Python 模块: python-gitlab.

功能很简单,就是根据账号权限并发拉取所有能拉取的仓库,如果当前目录下不存在就创建;如果已存在仓库,则更新.

import platform,os,gitlab,sys,multiprocessing


def returnpath(path:str)->str:
    if 'Windows' == platform.system():
        path = path.replace('/','\\')
    return path

def get_gitlab_groups_projs_path(gl_server:gitlab.Gitlab)->list:
    projs = []
    projs_id = []
    projs_tmp = []
    def __add(group):
        for proj in group.projects.list():
            projs_tmp.append({'id':proj.attributes.get('id'),'proj_path':proj.attributes.get('path_with_namespace'),
                              'group_path':proj.attributes.get('namespace').get('full_path'),
                              'url':proj.attributes.get('http_url_to_repo')
                              })
    for group in gl_server.groups.list(order_by='id',all_available=True):
        __add(group)
        sgs = group.subgroups.list(lazy=True)
        for sg in sgs:
            sg_attr = sg.attributes
            __add(gl_server.groups.get(sg_attr.get('id')))
    for proj in projs_tmp:
        if proj.get('id') not in projs_id:
            projs.append(proj)
            projs_id.append(proj.get('id'))
    return projs

def multi_process(num,func,infos,commit):
    task_pool = multiprocessing.Pool(num)
    for info in infos:
        task_pool.apply_async(func,args=(info,commit,))
    task_pool.close()
    task_pool.join()

def get_repo(info:dict,*args):
    cmd = 'cd ' + os.getcwd() + returnpath('/')
    if os.path.exists(path=info.get('proj_path')):
        cmd += info.get('proj_path') + ' && git pull'
    else:
        cmd += info.get('group_path') + '&& git clone  ' + info.get('url')
    os.system(cmd)

def push_repo(info:dict,commit:str):
    proj_path = info.get('proj_path')
    if os.path.exists(path=proj_path):
        cmd = 'cd ' + os.getcwd() + returnpath('/') + proj_path + '&& git pull && git commit -am "' + commit + '" && git push'
        os.system(cmd)
    else:
        print('Not exit ' + proj_path)


if __name__ == "__main__":
    action = ''
    if len(sys.argv) < 2 :
        print("参数过少.\neg: "+sys.argv[0]+' pull')
        sys.exit(1)
    else:
        action = sys.argv[1]
    git_addr = "http://gitlab.addr:port" # gitlab服务器地址
    token = '8Q_uudHvJsNBTApedU5V' # 账号的token,在个人页面的Setting - Access Tokens 中创建
    processNum = 5
    gl_server = gitlab.Gitlab(url=git_addr, private_token=token)
    infos = get_gitlab_groups_projs_path(gl_server=gl_server)
    # sys.exit(0)
    for proj in infos:
        if not os.path.exists(path=proj.get('group_path')):
            os.makedirs(proj.get('group_path'))
    if not os.path.exists(path=returnpath('TL')):
        processNum = 3
        print(processNum)
    if 'pull' == action:
        multi_process(num=processNum,func=get_repo,infos=infos,commit='')
    elif 'push' == action:
        commit = 'Batch Edit'
        multi_process(num=processNum,func=push_repo,infos=infos,commit=commit)
    else:
        print('Unkonw action.')