Beispiel #1
0
    def f2h(self, args):
        """
        本迭代的特性分支转修复分支
        :return:
        """
        branch = None
        while args:
            branch = args.pop(0)

        if not branch:
            raise exception.FlowException(u'未指定分支名称')

        old_branch = igit.real_branch(
            branch,
            iconfig.read_config('system', 'branch')['feature_prefix'])
        new_branch = igit.real_branch(
            branch.split('/')[-1],
            iconfig.read_config('system', 'branch')['hotfix_prefix'])

        if not old_branch or not new_branch:
            raise exception.FlowException(u'分支名称不合法')

        if old_branch not in igit.local_branches():
            raise exception.FlowException(u'分支不存在:%s' % old_branch)

        if ihelper.confirm(u'确定将特性分支%s转为修复分支%s吗?' %
                           (old_branch, new_branch)) == 'y':
            git.Git('rename', [old_branch, new_branch]).execute()
            ok()
        else:
            ok(u'取消操作')
Beispiel #2
0
    def delete(self, args):
        """
        删除分支
        :return:
        """
        if not args:
            raise exception.FlowException(u'指令格式错误,请输入h %s查看使用说明' % self.cmd)

        branch = None
        delete_remote = True
        auto_delete = False

        while args:
            c = args.pop(0)
            if c == '--np' or c == '--no-push':
                delete_remote = False
            elif c == '-y':
                auto_delete = True
            else:
                branch = igit.real_branch(c, self.cmd)

        if not branch:
            raise exception.FlowException(u'请输入分支名称')

        if auto_delete or ihelper.confirm(u'确定删除分支 %s 吗?' % branch,
                                          default='n') == 'y':
            igit.delete_branch(branch, del_remote=delete_remote)
Beispiel #3
0
    def rename(self):
        """
        分支重命名。old和new需要时绝对分支名
        """
        if len(self.args) < 2:
            raise exception.FlowException('指令格式错误,请输入help查看使用说明')

        old = self.args[0]
        new = self.args[1]

        local_branches = igit.local_branches()

        if old not in local_branches:
            raise exception.FlowException(u'分支名称不存在:%s' % old)

        remote_branches = igit.remote_branches()

        # 名称重复性检测
        if new in local_branches or new in remote_branches:
            raise exception.FlowException(u'该分支已经存在:%s' % new)

        info(u'重命名分支:%s -> %s...' % (old, new))

        # 重命名本地分支
        ihelper.execute('git branch -m ' + old + ' ' + new, raise_err=True)
        # 删除远程分支(如果有的话)
        if old in remote_branches:
            ihelper.execute('git push --delete origin ' + old)
        # 上传新分支到远程
        ihelper.execute('git push -u origin ' + new + ':' + new)

        #防止重命名后检查master更新情况
        igit.set_last_sync_master_date(new)
Beispiel #4
0
    def f2f(self, args):
        """
        修复分支转修复分支,默认转到下个迭代
        :param list args:
        :return:
        """
        if '-n' not in args and '-s' not in args:
            args.append('-n')

        b_info = self.__branch_and_sprint(args)
        if not b_info['branch']:
            raise exception.FlowException(u'未指定分支名称')

        old_branch = igit.real_branch(
            b_info['branch'],
            iconfig.read_config('system', 'branch')['feature_prefix'])
        new_branch = igit.real_branch(
            '%s/%s' % (b_info['sprint'], b_info['branch'].split('/')[-1]),
            iconfig.read_config('system', 'branch')['feature_prefix'])

        if not old_branch or not new_branch:
            raise exception.FlowException(u'分支名称不合法')

        if old_branch not in igit.local_branches():
            raise exception.FlowException(u'分支不存在:%s' % old_branch)

        if ihelper.confirm(u'确定将特性分支%s转为特性分支%s吗?' %
                           (old_branch, new_branch)) == 'y':
            git.Git('rename', [old_branch, new_branch]).execute()
            ok()
        else:
            ok(u'取消操作')
