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 exec_hook(flag, position, proj=None, branch=None): """ 执行钩子指令 :param flag: 标识,如product :param position: 位置,如post(主指令后),pre(主指令前) :param proj: 所在的项目 :param branch: 所在的分支 :return: None """ hook_cfg = iconfig.read_config('system', "hook") if not hook_cfg or not hook_cfg.has_key(flag) or not isinstance(hook_cfg[flag], dict): return None hook_cfg = hook_cfg[flag] if not hook_cfg.has_key(position) or not isinstance(hook_cfg[position], list) or not hook_cfg[position]: return None orig_dir = os.getcwd() orig_branch = igit.current_branch() for cfg in hook_cfg[position]: if not cfg or not isinstance(cfg, dict) or not cfg.has_key('cmd'): continue # 项目限制 if proj and cfg.has_key("proj") \ and isinstance(cfg["proj"], list) \ and cfg["proj"] \ and proj not in cfg["proj"]: continue # 分支限制 if branch and cfg.has_key("branch") \ and isinstance(cfg["branch"], list) \ and cfg["branch"] \ and branch not in cfg["branch"]: continue if not cfg.has_key("title") or not cfg["title"]: cfg["title"] = u"自定义脚本:%s" % cfg["cmd"] # 执行钩子 iprint.say(('green', u'执行'), ('yellow', cfg["title"]), ('green', '...')) ihelper.execute(cfg["cmd"]) iprint.say(('yellow', cfg["title"]), ('green', u'执行完成!')) if os.getcwd() != orig_dir: os.chdir(orig_dir) if igit.current_branch() != orig_branch: os.system('git checkout %s' % orig_branch)
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'成功!')
def headline(): """ 页眉 """ print project = iglobal.PROJECT curr_proj_info = iconfig.read_config('project', project) branch = igit.current_branch() if project != 'global' else None real_path = os.getcwd() if (project == 'global' or not project or not curr_proj_info or not curr_proj_info.has_key('dir')) \ else curr_proj_info['dir'] if real_path.count('/') > 2: path_arr = real_path.split('/') real_path = '/'.join( [path_arr[0], path_arr[1], '...', path_arr[len(path_arr) - 1]]) iprint.green( iglobal.SPRINT), iprint.sky_blue('/'), iprint.yellow(project + '(' + real_path + ')') if branch: status = igit.workspace_status(text=True) iprint.sky_blue('[ ' + branch + ('(' + status + ')' if status else '') + ' ]') print sys.stdout.flush()
def merge(self): """ 将生产分支最新代码merge到当前分支 步骤: 1. 拉取生产分支: git fetch origin master && git checkout master && git rebase origin/master 2. 拉取当前分支: git fetch origin currbranch && git checkout currbranch && git rebase origin/currbranch 3. 将master合并到当前分支: git checkout currbranch && git merge master :return: """ prod_branch = igit.product_branch() curr_branch = igit.current_branch() if curr_branch == prod_branch: return #进入生产分支 ihelper.execute('git checkout %s' % prod_branch) #拉取生产远程分支到本地 igit.pull() #切回开发分支 ihelper.execute('git checkout %s' % curr_branch) #拉取远程开发分支到本地 igit.pull() #合并本地master到本地开发分支并推送到远程 igit.merge(prod_branch, need_pull=False) igit.set_last_sync_master_date(curr_branch) ok('done!')
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 获取最新代码')
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'成功!')
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 finally: if c_branch != igit.current_branch(): info(u'切换回 %s' % c_branch) ihelper.execute('git checkout %s' % c_branch) ok(u'操作成功!') def delete(self): """ 删除本地匹配模式的多个分支,并删除远程相应分支 :return: """ if not self.args: raise exception.FlowException(u'指令格式错误,请输入help查看使用说明') tag_pattern = None del_remote = True
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