coverband 2.0.3 → 3.0.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/.rubocop.yml +73 -0
- data/.travis.yml +0 -3
- data/README.md +3 -3
- data/changes.md +65 -49
- data/coverband.gemspec +1 -1
- data/lib/coverband.rb +9 -6
- data/lib/coverband/adapters/base.rb +22 -2
- data/lib/coverband/adapters/file_store.rb +11 -11
- data/lib/coverband/adapters/redis_store.rb +22 -57
- data/lib/coverband/collectors/coverage.rb +57 -53
- data/lib/coverband/configuration.rb +6 -14
- data/lib/coverband/integrations/background.rb +7 -0
- data/lib/coverband/{middleware.rb → integrations/middleware.rb} +1 -3
- data/lib/coverband/reporters/base.rb +37 -82
- data/lib/coverband/reporters/console_report.rb +3 -0
- data/lib/coverband/reporters/simple_cov_report.rb +4 -3
- data/lib/coverband/reporters/web.rb +38 -35
- data/lib/coverband/utils/s3_report_writer.rb +59 -0
- data/lib/coverband/{tasks.rb → utils/tasks.rb} +0 -0
- data/lib/coverband/version.rb +1 -1
- data/test/benchmarks/benchmark.rake +3 -3
- data/test/test_helper.rb +18 -17
- data/test/unit/adapters_base_test.rb +29 -0
- data/test/unit/adapters_file_store_test.rb +2 -2
- data/test/unit/adapters_redis_store_test.rb +14 -51
- data/test/unit/collectors_coverage_test.rb +3 -107
- data/test/unit/configuration_test.rb +2 -9
- data/test/unit/full_stack_test.rb +47 -0
- data/test/unit/middleware_test.rb +21 -57
- data/test/unit/reports_base_test.rb +12 -71
- data/test/unit/reports_console_test.rb +9 -22
- data/test/unit/reports_simple_cov_test.rb +3 -37
- data/test/unit/reports_web_test.rb +4 -0
- data/test/unit/{s3_report_writer_test.rb → utils_s3_report_writer_test.rb} +1 -1
- metadata +29 -18
- data/lib/coverband/adapters/memory_cache_store.rb +0 -53
- data/lib/coverband/collectors/base.rb +0 -126
- data/lib/coverband/collectors/trace.rb +0 -122
- data/lib/coverband/s3_report_writer.rb +0 -49
- data/test/unit/adapters_memory_cache_store_test.rb +0 -66
- data/test/unit/collectors_base_test.rb +0 -104
- data/test/unit/collectors_trace_test.rb +0 -106
@@ -2,64 +2,81 @@
|
|
2
2
|
|
3
3
|
module Coverband
|
4
4
|
module Collectors
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
###
|
6
|
+
# TODO: look at alternatives to semaphore
|
7
|
+
# StandardError seems line be better option
|
8
|
+
# coverband previously had RuntimeError here
|
9
|
+
# but runtime error can let a large number of error crash this method
|
10
|
+
# and this method is currently in a ensure block in middleware and threads
|
11
|
+
###
|
12
|
+
class Coverage
|
13
|
+
def self.instance
|
14
|
+
Thread.current[:coverband_instance] ||= Coverband::Collectors::Coverage.new
|
8
15
|
end
|
9
16
|
|
10
|
-
def
|
11
|
-
|
17
|
+
def reset_instance
|
18
|
+
@project_directory = File.expand_path(Coverband.configuration.root)
|
19
|
+
@file_line_usage = {}
|
20
|
+
@ignored_files = Set.new
|
21
|
+
@ignore_patterns = Coverband.configuration.ignore + ['internal:prelude', 'schema.rb']
|
22
|
+
@reporting_frequency = Coverband.configuration.reporting_frequency
|
23
|
+
@store = Coverband.configuration.store
|
24
|
+
@verbose = Coverband.configuration.verbose
|
25
|
+
@logger = Coverband.configuration.logger
|
26
|
+
@current_thread = Thread.current
|
27
|
+
Thread.current[:coverband_instance] = nil
|
28
|
+
self
|
12
29
|
end
|
13
30
|
|
14
|
-
def report_coverage
|
15
|
-
|
16
|
-
|
31
|
+
def report_coverage(force_report = false)
|
32
|
+
return if !ready_to_report? && !force_report
|
33
|
+
unless @store
|
34
|
+
@logger.debug 'no store set, no-op'
|
17
35
|
return
|
18
36
|
end
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
37
|
+
new_results = get_new_coverage_results
|
38
|
+
add_filtered_files(new_results)
|
39
|
+
@store.save_report(files_with_line_usage)
|
40
|
+
@file_line_usage.clear
|
41
|
+
rescue StandardError => err
|
42
|
+
if @verbose
|
43
|
+
@logger.error 'coverage failed to store'
|
44
|
+
@logger.error "error: #{err.inspect} #{err.message}"
|
45
|
+
@logger.error err.backtrace
|
23
46
|
end
|
47
|
+
end
|
24
48
|
|
25
|
-
|
26
|
-
|
49
|
+
protected
|
50
|
+
|
51
|
+
def track_file?(file)
|
52
|
+
@ignore_patterns.none? do |pattern|
|
53
|
+
file.include?(pattern)
|
54
|
+
end && file.start_with?(@project_directory)
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def add_filtered_files(new_results)
|
27
60
|
new_results.each_pair do |file, line_counts|
|
28
61
|
next if @ignored_files.include?(file)
|
29
62
|
next unless track_file?(file)
|
30
63
|
add_file(file, line_counts)
|
31
64
|
end
|
65
|
+
end
|
32
66
|
|
33
|
-
|
34
|
-
|
35
|
-
output_file_line_usage if @verbose == 'debug'
|
36
|
-
end
|
37
|
-
|
38
|
-
if @store
|
39
|
-
@store.save_report(files_with_line_usage)
|
40
|
-
@file_line_usage.clear
|
41
|
-
elsif @verbose
|
42
|
-
@logger.debug 'coverage report: '
|
43
|
-
@logger.debug @file_line_usage.inspect
|
44
|
-
end
|
45
|
-
# StandardError might be better option
|
46
|
-
# coverband previously had RuntimeError here
|
47
|
-
# but runtime error can let a large number of error crash this method
|
48
|
-
# and this method is currently in a ensure block in middleware
|
49
|
-
rescue StandardError => err
|
50
|
-
failed!
|
51
|
-
if @verbose
|
52
|
-
@logger.error 'coverage missing'
|
53
|
-
@logger.error "error: #{err.inspect} #{err.message}"
|
54
|
-
@logger.error err.backtrace
|
55
|
-
end
|
67
|
+
def ready_to_report?
|
68
|
+
(rand * 100.0) >= (100.0 - @reporting_frequency)
|
56
69
|
end
|
57
70
|
|
58
|
-
|
71
|
+
def get_new_coverage_results
|
72
|
+
coverage_results = nil
|
73
|
+
@semaphore.synchronize { coverage_results = new_coverage(::Coverage.peek_result.dup) }
|
74
|
+
coverage_results
|
75
|
+
end
|
59
76
|
|
60
77
|
def files_with_line_usage
|
61
78
|
@file_line_usage.select do |_file_name, coverage|
|
62
|
-
coverage.
|
79
|
+
coverage.any? { |value| value && value.nonzero? }
|
63
80
|
end
|
64
81
|
end
|
65
82
|
|
@@ -93,21 +110,8 @@ module Coverband
|
|
93
110
|
new_results.dup
|
94
111
|
end
|
95
112
|
|
96
|
-
# TODO this seems like a dumb conversion for the already good coverage format
|
97
|
-
# coverage is 0 based other implementation matches line number
|
98
113
|
def add_file(file, line_counts)
|
99
|
-
@file_line_usage[file] =
|
100
|
-
line_counts.each_with_index do |line_count, index|
|
101
|
-
@file_line_usage[file][(index + 1)] = line_count if line_count
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def file_usage
|
106
|
-
hash = {}
|
107
|
-
@file_line_usage.each do |file, lines|
|
108
|
-
hash[file] = lines.values.compact.inject(0, :+)
|
109
|
-
end
|
110
|
-
hash.sort_by { |_key, value| value }
|
114
|
+
@file_line_usage[file] = line_counts
|
111
115
|
end
|
112
116
|
|
113
117
|
def initialize
|
@@ -3,9 +3,9 @@
|
|
3
3
|
module Coverband
|
4
4
|
class Configuration
|
5
5
|
attr_accessor :redis, :root_paths, :root,
|
6
|
-
:ignore, :additional_files, :
|
7
|
-
:reporter, :
|
8
|
-
:
|
6
|
+
:ignore, :additional_files, :verbose,
|
7
|
+
:reporter, :reporting_frequency,
|
8
|
+
:disable_on_failure_for,
|
9
9
|
:redis_namespace, :redis_ttl,
|
10
10
|
:safe_reload_files
|
11
11
|
|
@@ -13,24 +13,16 @@ module Coverband
|
|
13
13
|
|
14
14
|
def initialize
|
15
15
|
@root = Dir.pwd
|
16
|
-
@redis = nil
|
17
16
|
@root_paths = []
|
18
17
|
@ignore = []
|
19
18
|
@additional_files = []
|
20
|
-
@
|
21
|
-
@percentage = 0.0
|
19
|
+
@reporting_frequency = 0.0
|
22
20
|
@verbose = false
|
23
21
|
@reporter = 'scov'
|
24
|
-
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3.0')
|
25
|
-
@collector = 'trace'
|
26
|
-
else
|
27
|
-
@collector = 'coverage'
|
28
|
-
end
|
29
22
|
@logger = Logger.new(STDOUT)
|
30
|
-
@startup_delay = 0
|
31
|
-
@memory_caching = false
|
32
23
|
@store = nil
|
33
|
-
|
24
|
+
|
25
|
+
# TODO: should we push these to adapter configs
|
34
26
|
@s3_region = nil
|
35
27
|
@s3_bucket = nil
|
36
28
|
@s3_access_key_id = nil
|
@@ -7,11 +7,9 @@ module Coverband
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def call(env)
|
10
|
-
Coverband::Collectors::Base.instance.configure_sampling
|
11
|
-
Coverband::Collectors::Base.instance.record_coverage
|
12
10
|
@app.call(env)
|
13
11
|
ensure
|
14
|
-
Coverband::Collectors::
|
12
|
+
Coverband::Collectors::Coverage.instance.report_coverage
|
15
13
|
end
|
16
14
|
end
|
17
15
|
end
|
@@ -2,25 +2,26 @@
|
|
2
2
|
|
3
3
|
module Coverband
|
4
4
|
module Reporters
|
5
|
+
###
|
6
|
+
# This is the base clase for report generation
|
7
|
+
# it helps with filtering, normalization, etc for final reprort generation
|
8
|
+
###
|
5
9
|
class Base
|
6
|
-
def self.report(store,
|
7
|
-
|
8
|
-
additional_coverage_data = options.fetch(:additional_scov_data) { [] }
|
10
|
+
def self.report(store, _options = {})
|
11
|
+
scov_style_report = get_current_scov_data_imp(store, root_paths)
|
9
12
|
|
10
13
|
if Coverband.configuration.verbose
|
11
|
-
|
12
|
-
Coverband.configuration.logger.debug
|
13
|
-
end
|
14
|
-
|
15
|
-
scov_style_report = report_scov_with_additional_data(store, additional_coverage_data, roots)
|
16
|
-
|
17
|
-
if Coverband.configuration.verbose
|
18
|
-
Coverband.configuration.logger.debug "report:\n #{scov_style_report.inspect}"
|
14
|
+
msg = "report:\n #{scov_style_report.inspect}"
|
15
|
+
Coverband.configuration.logger.debug msg
|
19
16
|
end
|
20
17
|
scov_style_report
|
21
18
|
end
|
22
19
|
|
23
|
-
|
20
|
+
# protected
|
21
|
+
# below are all not public API
|
22
|
+
# but as they are class methods protected doesn't really do anything
|
23
|
+
|
24
|
+
def self.root_paths
|
24
25
|
roots = Coverband.configuration.root_paths
|
25
26
|
roots << "#{current_root}/"
|
26
27
|
roots
|
@@ -30,19 +31,26 @@ module Coverband
|
|
30
31
|
File.expand_path(Coverband.configuration.root)
|
31
32
|
end
|
32
33
|
|
33
|
-
protected
|
34
|
-
|
35
34
|
def self.fix_file_names(report_hash, roots)
|
36
|
-
|
37
|
-
|
35
|
+
if Coverband.configuration.verbose
|
36
|
+
Coverband.configuration.logger.info "fixing root: #{roots.join(', ')}"
|
37
|
+
end
|
38
|
+
|
39
|
+
fixed_report = {}
|
40
|
+
# normalize names across servers
|
41
|
+
report_hash.each_pair do |key, vals|
|
38
42
|
filename = filename_from_key(key, roots)
|
39
|
-
fixed_report
|
43
|
+
if fixed_report.key?(filename)
|
44
|
+
fixed_report[filename] = merge_arrays(fixed_report[filename], vals)
|
45
|
+
else
|
46
|
+
fixed_report[filename] = vals
|
47
|
+
end
|
40
48
|
end
|
41
49
|
fixed_report
|
42
50
|
end
|
43
51
|
|
44
|
-
# > merge_arrays([0,0,1,0,1],[nil,0,1,0,0])
|
45
|
-
# [0,0,1,0,1]
|
52
|
+
# > merge_arrays([nil,0,0,1,0,1],[nil,nil,0,1,0,0])
|
53
|
+
# > [nil,0,0,1,0,1]
|
46
54
|
def self.merge_arrays(first, second)
|
47
55
|
merged = []
|
48
56
|
longest = first.length > second.length ? first : second
|
@@ -56,20 +64,6 @@ module Coverband
|
|
56
64
|
merged
|
57
65
|
end
|
58
66
|
|
59
|
-
# > merge_existing_coverage({"file.rb" => [0,1,2,nil,nil,nil]}, {"file.rb" => [0,1,2,nil,0,1,2]})
|
60
|
-
# expects = {"file.rb" => [0,2,4,nil,0,1,2]}
|
61
|
-
def self.merge_existing_coverage(scov_style_report, existing_coverage)
|
62
|
-
existing_coverage.each_pair do |file_key, existing_lines|
|
63
|
-
next if Coverband.configuration.ignore.any? { |i| file_key.match(i) }
|
64
|
-
scov_style_report[file_key] = if current_line_hits = scov_style_report[file_key]
|
65
|
-
merge_arrays(current_line_hits, existing_lines)
|
66
|
-
else
|
67
|
-
existing_lines
|
68
|
-
end
|
69
|
-
end
|
70
|
-
scov_style_report
|
71
|
-
end
|
72
|
-
|
73
67
|
def self.filename_from_key(key, roots)
|
74
68
|
filename = key
|
75
69
|
roots.each do |root|
|
@@ -82,64 +76,25 @@ module Coverband
|
|
82
76
|
filename
|
83
77
|
end
|
84
78
|
|
85
|
-
|
86
|
-
#
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
lines_hit = store.covered_lines_for_file(key)
|
94
|
-
if lines_hit.is_a?(Array)
|
95
|
-
line_array.each_with_index { |_, index| line_array[index] = 1 if lines_hit.include?((index + 1)) }
|
96
|
-
else
|
97
|
-
line_array.each_with_index { |_, index| line_array[index] = (line_array[index].to_i + lines_hit[(index + 1).to_s].to_i) if lines_hit.keys.include?((index + 1).to_s) }
|
98
|
-
end
|
99
|
-
{ filename => line_array }
|
100
|
-
else
|
101
|
-
Coverband.configuration.logger.info "file #{filename} not found in project"
|
102
|
-
nil
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
79
|
+
###
|
80
|
+
# why do we need to merge covered files data?
|
81
|
+
# basically because paths on machines or deployed hosts could be different, so
|
82
|
+
# two different keys could point to the same filename or `line_key`
|
83
|
+
# this logic should be pushed to base report
|
84
|
+
# TODO: think we are filtering based on ignore while sending to the store
|
85
|
+
# and as we pull it out here
|
86
|
+
###
|
106
87
|
def self.get_current_scov_data_imp(store, roots)
|
107
88
|
scov_style_report = {}
|
108
|
-
|
109
|
-
###
|
110
|
-
# why do we need to merge covered files data?
|
111
|
-
# basically because paths on machines or deployed hosts could be different, so
|
112
|
-
# two different keys could point to the same filename or `line_key`
|
113
|
-
# this logic should be pushed to base report
|
114
|
-
###
|
115
|
-
store.covered_files.each do |key|
|
89
|
+
store.coverage.each_pair do |key, line_data|
|
116
90
|
next if Coverband.configuration.ignore.any? { |i| key.match(i) }
|
117
|
-
line_data = line_hash(store, key, roots)
|
118
|
-
|
119
91
|
next unless line_data
|
120
|
-
|
121
|
-
previous_line_hash = scov_style_report[line_key]
|
122
|
-
|
123
|
-
if previous_line_hash
|
124
|
-
line_data[line_key] = merge_arrays(line_data[line_key], previous_line_hash)
|
125
|
-
end
|
126
|
-
|
127
|
-
scov_style_report.merge!(line_data)
|
92
|
+
scov_style_report[key] = line_data
|
128
93
|
end
|
129
94
|
|
130
95
|
scov_style_report = fix_file_names(scov_style_report, roots)
|
131
96
|
scov_style_report
|
132
97
|
end
|
133
|
-
|
134
|
-
def self.report_scov_with_additional_data(store, additional_scov_data, roots)
|
135
|
-
scov_style_report = get_current_scov_data_imp(store, roots)
|
136
|
-
|
137
|
-
additional_scov_data.each do |data|
|
138
|
-
scov_style_report = merge_existing_coverage(scov_style_report, data)
|
139
|
-
end
|
140
|
-
|
141
|
-
scov_style_report
|
142
|
-
end
|
143
98
|
end
|
144
99
|
end
|
145
100
|
end
|
@@ -7,12 +7,12 @@ module Coverband
|
|
7
7
|
begin
|
8
8
|
require 'simplecov'
|
9
9
|
rescue StandardError
|
10
|
-
|
10
|
+
msg = 'coverband requires simplecov to generate a report, when config.reporter=scov'
|
11
|
+
Coverband.configuration.logger.error msg
|
11
12
|
return
|
12
13
|
end
|
13
14
|
|
14
15
|
scov_style_report = super(store, options)
|
15
|
-
|
16
16
|
open_report = options.fetch(:open_report) { true }
|
17
17
|
|
18
18
|
# set root to show files if user has simplecov profiles
|
@@ -43,7 +43,8 @@ module Coverband
|
|
43
43
|
access_key_id: Coverband.configuration.s3_access_key_id,
|
44
44
|
secret_access_key: Coverband.configuration.s3_secret_access_key
|
45
45
|
}
|
46
|
-
S3ReportWriter.new(Coverband.configuration.s3_bucket,
|
46
|
+
Coverband::Utils::S3ReportWriter.new(Coverband.configuration.s3_bucket,
|
47
|
+
s3_writer_options).persist! if Coverband.configuration.s3_bucket
|
47
48
|
end
|
48
49
|
end
|
49
50
|
end
|
@@ -9,10 +9,10 @@ module Coverband
|
|
9
9
|
attr_reader :request
|
10
10
|
|
11
11
|
def initialize
|
12
|
+
full_path = Gem::Specification.find_by_name('simplecov-html').full_gem_path
|
12
13
|
@static = Rack::Static.new(self,
|
13
|
-
|
14
|
-
|
15
|
-
)
|
14
|
+
root: File.expand_path('public', full_path),
|
15
|
+
urls: [/.*\.css/, /.*\.js/, /.*\.gif/, /.*\.png/])
|
16
16
|
end
|
17
17
|
|
18
18
|
def call(env)
|
@@ -20,60 +20,63 @@ module Coverband
|
|
20
20
|
|
21
21
|
if request.post?
|
22
22
|
case request.path_info
|
23
|
-
when
|
23
|
+
when %r{\/collect_update_and_view}
|
24
24
|
collect_update_and_view
|
25
|
-
when
|
25
|
+
when %r{\/clear}
|
26
26
|
clear
|
27
|
-
when
|
27
|
+
when %r{\/update_report}
|
28
28
|
update_report
|
29
|
-
when
|
29
|
+
when %r{\/collect_coverage}
|
30
30
|
collect_coverage
|
31
|
-
when
|
31
|
+
when %r{\/reload_files}
|
32
32
|
reload_files
|
33
33
|
else
|
34
|
-
[404, {'Content-Type' => 'text/html'}, ['404 error!']]
|
34
|
+
[404, { 'Content-Type' => 'text/html' }, ['404 error!']]
|
35
35
|
end
|
36
36
|
else
|
37
37
|
case request.path_info
|
38
38
|
when /.*\.(css|js|gif|png)/
|
39
39
|
@static.call(env)
|
40
|
-
when
|
41
|
-
[200, {'Content-Type' => 'text/html'}, [show]]
|
42
|
-
when
|
43
|
-
[200, {'Content-Type' => 'text/html'}, [index]]
|
40
|
+
when %r{\/show}
|
41
|
+
[200, { 'Content-Type' => 'text/html' }, [show]]
|
42
|
+
when %r{\/}
|
43
|
+
[200, { 'Content-Type' => 'text/html' }, [index]]
|
44
44
|
else
|
45
|
-
[404, {'Content-Type' => 'text/html'}, ['404 error!']]
|
45
|
+
[404, { 'Content-Type' => 'text/html' }, ['404 error!']]
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
#
|
50
|
+
# TODO: move to file or template
|
51
51
|
def index
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
52
|
+
notice = "<strong>Notice:</strong> #{Rack::Utils.escape_html(request.params['notice'])}<br/>"
|
53
|
+
notice = request.params['notice'] ? notice : ''
|
54
|
+
%(
|
55
|
+
<html>
|
56
|
+
#{notice}
|
57
|
+
<ul>
|
58
|
+
<li><a href='#{base_path}'>Coverband Web Admin Index</a></li>
|
59
|
+
<li>#{button("#{base_path}collect_update_and_view", 'collect data, update report, & view')}</li>
|
60
|
+
<li><a href='#{base_path}show'>view coverage report</a></li>
|
61
|
+
<li>#{button("#{base_path}collect_coverage", 'update coverage data (collect coverage)')}</li>
|
62
|
+
<li>#{button("#{base_path}update_report", 'update coverage report (rebuild report)')}</li>
|
63
|
+
<li>#{button("#{base_path}clear", 'clear coverage report')}</li>
|
64
|
+
<li>#{button("#{base_path}reload_files", 'reload Coverband files')}</li>
|
65
|
+
</ul>
|
66
|
+
<br/>
|
67
|
+
version: #{Coverband::VERSION}<br/>
|
68
|
+
<a href='https://github.com/danmayer/coverband'>Coverband</a>
|
69
|
+
</html>
|
70
|
+
)
|
68
71
|
end
|
69
72
|
|
70
73
|
def show
|
71
74
|
html = s3.get_object(bucket: Coverband.configuration.s3_bucket, key: 'coverband/index.html').body.read
|
72
|
-
#
|
75
|
+
# HACK: the static HTML assets to link to the path where this was mounted
|
73
76
|
html = html.gsub("src='", "src='#{base_path}")
|
74
77
|
html = html.gsub("href='", "href='#{base_path}")
|
75
|
-
html = html.gsub(
|
76
|
-
html = html.gsub(
|
78
|
+
html = html.gsub('loading.gif', "#{base_path}loading.gif")
|
79
|
+
html = html.gsub('/images/', "#{base_path}images/")
|
77
80
|
html
|
78
81
|
end
|
79
82
|
|
@@ -90,7 +93,7 @@ module Coverband
|
|
90
93
|
end
|
91
94
|
|
92
95
|
def collect_coverage
|
93
|
-
Coverband::Collectors::
|
96
|
+
Coverband::Collectors::Coverage.instance.report_coverage
|
94
97
|
notice = 'coverband coverage collected'
|
95
98
|
[301, { 'Location' => "#{base_path}?notice=#{notice}" }, []]
|
96
99
|
end
|