Beispiel #5
0
def required_check():
    """
    必须进行的检查
    """
    iprint.info(u'正在进行工作环境检查...')

    #git版本检测
    git_version = igit.git_version()
    if int(git_version[0]) < 2:
        raise exception.FlowException(u'git版本过低,请安装2.0.0以上版本')

    # 检查project.json有没有配置以及路径是否正确
    proj_cfg = iconfig.read_config('project', use_cache=False)
    if not proj_cfg:
        raise exception.FlowException(
            u'请配置项目信息(config/project.json文件,具体格式参见readme.md文件)')

    for proj_name, info in proj_cfg.items():
        if proj_name == 'global':
            raise exception.FlowException(u'项目名称不能叫global,请使用别的名称')

        if not info['dir'] or not os.path.exists(
                info['dir']) or not os.path.isdir(info['dir']):
            raise exception.FlowException(u'项目' + proj_name + u'的目录配置不正确')

        # 检测目录是否有效的git仓库
        if not igit.dir_is_repository(info['dir']):
            raise exception.FlowException(u'目录' + info['dir'] + u'不是有效的git仓库')

    # sprint版本号检测
    return isprint.check_sprint()
Beispiel #6
0
    def tag(self):
        """
        在生产分支上打标签
        :return:
        """
        if not self.args:
            return ihelper.execute('git tag')

        #将要在该分支上打标签
        tag_branch = igit.product_branch()

        # 当前工作空间是否干净
        if igit.current_branch() != tag_branch and not igit.workspace_is_clean(
        ):
            raise exception.FlowException(u'工作区中尚有未保存的内容')

        tag_name = None
        comment = ''

        while self.args:
            c = self.args.pop(0)
            if c == '-a':
                tag_name = self.args.pop(0)
            elif c == '-m':
                while self.args:
                    if self.args[0].startswith('-'):
                        break

                    comment += self.args.pop(0) + ' '

        if not comment:
            raise exception.FlowException(u'请输入标签注释')

        if not tag_name:
            tag_name = igit.tag_name()

        if not tag_name:
            raise exception.FlowException(u'未设置tag name')

        if ihelper.confirm(u'将在分支 %s 上打tag:%s, ok?' %
                           (tag_branch, tag_name)) != 'y':
            warn(u'取消操作')
            return

        c_branch = igit.current_branch()

        try:
            #切换分支
            if c_branch != tag_branch:
                info(u'切换到分支 %s:' % tag_branch)
                ihelper.execute('git checkout %s' % tag_branch)

            #打tag
            print igit.tag(tag_name, comment)
        except exception.FlowException, e:
            error(u'操作失败:')
            raise e
Beispiel #7
0
    def test(self, args):
        """
        发布到测试分支,只允许单个分支发布
        :param args:
        :return:
        """
        # 当前工作空间是否干净
        if not igit.workspace_is_clean():
            raise exception.FlowException(u'工作区中尚有未保存的内容')

        if not args:
            branch = igit.current_branch()
        else:
            branch = args.pop(0)

        branch = igit.real_branch(branch, self.cmd)

        if branch != igit.current_branch():
            # 切换分支
            info(u'切换到分支%s' % branch)
            ihelper.execute('git checkout ' + branch)

            # 当前工作空间是否干净
            if not igit.workspace_is_clean():
                raise exception.FlowException(u'工作区中尚有未保存的内容')

        igit.sync_branch()

        # 切换到test分支
        test_branch = igit.test_branch()
        info(u'切换到分支%s' % test_branch)
        ihelper.execute('git checkout ' + test_branch)

        # 当前工作空间是否干净
        if not igit.workspace_is_clean():
            raise exception.FlowException(u'工作区中尚有未保存的内容')

        # 合并
        info(u'正在将%s合并到%s上...' % (branch, test_branch))
        igit.merge(branch)

        # 正常执行后,工作空间应该是干净的
        if not igit.workspace_is_clean():
            raise exception.FlowException(u'合并失败,请用git status查看工作空间详情')

        # 将test推到远程
        igit.push()

        # 切换到原来的分支
        info(u'切换回%s' % branch)
        ihelper.execute('git checkout ' + branch)

        ok(u'合并到' + test_branch + u'成功!')
