require 'git' require 'KCommercialPipeline/core/version_pipeline/release_branches' require 'KCommercialPipeline/core/git' require 'KCommercialPipeline/core/branch_diffs' require 'KCommercialPipeline/core/kim_cfg' module KCommercial module KCPipeline class AutoCherryPickResult attr_accessor :conflicts attr_accessor :target_b attr_accessor :source_b attr_accessor :cherry_picks def initialize(target_b:,source_b:,conflicts:,cherry_picks:) @conflicts = conflicts @target_b = target_b @source_b = source_b @cherry_picks = cherry_picks end end class AutoCherryPick attr_accessor :mentioned_list def run rs_list = prepare parse_result(rs_list) end def prepare #忽略由于环境配置造成的变更 不做提交 `git reset --hard` current_rb = KCGit.git.current_branch target_branchs = BranchTool.bigger_release_branchs(current_rb) target_branchs << "develop" rs_list = [] target_branchs.each do |b| KCommercial::UI.info"开始向#{b}分支自动cherry-pick" rs = auto_cherry_pick_in_branch(b,current_rb) unless rs.nil? rs_list << rs end end rs_list end def mentioned_list @mentioned_list ||= KimConfig.configs["AutoCherryPick"]['kim']["mentioned_list"] || [] end def robot_keys @robot_keys ||= KimConfig.configs["AutoCherryPick"]['kim']["robot_key"] || [] end def auto_cherry_pick_in_branch(target_b,current_rb) diffs = KCBranchDiffs.new(current_rb,target_b).diffs unless diffs.empty? KCommercial::UI.info"#{current_rb}分支有#{diffs.size}个commit需要cherry--pick到#{target_b}分支" KCGit.git.checkout(target_b) result = nil #尝试整体合入 all_commits = [] diffs.reverse_each do |diff| all_commits << diff.ori_commit_id end rs = KCGit.git.branch.cherry_pick_all(all_commits) unless rs.code == 0 roll_back_cherry_pick #尝试单个cherry pick result = cherry_pick_by_one(diffs,target_b,current_rb) else KCommercial::UI.info"开始推送#{all_commits.size}个commit 到#{target_b}分支" KCGit.git.push("origin",target_b) result = AutoCherryPickResult.new(target_b:target_b,conflicts:[],cherry_picks:diffs,source_b: current_rb) end else KCommercial::UI.info"不需要自动cherry-pick到#{target_b}分支,退出cherry-pick" end result end def cherry_pick_by_one(diffs,target_b,current_rb) conflicts = [] cherry_picks = [] diffs.reverse_each do |diff| rs = KCGit.git.branch.cherry_pick(diff.ori_commit_id) unless rs.code == 0 roll_back_cherry_pick KCommercial::UI.info("commitid = #{diff.ori_commit_id},message = #{diff.message},autho = #{diff.author.author} 自动cherry-pick失败,开始回滚") conflicts << diff else cherry_picks << diff end end KCommercial::UI.info"有#{cherry_picks.size}个已经 cherry-pick 到#{target_b}分支,有#{conflicts.size}个自动cherry-pick到#{target_b}分支失败" unless cherry_picks.size == 0 KCommercial::UI.info"开始推送#{cherry_picks.size}个commit 到#{target_b}分支" KCGit.git.push("origin",target_b) end result = AutoCherryPickResult.new(target_b:target_b,conflicts:conflicts,cherry_picks:cherry_picks,source_b: current_rb) result end def roll_back_cherry_pick rs = KCGit.git.branch.roll_back unless rs.code == 0 KCommercial::UI.error("自动cherry-pick失败,回滚失败,请手动合入!") exit! -1 end KCommercial::UI.debug("自动cherry-pick失败,回滚成功") end #解析结果,发送通知 def parse_result(results) results.each do |rs| unless rs.conflicts.empty? notify_conflicts(rs) end unless rs.cherry_picks.empty? notify_cherry_picks(rs) end end end def notify_conflicts(rs) conflicts__title = "#{rs.target_b}自动cherry-pick有#{rs.conflicts.size}个冲突,请对应开发人工处理!" msg = diffs_to_markdown(rs.conflicts,conflicts__title) kim_model = KimModel.new(MessageType::Markdown, "", msg, "", mentioned_list) robot_keys.each do |robot_key| kim = Kim.new(robot_key, kim_model) kim.notifi_kim end end def notify_cherry_picks(rs) cp__title = "#{rs.target_b}成功自动cherry-pick#{rs.cherry_picks.size}个commit" msg = diffs_to_markdown(rs.cherry_picks,cp__title) kim_model = KimModel.new(MessageType::Markdown, "", msg, "", mentioned_list) robot_keys.each do |robot_key| kim = Kim.new(robot_key, kim_model) kim.notifi_kim end end def diffs_to_markdown(conflicts,title) unless conflicts.empty? labels = ['commit_msg', 'commit', 'author', "date"] table = MarkdownTables.make_table(labels, diff_to_data(conflicts), is_rows: true, align: %w[l c c l]) <