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'取消操作')
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)
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'取消操作')
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
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))
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'创建分支失败')
def product(self, args): """ 发布到生产分支 :param list args: :return: """ continue_p = False abort_p = False branch_alias = {} tick = 1 line_branches = [] while args: c = args.pop(0) if c == '--abort': abort_p = True elif c == '--continue': continue_p = True else: if c.endswith(':'): c += '*' line_branches.append(c) if abort_p: # 清除runtime后退出 ok(u'取消发布') ihelper.write_runtime('publish_branches') ihelper.write_runtime('publish_tags') return if continue_p: # 继续上次的发布 self.publish_to_master() return if ihelper.read_runtime('publish_branches'): error(u'上次发布尚未完成,请执行 %s p --continue 继续,或执行 %s p --abort 结束' % (self.cmd, self.cmd)) return branches = self.__resolve_branches(line_branches) for key, val in branches.items(): if not val: branches.pop(key) if not branches: warn(u'没有需要发布的分支') return # 打印列表,并为分支设置别名 warn(u'待发布分支列表:') for proj, p_brs in branches.items(): ok(proj + u':') for pbr in p_brs: alias = 'f%s' % tick say(('white', ' [ '), ('green', alias), ('white', ' ] %s' % pbr)) branch_alias[alias] = (proj, pbr) tick += 1 print info(u'1. 输入 "in 分支简称列表(f1 f2...,多个分支用空格隔开)" 告知系统要发布的分支。或者') info(u'2. 输入 "ex 分支简称列表" 告知系统要排除的分支。或者') info(u'3. 输入 all 发布以上列出的所有项目分支。或者') info(u'4. 输入 cancel 取消发布') print retr = True while retr: retr = False final_branches = self.__choose_branch_dialog(branch_alias) if final_branches == 'cancel': return print warn(u'将发布以下分支到生产环境:') the_proj = None for ele in final_branches: if the_proj != ele[0]: the_proj = ele[0] ok(ele[0] + ':') info(' ' + ele[1]) print confirm = ihelper.confirm(u'请确认') if confirm == 'c': return elif confirm == 'n': # 返回分支选择 info(u'请重新选择待发布分支...') retr = True elif confirm == 'y': # 开始执行发布,发布前先持久化待发布列表 ihelper.write_runtime('publish_branches', final_branches) info(u'正在发布...') self.publish_to_master(final_branches)
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