Beispiel #8
0
    def delete(self):
        """
        删除本地匹配模式的多个分支,并删除远程相应分支
        :return:
        """
        if not self.args:
            raise exception.FlowException(u'指令格式错误,请输入help查看使用说明')

        tag_pattern = None
        del_remote = True
        del_branches = []

        while self.args:
            c = self.args.pop(0)
            if c == '--no-remote':
                del_remote = False
            else:
                tag_pattern = c

        if not tag_pattern:
            raise exception.FlowException(u'请指定需要删除的分支匹配模式')

        for branch in igit.local_branches():
            if branch == igit.product_branch():
                continue
            if re.match(tag_pattern, branch):
                del_branches.append(branch)

        if not del_branches:
            warn(u'没有符合条件的分支')
            return

        #打印出将要删除的分支列表
        warn(u'将要删除以下分支%s:' % ('(以及其对应的远程分支)' if del_remote else ''))
        for del_branch in del_branches:
            ok(del_branch)

        print

        if (ihelper.confirm(
                u'确定删除吗%s?' %
            ('(同时删除远程分支,删除后不可恢复)' if del_remote else ''), 'n') != 'y'):
            return

        #删除分支
        for del_branch in del_branches:
            try:
                igit.delete_branch(del_branch, del_remote)
            except exception.FlowException, e:
                warn(str(e))
Beispiel #9
0
def tag(tag_name, comment):
    """
    打标签
    :return:
    """
    out = ihelper.execute('git tag -a %s -m "%s"' % (tag_name, comment), print_out=False)
    if (out.find('already exists') > -1):
        raise exception.FlowException(u'已存在该标签')

    out = ihelper.execute('git push origin %s' % tag_name, print_out=False)
    if (out.find('already exists') > -1):
        raise exception.FlowException(u'远程已存在该标签')

    return out
Beispiel #10
0
def sync_branch():
    if not workspace_is_clean():
        raise exception.FlowException(u'当前工作空间不是clean状态')

    # 先pull再push
    pull()
    push(need_pull=False)
Beispiel #11
0
    def __post_publish(self, proj, tag_list):
        """
        项目发布完成的后续工作
        :return:
        """
        # 执行后续钩子
        self.exec_hook("product", "post", proj)

        # 钩子执行后需检查工作空间是否干净
        if igit.workspace_at_status(iglobal.GIT_CONFLICT):
            raise exception.FlowException(
                u'出现冲突,请手工解决冲突后执行 %s p --continue 继续。或执行 %s p --abort 结束' %
                (self.cmd, self.cmd))

        if igit.workspace_at_status(
                iglobal.GIT_UNCOMMITED) or igit.workspace_at_status(
                    iglobal.GIT_UNSTAGED):
            git.Git('commit', ['-p', '发布生产:执行自定义钩子后提交']).execute()

        # 标签
        info(u'项目 %s 发布完成,打标签:' % proj)
        proj_tag = self.__tag()

        if proj_tag:
            tag_list.append((proj, proj_tag))
Beispiel #12
0
    def real_cmd(cmd, raise_err=True, valid=True, top_cmd=None):
        """
        valid=True时,如果不指定top_cmd,则认为cmd是一级指令,否则认为是top_cmd的二级指令
        :param str top_cmd:
        :param cmd:
        :param raise_err:
        :param valid:
        :return:
        """
        config = iconfig.read_config('system')
        alias = config['alias']
        cmd = alias[cmd] if alias.has_key(cmd) else cmd

        if valid:
            error = False
            if top_cmd:
                top_cmd = alias[top_cmd] if top_cmd in alias else top_cmd
                cls = config['cmd_cls'][top_cmd] if top_cmd in config['cmd_cls'] else None

                if not cls:
                    error = True
                else:
                    if cmd not in dir(eval('%s.%s' % (cls.lower(), cls))):
                        error = True
            elif not config['cmd_cls'].has_key(cmd):
                error = True

            if error:
                if raise_err:
                    raise exception.FlowException(u'无效指令')
                else:
                    return None

        return cmd
