class Coverband::Reporter
def self.baseline
def self.baseline require 'coverage' Coverage.start yield @project_directory = File.expand_path(Coverband.configuration.root) results = Coverage.result results = results.reject { |key, val| !key.match(@project_directory) || Coverband.configuration.ignore.any? { |pattern| key.match(/#{pattern}/) } } if Coverband.configuration.verbose Coverband.configuration.logger.info results.inspect end config_dir = File.dirname(Coverband.configuration.baseline_file) Dir.mkdir config_dir unless File.exists?(config_dir) File.open(Coverband.configuration.baseline_file, 'w') { |f| f.write(results.to_json) } end
def self.clear_coverage(redis = nil)
def self.clear_coverage(redis = nil) redis ||= Coverband.configuration.redis redis.smembers('coverband').each { |key| redis.del("coverband.#{key}") } redis.del("coverband") end
def self.current_root
def self.current_root File.expand_path(Coverband.configuration.root) end
def self.filename_from_key(key, roots)
def self.filename_from_key(key, roots) filename = key roots.each do |root| filename = filename.gsub(/^#{root}/, './') end # the filename for SimpleCov is expected to be a full path. # roots.last should be roots << current_root}/ # a fully expanded path of config.root filename = filename.gsub('./', roots.last) filename end
def self.fix_file_names(report_hash, roots)
def self.fix_file_names(report_hash, roots) fixed_report = {} #normalize names across servers report_hash.each_pair do |key, values| filename = filename_from_key(key, roots) fixed_report[filename] = values end fixed_report end
def self.get_current_scov_data(options = {})
def self.get_current_scov_data(options = {}) additional_scov_data = options.fetch(:additional_scov_data) { [] } if (additional_scov_data) report_scov_with_additional_data(Coverband.configuration.redis, Coverband.configuration.coverage_baseline, additional_scov_data, get_roots) else get_current_scov_data_imp(Coverband.configuration.redis, get_roots) end end
def self.get_current_scov_data_imp(redis, roots)
def self.get_current_scov_data_imp(redis, roots) scov_style_report = {} redis.smembers('coverband').each do |key| next if Coverband.configuration.ignore.any?{ |i| key.match(i) } line_data = line_hash(redis, key, roots) if line_data line_key = line_data.keys.first previous_line_hash = scov_style_report[line_key] if previous_line_hash line_data[line_key] = merge_arrays(line_data[line_key], previous_line_hash) end scov_style_report.merge!(line_data) end end scov_style_report = fix_file_names(scov_style_report, roots) scov_style_report end
def self.get_roots
def self.get_roots roots = Coverband.configuration.root_paths roots << "#{current_root}/" roots end
def self.line_hash(redis, key, roots)
>> puts Coverage.result.inspect
def self.line_hash(redis, key, roots) filename = filename_from_key(key, roots) if File.exists?(filename) lines_hit = redis.smembers("coverband.#{key}") count = File.foreach(filename).inject(0) { |c, line| c + 1 } if filename.match(/\.erb/) line_array = Array.new(count, nil) else line_array = Array.new(count, 0) end line_array.each_with_index{|line,index| line_array[index] = 1 if lines_hit.include?((index + 1).to_s) } {filename => line_array} else Coverband.configuration.logger.info "file #{filename} not found in project" nil end end
def self.line_members(redis, key)
def self.line_members(redis, key) redis.smembers("coverband.#{key}").inspect end
def self.merge_arrays(first, second)
merge to
[nil,0,1,0,0]
[0,0,1,0,1]
def self.merge_arrays(first, second) merged = [] longest = first.length > second.length ? first : second longest.each_with_index do |line, index| if first[index] || second[index] merged[index] = (first[index].to_i + second[index].to_i >= 1 ? 1 : 0) else merged[index] = nil end end merged end
def self.merge_existing_coverage(scov_style_report, existing_coverage)
def self.merge_existing_coverage(scov_style_report, existing_coverage) existing_coverage.each_pair do |key, lines| if current_lines = scov_style_report[key] lines.each_with_index do |line, index| if line.nil? && current_lines[index].to_i == 0 current_lines[index] = nil else current_lines[index] = current_lines[index] ? (current_lines[index].to_i + line.to_i) : nil end end scov_style_report[key] = current_lines else scov_style_report[key] = lines end end scov_style_report end
def self.report(options = {})
def self.report(options = {}) begin require 'simplecov' if Coverband.configuration.reporter=='scov' rescue Coverband.configuration.logger.error "coverband requires simplecov in order to generate a report, when configured for the scov report style." return end redis = Coverband.configuration.redis roots = get_roots existing_coverage = Coverband.configuration.coverage_baseline open_report = options.fetch(:open_report) { true } if Coverband.configuration.verbose Coverband.configuration.logger.info "fixing root: #{roots.join(', ')}" end if Coverband.configuration.reporter == 'scov' additional_scov_data = options.fetch(:additional_scov_data) { [] } if Coverband.configuration.verbose print additional_scov_data end report_scov(redis, existing_coverage, additional_scov_data, roots, open_report) else lines = redis.smembers('coverband').map{ |key| report_line(redis, key) } Coverband.configuration.logger.info lines.join("\n") end end
def self.report_line(redis, key)
/Users/danmayer/projects/cover_band_server/app/rb: ["54", "55"]
/Users/danmayer/projects/cover_band_server/views/index/erb: ["0", "2", "3", "6", "65532", "65533"]
def self.report_line(redis, key) "#{key}: #{line_members(redis, key)}" end
def self.report_scov(redis, existing_coverage, additional_scov_data, roots, open_report)
def self.report_scov(redis, existing_coverage, additional_scov_data, roots, open_report) scov_style_report = report_scov_with_additional_data(redis, existing_coverage, additional_scov_data, roots) if Coverband.configuration.verbose Coverband.configuration.logger.info "report: " Coverband.configuration.logger.info scov_style_report.inspect end # add in files never hit in coverband SimpleCov.track_files "#{current_root}/{app,lib,config}/**/*.{rb,haml,erb,slim}" SimpleCov::Result.new(SimpleCov.add_not_loaded_files(scov_style_report)).format! if open_report `open #{SimpleCov.coverage_dir}/index.html` else Coverband.configuration.logger.info "report is ready and viewable: open #{SimpleCov.coverage_dir}/index.html" end S3ReportWriter.new(Coverband.configuration.s3_bucket).persist! if Coverband.configuration.s3_bucket end
def self.report_scov_with_additional_data(redis, existing_coverage, additional_scov_data, roots)
def self.report_scov_with_additional_data(redis, existing_coverage, additional_scov_data, roots) scov_style_report = get_current_scov_data_imp redis, roots existing_coverage = fix_file_names(existing_coverage, roots) scov_style_report = merge_existing_coverage(scov_style_report, existing_coverage) additional_scov_data.each do |data| scov_style_report = merge_existing_coverage(scov_style_report, data) end scov_style_report end