module Knapsack module Distributors class ReportDistributor < BaseDistributor def sorted_report @sorted_report ||= report.sort_by { |spec_path, time| time }.reverse end def sorted_report_with_existing_specs @sorted_report_with_existing_specs ||= sorted_report.select { |spec_path, time| all_specs.include?(spec_path) } end def total_time_execution @total_time_execution ||= sorted_report_with_existing_specs.map(&:last).reduce(0, :+).to_f end def node_time_execution @node_time_execution ||= total_time_execution / ci_node_total end private def post_assign_spec_files_to_node assign_slow_spec_files assign_remaining_spec_files end def post_specs_for_node(node_index) node_spec = node_specs[node_index] return unless node_spec node_spec[:spec_files_with_time].map(&:first) end def default_node_specs @node_specs = [] ci_node_total.times do |index| @node_specs << { node_index: index, time_left: node_time_execution, spec_files_with_time: [] } end end def assign_slow_spec_files @not_assigned_spec_files = [] node_index = 0 sorted_report_with_existing_specs.each do |spec_file_with_time| assign_slow_spec_file(node_index, spec_file_with_time) node_index += 1 node_index %= ci_node_total end end def assign_slow_spec_file(node_index, spec_file_with_time) time = spec_file_with_time[1] time_left = node_specs[node_index][:time_left] - time if time_left >= 0 or node_specs[node_index][:spec_files_with_time].empty? node_specs[node_index][:time_left] -= time node_specs[node_index][:spec_files_with_time] << spec_file_with_time else @not_assigned_spec_files << spec_file_with_time end end def assign_remaining_spec_files @not_assigned_spec_files.each do |spec_file_with_time| index = node_with_max_time_left time = spec_file_with_time[1] node_specs[index][:time_left] -= time node_specs[index][:spec_files_with_time] << spec_file_with_time end end def node_with_max_time_left node_spec = node_specs.max { |a,b| a[:time_left] <=> b[:time_left] } node_spec[:node_index] end end end end