Beispiel #13
0
def real_branch( branch, prefix):
    """
    获取完整的分支名
    :param str prefix:
    :param str branch:
    :return: str
    """
    if not branch:
        raise exception.FlowException(u'参数错误')

    if branch.find(':') != -1:
        branch = branch.split(':')[1]

    original_branch = branch
    branch = filter(lambda x:x != '', branch.split('/'))
    config = iconfig.read_config('system', 'branch')

    if len(branch) > 2 and branch[0] != config['feature_prefix']:
        raise exception.FlowException(u'分支格式不合法')

    if len(branch) == 3:
        branch[1] = isprint.get_sprint(branch[1])
        if not branch[1]:
            raise exception.FlowException(u'分支格式不合法')
        return '/'.join(branch)

    if len(branch) == 2:
        if branch[0] == 'hotfix':
            return '/'.join(branch)
        elif isprint.check_sprint_format(branch[0], True):
            # 迭代号开始的,此时prefix只能是feature
            if prefix != config['feature_prefix']:
                raise exception.FlowException(u'分支格式不合法')

            branch[0] = isprint.get_sprint(branch[0])
            branch.insert(0, config[prefix + '_prefix'])
        else:
            # 看是否以feature或hotfix开头
            if branch[0] != config['feature_prefix'] and branch[0] != config['hotfix_prefix']:
                raise exception.FlowException(u'分支格式不合法')

        return '/'.join(branch)

    if original_branch.find('/') == 0:
        return config[prefix + '_prefix'] + original_branch
    else:
        return config[prefix + '_prefix'] + ('/' + iglobal.SPRINT if prefix == 'feature' else '') + '/' + branch[0]
Beispiel #14
0
def check_dir():
    runtime_dir = iglobal.BASE_DIR + '/runtime/'
    config_dir = iglobal.BASE_DIR + '/config/'
    log_dir = iglobal.BASE_DIR + '/log/'
    config_file = config_dir + 'system.json'
    project_file = config_dir + 'project.json'

    if not os.path.exists(config_dir):
        raise exception.FlowException(u'目录缺失:%s' % config_dir)
    if not os.path.exists(config_file):
        raise exception.FlowException(u'文件缺失:%s' % config_file)
    if not os.path.exists(project_file):
        raise exception.FlowException(u'文件缺失:%s' % project_file)
    if not os.path.isdir(runtime_dir):
        os.mkdir(runtime_dir)
    if not os.path.isdir(log_dir):
        os.mkdir(log_dir)
    return True
Beispiel #15
0
def execute(cmd, print_out=True, raise_err=False, return_result=False):
    if not print_out:
        return_result = True

    # 不关心异常且需要输出且不需要返回时,直接调用os.system
    if print_out and not raise_err and not return_result:
        if iglobal.SILENCE:
            p = os.popen(cmd)
            out = p.read()
            p.close()
            return out
        else:
            sys.stdout.flush()
            return os.system(cmd)
    else:
        # git指令需要特殊处理
        is_git_cmd = True if cmd.startswith('git ') else False

        p = subprocess.Popen(cmd,
                             stderr=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stdin=subprocess.PIPE,
                             shell=True)
        out, err = p.communicate()

        del p

        # 致命git错误必须抛出
        if is_git_cmd and igit.is_fatal_git_error(out + err):
            raise exception.FlowException(u'发生致命git错误:\n%s' % (out + err))

        if err:
            if raise_err:
                # 将错误抛出由外界处理
                raise exception.FlowException(err)
            else:
                out = err + out

        if print_out and not iglobal.SILENCE:
            iprint.info(out)

        if return_result:
            return out.rstrip('\n')
Beispiel #16
0
    def sprint(args):
        """
        切换到某个迭代
        :param args:
        """
        sprint = isprint.get_sprint(None if not args else args[0])
        if not sprint:
            raise exception.FlowException(u'版本号格式错误')

        iglobal.SPRINT = sprint
        ihelper.write_runtime('sprint', sprint)
