def set_last_sync_master_date(branch): last_merge_date = ihelper.read_runtime('last_merge_date') if not last_merge_date: last_merge_date = {} last_merge_date[branch] = datetime.datetime.now().strftime('%Y-%m-%d') #垃圾回收:删除7天之前的记录 for key, mdate in last_merge_date.items(): if mdate and time.mktime(time.strptime(str(mdate), '%Y-%m-%d')) < time.time() - 604800: last_merge_date.pop(key) ihelper.write_runtime('last_merge_date', last_merge_date)
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
def check_product_branch_has_new_update(): """ 检查生产分支是否有更新内容 检查方法:获取远程生产分支的最近一次commitid,检验该commitid是否出现在当前分支中 :return: """ prod_branch = product_branch() curr_branch = current_branch() if curr_branch in [prod_branch, test_branch()]: return #一天只检验一次 last_merge_date = ihelper.read_runtime('last_merge_date') if last_merge_date \ and last_merge_date.has_key(curr_branch) \ and last_merge_date[curr_branch] == datetime.datetime.now().strftime('%Y-%m-%d'): return info(u'正在检查%s分支有无更新...' % prod_branch) #拉取最新生产分支 fetch(branch = prod_branch) #拉取最新当前分支 fetch(branch=curr_branch) #获取生产分支最新一次提交的commit_id last_cmt_id = __get_last_commit_id(prod_branch) if not last_cmt_id: return #检查该commit_id是否在当前分支上 if not ihelper.popen("git branch --list -a --contains %s *%s" % (last_cmt_id, curr_branch)).splitlines(): warn(u'%s分支已有更新,请执行merge指令合并到当前分支' % prod_branch) else: set_last_sync_master_date(curr_branch)
def check_workspace_health(): """ 检查工作区是否健康:是否处于conflict、rebasing状态 :return: """ text = ihelper.popen('git status') if workspace_at_status(iglobal.GIT_CONFLICT, raw_text=text, use_cache=True): if workspace_at_status(iglobal.GIT_REBASING, raw_text=text, use_cache=True): warn(u'rebase出现冲突。请手工解决冲突后执行 git add . && git rebase --continue 继续完成操作。或者执行 git rebase --abort取消操作') elif workspace_at_status(iglobal.GIT_CHERRING, raw_text=text, use_cache=True): warn(u'cherry-pick出现冲突。请手工解决冲突后执行 git add . && git cherry-pick --continue 继续完成操作。或者执行git cherry-pick --abort取消操作') elif workspace_at_status(iglobal.GIT_MERGING, raw_text=text, use_cache=True): warn(u'merge出现冲突。请手工解决冲突后执行 git add . && git commit 完成合并操作。或者执行 git merge --abort取消操作') else: warn(u'当前工作区存在冲突,请手工处理冲突后执行 git add . && git commit 解决冲突') elif workspace_at_status(iglobal.GIT_REBASING, raw_text=text, use_cache=True): warn(u'工作区正处于rebasing中,请执行 git rebase --continue 完成操作') elif workspace_at_status(iglobal.GIT_CHERRING, raw_text=text, use_cache=True): warn(u'工作区正处于cherry picking中,请执行 git cherry-pick --continue 完成操作') elif workspace_at_status(iglobal.GIT_MERGING, raw_text=text, use_cache=True): warn(u'工作区正处于merging中,请执行 git commit 完成操作') elif ihelper.read_runtime('publish_branches'): warn(u'上次发布尚未完成,请解决冲突后执行 ft p --continue 继续完成发布。或者执行 ft p --abort 结束该发布')
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))
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)