Beispiel #17
0
    def cd(args):
        """
        进入项目目录
        :param args:
        """
        if not args:
            raise exception.FlowException(u'指令格式不正确,请键入help查看该指令使用方式')

        proj_name = args[0]
        proj = iconfig.read_config('project', proj_name)

        if not proj or not proj.has_key('dir'):
            raise exception.FlowException(u'未配置项目' + proj_name + u'信息,请进入config/project.json中正确配置')

        if not os.path.isdir(proj['dir']):
            raise exception.FlowException(u'该项目git根目录配置不正确,请进入config/project.json中正确配置')

        iglobal.PROJECT = proj_name
        ihelper.write_runtime('project', proj_name)
        os.chdir(proj['dir'])
Beispiel #18
0
def check_sprint():
    """
    迭代版本号检查
    """
    sprint = ihelper.read_runtime('sprint')

    if not sprint:
        raise exception.FlowException(u'尚未设置迭代版本号,请使用sp指令设置正确的迭代版本号')
    else:
        sp_date = get_date_from_sprint(sprint).split('-')
        now = time.strftime('%Y-%m-' + '01').split('-')
        d1 = datetime.datetime(int(sp_date[0]), int(sp_date[1]),
                               int(sp_date[2]))
        d2 = datetime.datetime(int(now[0]), int(now[1]), int(now[2]))
        diff = abs((d1 - d2).days)

        if diff >= 90:
            raise exception.FlowException(u'迭代版本号(' + sprint +
                                          u')和当前日期不符,请使用sp指令重新设置正确的迭代版本号')

    return True
Beispiel #19
0
def simple_branch(branch):
    """
    获取分支精简名称
    :param str branch:
    :return: str
    """
    if not branch:
        raise exception.FlowException(u'请输入分支名称')

    if branch.startswith('/') and branch.count('/') == 1:
        return branch

    return branch.split('/').pop()
Beispiel #20
0
def pull():
    """
    拉取当前分支
    :return:
    """
    fetch(branch=current_branch())

    if not workspace_at_status(iglobal.GIT_BEHIND) and not workspace_at_status(iglobal.GIT_DIVERGED):
        return

    ihelper.execute('git rebase')
    if workspace_at_status(iglobal.GIT_CONFLICT):
        raise exception.FlowException(u'拉取远程分支出错:冲突。请手工解决冲突后执行git add . && git rebase --continue,然后再重新执行命令')
Beispiel #21
0
    def commit(self):
        """
        提交
        :return:
        """
        comment = ''
        push = False

        if not self.args:
            raise exception.FlowException(u'指令格式错误,请输入h ft查看使用说明')

        while self.args:
            c = self.args.pop(0)
            if c == '-p':
                push = True
            else:
                comment += ' %s' % c

        comment = comment.strip()

        if not comment:
            raise exception.FlowException(u'请填写提交说明')

        curr_branch = igit.current_branch()

        # 提交
        ihelper.execute('git add .')
        ihelper.execute('git commit -m "' +
                        igit.comment(comment,
                                     curr_branch.split('/')[0]).
                        decode('utf-8').encode(iglobal.FROM_ENCODING) + '"')

        if push:
            igit.push(curr_branch)

        ok(u'提交' + (u'并推送到远程仓库' if push else '') + u'成功!')
Beispiel #22
0
def sync(project, prefix=None, only_this_sprint=True, deep=False):
    """
    同步本地和远程分支
    :param bool deep: 是否深层合并,只有深层合并才会同步本地和远程都存在的分支(暂未实现),否则只是创建本地没有的分支和推远程没有的分支
    :param project:
    :param prefix:
    :param only_this_sprint:
    :return:
    """
    iglobal.SILENCE = True
    old_project = iglobal.PROJECT

    try:
        # 进入该项目目录
        if project != iglobal.PROJECT:
            command.Extra('cd', [project]).execute()

        if prefix and only_this_sprint:
            prefix = '%s/%s' % (prefix.rstrip('/'), iglobal.SPRINT)

        # remote_branches里面已经执行了git fetch了,此处就不再执行了
        l_brs = local_branches()
        r_brs = remote_branches()

        if prefix:
            l_brs = filter(lambda x:str(x).startswith(prefix), l_brs)
            r_brs = filter(lambda x:str(x).startswith(prefix), r_brs)

        local_only = list(set(l_brs).difference(set(r_brs)))
        remote_only = list(set(r_brs).difference(set(l_brs)))
        the_same = list(set(l_brs).intersection(set(r_brs)))

        # 仅在本地存在的,推到远程去
        for l_o_br in local_only:
            ihelper.execute('git push -u origin %s:%s' % (l_o_br, l_o_br))

        # 仅远程存在的,创建本地相关分支
        for r_o_br in remote_only:
            ihelper.execute('git branch %s origin/%s' % (r_o_br, r_o_br))

        # 两边都存在的,同步
        if the_same and deep:
            raise exception.FlowException(u'暂未实现')

        if old_project != iglobal.PROJECT:
            command.Extra('cd', [old_project]).execute()
    finally:
        iglobal.SILENCE = False
Beispiel #23
0
    def checkout(self, args):
        """
        切换到某个特性/修复分支并拉取最新代码(如果工作空间是干净的)
        :return:
        """
        branch = None
        sync_remote = False
        while args:
            c = args.pop(0)
            if c == '-r' or c == '--remote':
                sync_remote = True
            else:
                branch = igit.real_branch(c, self.cmd)

        current_branch = igit.current_branch()

        if not branch:
            branch = current_branch

        if branch == current_branch:
            sync_remote = True

        __error = False
        if branch != current_branch:
            # 检查当前分支下工作区状态
            if not igit.workspace_is_clean():
                raise exception.FlowException(
                    u'工作区中尚有未提交的内容,请先用commit提交或用git stash保存到Git栈中')

            out = ihelper.execute('git checkout ' + branch, return_result=True)
            # git的checkout指令输出在stderr中
            if 'Switched to branch' not in out:
                __error = True

        if __error:
            warn(u'checkout失败')
            return

        if sync_remote:
            info('fetch from remote...')
            igit.fetch(branch=branch)

        if igit.workspace_at_status(
                iglobal.GIT_BEHIND) or igit.workspace_at_status(
                    iglobal.GIT_BEHIND):
            warn(u'远程仓库已有更新,请执行 git rebase 获取最新代码')
Beispiel #24
0
def delete_branch(branchName, del_remote=False):
    """
    删除分支
    :param branchName:
    :param del_remote:
    :return:
    """
    if branchName == current_branch():
        raise exception.FlowException('can not delete current branch')

    info(u'删除本地分支 %s ...' % branchName)
    ihelper.execute('git branch -D %s' % branchName, raise_err=True)
    #删除远程分支
    if del_remote:
        info(u'删除远程分支 origin/%s ...' % branchName)
        ihelper.execute('git push --delete origin %s' % branchName)

    ok(u'删除成功!')
Beispiel #25
0
def merge(branch, need_push=True, need_pull=True):
    """
    将branch合并到当前分支
    :param need_pull:
    :param need_push:
    :param branch:
    :return:
    """
    # 从远程仓库拉最新代码
    if need_pull:
        pull()

    # 合并(git合并冲突信息在stdout中)
    ihelper.execute('git merge --no-ff ' + branch)
    if workspace_at_status(iglobal.GIT_CONFLICT):
        ihelper.execute('git status -s')
        raise exception.FlowException(u'合并失败:发生冲突。请手工解决冲突后执行git add . && git commit,然后重新执行命令')

    # 推送到远程仓库
    if need_push:
        ihelper.execute('git push')
Beispiel #26
0
 def execute(self):
     raise exception.FlowException(u"指令尚未实现")
Beispiel #27
0
    def create(self, args):
        """
        创建特性/修复分支。一次只能创建一个,会推到远端,且切换到此分支
        :return:
        """
        if not args:
            raise exception.FlowException(u'指令格式错误,请输入h %s查看使用说明' % self.cmd)

        branch = None
        auto_create_from_remote = False
        push_to_remote = True

        while args:
            c = args.pop(0)
            if c == '-y':
                auto_create_from_remote = True
            elif c == '--np' or c == '--no-push':
                push_to_remote = False
            else:
                branch = c

        if not branch:
            raise exception.FlowException(u'请输入分支名称')

        # 分支简称不可与项目、迭代名称相同(防止一些指令出现歧义)
        simple_branch = igit.simple_branch(branch)
        if simple_branch == iglobal.SPRINT or simple_branch in ihelper.projects(
        ):
            raise exception.FlowException(u'分支简称不可与项目或迭代名同名')

        branch = igit.real_branch(branch, self.cmd)

        # 检查当前分支下工作区状态
        if not igit.workspace_is_clean():
            raise exception.FlowException(
                u'工作区中尚有未提交的内容,请先用git commit提交或用git stash保存到Git栈中')

        # 分支名称重复性检查
        info(u'检查本地分支...')
        if branch in igit.local_branches():
            raise exception.FlowException(u'该分支名称已经存在')

        # 本地没有但远程有
        create_from_remote = False
        info(u'检查远程分支...')
        if branch in igit.remote_branches():
            if not auto_create_from_remote and ihelper.confirm(
                    u'远程仓库已存在%s,是否基于该远程分支创建本地分支?' % branch) != 'y':
                return
            else:
                create_from_remote = True

        say(('white', u'正在创建分支'), ('sky_blue', branch), ('white', '...'))

        if create_from_remote:
            # 基于远程分支创建本地分支,会自动追踪该远程分支
            ihelper.execute('git checkout -b ' + branch + ' origin/' + branch)
        else:
            # 切换到生产分支
            p_branch = igit.product_branch()
            ihelper.execute('git checkout ' + p_branch)
            igit.pull()

            # 基于本地生产分支创建新分支
            ihelper.execute('git checkout -b ' + branch)

            # 推送到远程
            if push_to_remote:
                ihelper.execute('git push -u origin ' + branch + ':' + branch)

        if igit.workspace_is_clean():
            #处理master更新检验,防止创建分支后执行master更新检查操作
            igit.set_last_sync_master_date(branch)

            ok(u'创建成功!已进入分支:' + branch)
        else:
            raise exception.FlowException(u'创建分支失败')
Beispiel #28
0
    def sql(args=None):
        """
        获取项目下面的所有sql
        :param args:
        :return:
        """
        dirs = []
        old_proj = iglobal.PROJECT
        for proj, info in iconfig.read_config('project').items():
            if 'ignore_sql_file' in info and info['ignore_sql_file']:
                continue

            # 需要先将项目切换到相应的分支
            sql_branch = info['branch']['sql_branch'] \
                if info.has_key('branch') and 'sql_branch' in info['branch'] \
                else iconfig.read_config('system', 'branch')['sql_branch']

            # 进入项目
            if iglobal.PROJECT != proj:
                iprint.info(u'进入项目%s' % proj)
                Extra.cd([proj])

            curr_branch = igit.current_branch()
            if curr_branch != sql_branch:
                if not igit.workspace_is_clean():
                    raise exception.FlowException(u'项目的工作空间有尚未保存的修改,请先执行git commit提交或git clean -fd丢弃。处理后请再次执行sql指令')
                # 切换分支
                ihelper.system('git checkout %s' % sql_branch)

            # 拉取
            igit.pull()

            base_dir = info['dir']

            if 'sql_dir' in info:
                rel_dir = info['sql_dir']
            else:
                rel_dir = iconfig.read_config('system', 'sql_dir')

            dirs.append((proj, ihelper.real_path(str(base_dir).rstrip('/') + '/' + rel_dir)))

        if iglobal.PROJECT != old_proj:
            Extra.cd([old_proj])

        sql_file_suffixes = [ele.lstrip('.') for ele in str(iconfig.read_config('system', 'sql_file_suffix')).split('|')]

        if not dirs:
            return

        files = []
        for proj, sql_path in dirs:
            if not sql_path or not os.path.exists(sql_path):
                continue

            # 获取文件夹下所有的sql文件
            for f in os.listdir(sql_path):
                f = sql_path + f
                if not os.path.isfile(f):
                    continue

                if f.split('.')[-1] in sql_file_suffixes:
                    files.append(f)

        if not files:
            iprint.info(u'本次迭代没有sql需要执行')
            return

        # 排序
        def __isort(x, y):
            """
            :type x: str
            :type y: str
            :return:
            """
            sp_date = isprint.get_date_from_sprint(iglobal.SPRINT).split('-')
            year = sp_date[0]
            month = sp_date[1]

            x = os.path.basename(x)
            y = os.path.basename(y)

            if month == '12' and x.startswith('01'):
                x = str(int(year) + 1) + x
            else:
                x = year + x

            if month == '12' and y.startswith('01'):
                y = str(int(year) + 1) + y
            else:
                y = year + y

            if x < y:
                return -1

            return 1 if x > y else 0

        files.sort(__isort)

        print
        iprint.warn(u'以下sql需要发布:')
        for f in files:
            iprint.info('  ' + os.path.basename(f))
        print

        out_file = iglobal.BASE_DIR + '/runtime/' + iglobal.SPRINT + '.sql'
        if ihelper.confirm(u'是否导出sql?') == 'y':
            out_handler = open(out_file, 'w')
            out_handler.write('set names utf8;\n')
            for f_name in files:
                f_handler = open(f_name, 'r')
                out_handler.write('\n\n-- ----------------------------------- %s -----------------------------------\n' % os.path.basename(f_name))
                out_handler.write(f_handler.read())
                f_handler.close()
            out_handler.close()
            print
            iprint.ok(u'已写入到%s中' % out_file)
        else:
            return
Beispiel #29
0
    def publish_to_master(self, branches=None):
        """
        发布分支到生产环境
        :param branches: 待发布分支列表:[(proj_name, branch)]
        """
        curr_p_branch = None
        tag_list = []

        if not branches:
            #接着上次的继续发布
            branches = ihelper.read_runtime('publish_branches')
            tag_list = ihelper.read_runtime('publish_tags') or []

        if not branches:
            info(u'没有需要发布的分支')
            return

        orig_branches = list(branches)

        try:
            curr_proj = None
            for index, item in enumerate(branches):
                curr_p_branch = item
                proj, branch = tuple(item)

                if iglobal.PROJECT != proj:
                    info(u'进入项目%s' % proj)
                    extra.Extra('cd', [proj]).execute()

                if not igit.workspace_is_clean():
                    raise exception.FlowException(
                        u'项目%s工作空间有未提交的更改,请先提交(或丢弃)后执行 %s p --continue 继续' %
                        (proj, self.cmd))

                # 首次进入项目执行fetch获取本地和远程分支差异
                if curr_proj != proj:
                    info('fetch...')
                    igit.fetch(useCache=False)

                # 切换到将要合并的分支(如果不存在本地分支则会自动创建)
                ihelper.execute('git checkout %s' % branch)

                # 同步当前本地和远程分支(此处可能会出现冲突)
                igit.sync_branch()

                # 切换到master分支
                ihelper.execute('git checkout %s' % igit.product_branch())

                is_last_branch = index >= len(
                    branches) - 1 or proj != branches[index + 1][0]

                # 合并
                info(u'合并%s...' % branch)
                igit.merge(branch,
                           need_pull=proj != curr_proj,
                           need_push=is_last_branch)
                info(u'合并完成:%s' % branch)

                # 完成
                orig_branches.remove(curr_p_branch)

                if proj != curr_proj:
                    curr_proj = proj

                # 本项目发布完成后的一些操作
                if is_last_branch:
                    self.__post_publish(proj, tag_list)

            ok(u'发布完成!tag:')

            # 打印tag信息
            for (proj_name, tag_name) in tag_list:
                info(' %s  %s' % (proj_name, tag_name))

            # 清空tag list
            tag_list = []
        except Exception, e:
            error(e.message)
            warn(u'处理完成后执行 %s p --continue 继续。或执行 %s p --abort 结束' %
                 (self.cmd, self.cmd))
Beispiel #30
0
    def __init__(self, cmd, args):
        # 检查当前目录是否git仓库
        if not igit.dir_is_repository():
            raise exception.FlowException(u'当前目录不是有效的Git仓库')

        Command.__init__(self, cmd, args)