coverband 4.2.0 → 4.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +29 -9
- data/.travis.yml +10 -1
- data/Gemfile +3 -1
- data/Gemfile.rails4 +1 -0
- data/README.md +40 -15
- data/Rakefile +14 -3
- data/changes.md +47 -12
- data/coverband.gemspec +3 -1
- data/lib/coverband/adapters/base.rb +60 -36
- data/lib/coverband/adapters/file_store.rb +8 -8
- data/lib/coverband/adapters/redis_store.rb +18 -10
- data/lib/coverband/at_exit.rb +2 -11
- data/lib/coverband/collectors/coverage.rb +32 -36
- data/lib/coverband/collectors/delta.rb +34 -28
- data/lib/coverband/configuration.rb +76 -32
- data/lib/coverband/integrations/background.rb +8 -4
- data/lib/coverband/integrations/{middleware.rb → background_middleware.rb} +2 -6
- data/lib/coverband/integrations/bundler.rb +8 -0
- data/lib/coverband/integrations/report_middleware.rb +15 -0
- data/lib/coverband/integrations/resque.rb +3 -5
- data/lib/coverband/reporters/base.rb +39 -14
- data/lib/coverband/reporters/html_report.rb +21 -27
- data/lib/coverband/reporters/web.rb +13 -21
- data/lib/coverband/utils/file_list.rb +16 -5
- data/lib/coverband/utils/file_path_helper.rb +14 -3
- data/lib/coverband/utils/html_formatter.rb +25 -8
- data/lib/coverband/utils/lines_classifier.rb +5 -0
- data/lib/coverband/utils/railtie.rb +11 -12
- data/lib/coverband/utils/result.rb +1 -37
- data/lib/coverband/utils/results.rb +51 -0
- data/lib/coverband/utils/source_file.rb +31 -6
- data/lib/coverband/utils/tasks.rb +9 -10
- data/lib/coverband/version.rb +1 -1
- data/lib/coverband.rb +32 -21
- data/public/application.js +27 -0
- data/test/benchmarks/benchmark.rake +144 -26
- data/test/coverband/adapters/base_test.rb +73 -42
- data/test/coverband/adapters/file_store_test.rb +48 -37
- data/test/coverband/adapters/redis_store_test.rb +41 -10
- data/test/coverband/at_exit_test.rb +0 -2
- data/test/coverband/collectors/coverage_test.rb +57 -9
- data/test/coverband/collectors/delta_test.rb +36 -6
- data/test/coverband/configuration_test.rb +47 -7
- data/test/coverband/coverband_test.rb +14 -2
- data/test/coverband/integrations/background_middleware_test.rb +44 -0
- data/test/coverband/integrations/background_test.rb +1 -3
- data/test/coverband/integrations/report_middleware_test.rb +44 -0
- data/test/coverband/integrations/resque_worker_test.rb +4 -3
- data/test/coverband/integrations/test_resque_job.rb +3 -1
- data/test/coverband/reporters/base_test.rb +4 -4
- data/test/coverband/reporters/console_test.rb +1 -2
- data/test/coverband/reporters/html_test.rb +58 -19
- data/test/coverband/reporters/web_test.rb +0 -10
- data/test/coverband/utils/file_groups_test.rb +11 -5
- data/test/coverband/utils/file_list_test.rb +5 -5
- data/test/coverband/utils/html_formatter_test.rb +43 -0
- data/test/coverband/utils/result_test.rb +6 -47
- data/test/coverband/utils/results_test.rb +54 -0
- data/test/coverband/utils/s3_report_test.rb +2 -0
- data/test/coverband/utils/source_file_test.rb +50 -0
- data/test/dog.rb.erb +12 -0
- data/test/forked/rails_full_stack_test.rb +106 -0
- data/test/forked/rails_rake_full_stack_test.rb +40 -0
- data/test/integration/full_stack_test.rb +17 -15
- data/test/rails4_dummy/Rakefile +6 -0
- data/test/rails4_dummy/config/application.rb +8 -9
- data/test/rails4_dummy/config/coverband.rb +5 -3
- data/test/rails5_dummy/Rakefile +6 -0
- data/test/rails5_dummy/config/application.rb +6 -10
- data/test/rails5_dummy/config/coverband.rb +4 -2
- data/test/rails_test_helper.rb +22 -5
- data/test/test_helper.rb +42 -4
- data/test/unique_files.rb +17 -9
- data/views/file_list.erb +2 -2
- data/views/gem_list.erb +10 -1
- data/views/layout.erb +10 -3
- data/views/source_file.erb +13 -4
- data/views/source_file_loader.erb +1 -1
- metadata +52 -9
- data/test/coverband/integrations/middleware_test.rb +0 -96
- data/test/integration/rails_full_stack_test.rb +0 -95
|
@@ -13,23 +13,31 @@ module Coverband
|
|
|
13
13
|
###
|
|
14
14
|
REDIS_STORAGE_FORMAT_VERSION = 'coverband_3_2'
|
|
15
15
|
|
|
16
|
+
attr_reader :redis_namespace
|
|
17
|
+
|
|
16
18
|
def initialize(redis, opts = {})
|
|
17
19
|
super()
|
|
18
20
|
@redis = redis
|
|
19
21
|
@ttl = opts[:ttl]
|
|
20
22
|
@redis_namespace = opts[:redis_namespace]
|
|
21
23
|
@format_version = REDIS_STORAGE_FORMAT_VERSION
|
|
24
|
+
@keys = {}
|
|
25
|
+
Coverband::TYPES.each do |type|
|
|
26
|
+
@keys[type] = [@format_version, @redis_namespace, type].compact.join('.')
|
|
27
|
+
end
|
|
22
28
|
end
|
|
23
29
|
|
|
24
30
|
def clear!
|
|
25
31
|
Coverband::TYPES.each do |type|
|
|
26
32
|
@redis.del(type_base_key(type))
|
|
27
33
|
end
|
|
34
|
+
# temporarily clear the old namespace of coverband_3_2
|
|
35
|
+
@redis.del(type_base_key(nil))
|
|
28
36
|
end
|
|
29
37
|
|
|
30
38
|
def clear_file!(filename)
|
|
31
39
|
Coverband::TYPES.each do |type|
|
|
32
|
-
data =
|
|
40
|
+
data = coverage(type)
|
|
33
41
|
data.delete(filename)
|
|
34
42
|
save_coverage(data, type)
|
|
35
43
|
end
|
|
@@ -47,7 +55,7 @@ module Coverband
|
|
|
47
55
|
def migrate!
|
|
48
56
|
reset_base_key
|
|
49
57
|
@format_version = 'coverband3_1'
|
|
50
|
-
previous_data =
|
|
58
|
+
previous_data = coverage
|
|
51
59
|
if previous_data.empty?
|
|
52
60
|
puts 'no previous data to migrate found'
|
|
53
61
|
exit 0
|
|
@@ -58,7 +66,7 @@ module Coverband
|
|
|
58
66
|
clear!
|
|
59
67
|
reset_base_key
|
|
60
68
|
@format_version = REDIS_STORAGE_FORMAT_VERSION
|
|
61
|
-
save_coverage(merge_reports(
|
|
69
|
+
save_coverage(merge_reports(coverage, relative_path_report, skip_expansion: true))
|
|
62
70
|
end
|
|
63
71
|
|
|
64
72
|
def type=(type)
|
|
@@ -66,6 +74,12 @@ module Coverband
|
|
|
66
74
|
reset_base_key
|
|
67
75
|
end
|
|
68
76
|
|
|
77
|
+
def coverage(local_type = nil, opts = {})
|
|
78
|
+
local_type ||= opts.key?(:override_type) ? opts[:override_type] : type
|
|
79
|
+
data = redis.get type_base_key(local_type)
|
|
80
|
+
data ? JSON.parse(data) : {}
|
|
81
|
+
end
|
|
82
|
+
|
|
69
83
|
private
|
|
70
84
|
|
|
71
85
|
attr_reader :redis
|
|
@@ -79,7 +93,7 @@ module Coverband
|
|
|
79
93
|
end
|
|
80
94
|
|
|
81
95
|
def type_base_key(local_type)
|
|
82
|
-
[
|
|
96
|
+
@keys[local_type]
|
|
83
97
|
end
|
|
84
98
|
|
|
85
99
|
def save_coverage(data, local_type = nil)
|
|
@@ -87,12 +101,6 @@ module Coverband
|
|
|
87
101
|
redis.set type_base_key(local_type), data.to_json
|
|
88
102
|
redis.expire(type_base_key(local_type), @ttl) if @ttl
|
|
89
103
|
end
|
|
90
|
-
|
|
91
|
-
def get_report(local_type = nil)
|
|
92
|
-
local_type ||= type
|
|
93
|
-
data = redis.get type_base_key(local_type)
|
|
94
|
-
data ? JSON.parse(data) : {}
|
|
95
|
-
end
|
|
96
104
|
end
|
|
97
105
|
end
|
|
98
106
|
end
|
data/lib/coverband/at_exit.rb
CHANGED
|
@@ -16,19 +16,10 @@ module Coverband
|
|
|
16
16
|
at_exit do
|
|
17
17
|
::Coverband::Background.stop
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
# TODO: This is is brittle and not a great solution to avoid deploy time
|
|
21
|
-
# actions polluting the 'runtime' metrics
|
|
22
|
-
#
|
|
23
|
-
# * should we skip /bin/rails webpacker:compile ?
|
|
24
|
-
# * Perhaps detect heroku deployment ENV var opposed to tasks?
|
|
25
|
-
#####
|
|
26
|
-
default_heroku_tasks = ['assets:clean', 'assets:precompile']
|
|
27
|
-
if defined?(Rake) && Rake.respond_to?(:application) && (Rake&.application&.top_level_tasks || []).any? { |task| default_heroku_tasks.include?(task) }
|
|
19
|
+
if !Coverband.configuration.report_on_exit
|
|
28
20
|
# skip reporting
|
|
29
21
|
else
|
|
30
|
-
Coverband.report_coverage
|
|
31
|
-
#Coverband.configuration.logger&.debug('Coverband: Reported coverage before exit')
|
|
22
|
+
Coverband.report_coverage
|
|
32
23
|
end
|
|
33
24
|
end
|
|
34
25
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require 'singleton'
|
|
3
4
|
require_relative 'delta'
|
|
4
5
|
|
|
@@ -13,10 +14,13 @@ module Coverband
|
|
|
13
14
|
class Coverage
|
|
14
15
|
include Singleton
|
|
15
16
|
|
|
17
|
+
def self.ruby_version_greater_than_or_equal_to?(version)
|
|
18
|
+
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new(version)
|
|
19
|
+
end
|
|
20
|
+
|
|
16
21
|
def reset_instance
|
|
17
22
|
@project_directory = File.expand_path(Coverband.configuration.root)
|
|
18
|
-
@ignore_patterns = Coverband.configuration.ignore
|
|
19
|
-
@reporting_frequency = Coverband.configuration.reporting_frequency
|
|
23
|
+
@ignore_patterns = Coverband.configuration.ignore
|
|
20
24
|
@store = Coverband.configuration.store
|
|
21
25
|
@verbose = Coverband.configuration.verbose
|
|
22
26
|
@logger = Coverband.configuration.logger
|
|
@@ -27,36 +31,36 @@ module Coverband
|
|
|
27
31
|
end
|
|
28
32
|
|
|
29
33
|
def runtime!
|
|
30
|
-
@store.type =
|
|
34
|
+
@store.type = Coverband::RUNTIME_TYPE
|
|
31
35
|
end
|
|
32
36
|
|
|
33
37
|
def eager_loading!
|
|
34
38
|
@store.type = Coverband::EAGER_TYPE
|
|
35
39
|
end
|
|
36
40
|
|
|
37
|
-
def
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
def eager_loading
|
|
42
|
+
old_coverage_type = @store.type
|
|
43
|
+
eager_loading!
|
|
44
|
+
yield
|
|
45
|
+
ensure
|
|
46
|
+
report_coverage
|
|
47
|
+
@store.type = old_coverage_type
|
|
48
|
+
end
|
|
40
49
|
|
|
41
|
-
|
|
42
|
-
|
|
50
|
+
def report_coverage
|
|
51
|
+
@semaphore.synchronize do
|
|
52
|
+
raise 'no Coverband store set' unless @store
|
|
43
53
|
|
|
44
|
-
|
|
45
|
-
# Hack to prevent processes and threads from reporting first Coverage hit
|
|
46
|
-
# when we are in runtime collection mode, which do not have a cache of previous
|
|
47
|
-
# coverage to remove the initial stdlib Coverage loading data
|
|
48
|
-
###
|
|
49
|
-
if ((original_previous_set.nil? && @store.type == Coverband::EAGER_TYPE) ||
|
|
50
|
-
(original_previous_set && @store.type != Coverband::EAGER_TYPE))
|
|
54
|
+
files_with_line_usage = filtered_files(Delta.results)
|
|
51
55
|
@store.save_report(files_with_line_usage)
|
|
52
56
|
end
|
|
53
|
-
rescue StandardError =>
|
|
57
|
+
rescue StandardError => e
|
|
54
58
|
if @verbose
|
|
55
|
-
@logger
|
|
56
|
-
@logger
|
|
57
|
-
@logger
|
|
59
|
+
@logger.error 'coverage failed to store'
|
|
60
|
+
@logger.error "error: #{e.inspect} #{e.message}"
|
|
61
|
+
@logger.error e.backtrace
|
|
58
62
|
end
|
|
59
|
-
raise
|
|
63
|
+
raise e if @test_env
|
|
60
64
|
end
|
|
61
65
|
|
|
62
66
|
protected
|
|
@@ -78,30 +82,22 @@ module Coverband
|
|
|
78
82
|
private
|
|
79
83
|
|
|
80
84
|
def filtered_files(new_results)
|
|
81
|
-
new_results.
|
|
82
|
-
|
|
83
|
-
end.select { |_file_name, coverage| coverage.any? { |value| value&.nonzero? } }
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def ready_to_report?
|
|
87
|
-
(rand * 100.0) >= (100.0 - @reporting_frequency)
|
|
85
|
+
new_results.select! { |file, coverage| track_file?(file) && coverage.any? { |value| value&.nonzero? } }
|
|
86
|
+
new_results
|
|
88
87
|
end
|
|
89
88
|
|
|
90
89
|
def initialize
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
@semaphore = Mutex.new
|
|
91
|
+
raise NotImplementedError, 'Coverage needs Ruby > 2.3.0' if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3.0')
|
|
92
|
+
|
|
94
93
|
require 'coverage'
|
|
95
|
-
if
|
|
94
|
+
if Coverage.ruby_version_greater_than_or_equal_to?('2.6.0')
|
|
95
|
+
::Coverage.start(oneshot_lines: Coverband.configuration.use_oneshot_lines_coverage) unless ::Coverage.running?
|
|
96
|
+
elsif Coverage.ruby_version_greater_than_or_equal_to?('2.5.0')
|
|
96
97
|
::Coverage.start unless ::Coverage.running?
|
|
97
98
|
else
|
|
98
99
|
::Coverage.start
|
|
99
100
|
end
|
|
100
|
-
if Coverband.configuration.safe_reload_files
|
|
101
|
-
Coverband.configuration.safe_reload_files.each do |safe_file|
|
|
102
|
-
load safe_file
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
101
|
reset_instance
|
|
106
102
|
end
|
|
107
103
|
end
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
module Coverband
|
|
3
4
|
module Collectors
|
|
4
5
|
class Delta
|
|
5
|
-
|
|
6
|
-
@@
|
|
6
|
+
@@previous_coverage = {}
|
|
7
|
+
@@stubs = {}
|
|
8
|
+
|
|
7
9
|
attr_reader :current_coverage
|
|
8
10
|
|
|
9
11
|
def initialize(current_coverage)
|
|
@@ -12,54 +14,58 @@ module Coverband
|
|
|
12
14
|
|
|
13
15
|
class RubyCoverage
|
|
14
16
|
def self.results
|
|
15
|
-
|
|
17
|
+
if Coverband.configuration.use_oneshot_lines_coverage
|
|
18
|
+
::Coverage.result(clear: true, stop: false)
|
|
19
|
+
else
|
|
20
|
+
::Coverage.peek_result
|
|
21
|
+
end
|
|
16
22
|
end
|
|
17
23
|
end
|
|
18
24
|
|
|
19
25
|
def self.results(process_coverage = RubyCoverage)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
new(process_coverage.results).results
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def self.previous_results
|
|
27
|
-
@@previous_coverage
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def self.set_default_results
|
|
31
|
-
@@previous_coverage ||= {}
|
|
26
|
+
coverage_results = process_coverage.results
|
|
27
|
+
new(coverage_results).results
|
|
32
28
|
end
|
|
33
29
|
|
|
34
30
|
def results
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
if Coverband.configuration.use_oneshot_lines_coverage
|
|
32
|
+
transform_oneshot_lines_results(current_coverage)
|
|
33
|
+
else
|
|
34
|
+
new_results = generate
|
|
35
|
+
@@previous_coverage = current_coverage unless Coverband.configuration.simulate_oneshot_lines_coverage
|
|
36
|
+
new_results
|
|
37
|
+
end
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def self.reset
|
|
41
|
-
@@previous_coverage =
|
|
41
|
+
@@previous_coverage = {}
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
private
|
|
45
45
|
|
|
46
46
|
def generate
|
|
47
47
|
current_coverage.each_with_object({}) do |(file, line_counts), new_results|
|
|
48
|
-
if @@previous_coverage[file]
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
new_results[file] = if @@previous_coverage && @@previous_coverage[file]
|
|
49
|
+
array_diff(line_counts, @@previous_coverage[file])
|
|
50
|
+
else
|
|
51
|
+
line_counts
|
|
52
|
+
end
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def array_diff(latest, original)
|
|
57
57
|
latest.map.with_index do |v, i|
|
|
58
|
-
if
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
[0, v - original[i]].max if v && original[i]
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def transform_oneshot_lines_results(results)
|
|
63
|
+
results.each_with_object({}) do |(file, coverage), new_results|
|
|
64
|
+
@@stubs[file] ||= ::Coverage.line_stub(file)
|
|
65
|
+
transformed_line_counts = coverage[:oneshot_lines].each_with_object(@@stubs[file].dup) do |line_number, line_counts|
|
|
66
|
+
line_counts[line_number - 1] = 1
|
|
62
67
|
end
|
|
68
|
+
new_results[file] = transformed_line_counts
|
|
63
69
|
end
|
|
64
70
|
end
|
|
65
71
|
end
|
|
@@ -3,15 +3,32 @@
|
|
|
3
3
|
module Coverband
|
|
4
4
|
class Configuration
|
|
5
5
|
attr_accessor :root_paths, :root,
|
|
6
|
-
:
|
|
7
|
-
:reporter, :
|
|
8
|
-
:
|
|
9
|
-
:safe_reload_files, :background_reporting_enabled,
|
|
6
|
+
:additional_files, :verbose,
|
|
7
|
+
:reporter, :redis_namespace, :redis_ttl,
|
|
8
|
+
:background_reporting_enabled,
|
|
10
9
|
:background_reporting_sleep_seconds, :test_env,
|
|
11
|
-
:web_enable_clear, :gem_details, :web_debug
|
|
10
|
+
:web_enable_clear, :gem_details, :web_debug, :report_on_exit,
|
|
11
|
+
:simulate_oneshot_lines_coverage
|
|
12
12
|
|
|
13
|
-
attr_writer :logger, :s3_region, :s3_bucket, :s3_access_key_id, :s3_secret_access_key
|
|
14
|
-
attr_reader :track_gems
|
|
13
|
+
attr_writer :logger, :s3_region, :s3_bucket, :s3_access_key_id, :s3_secret_access_key, :password
|
|
14
|
+
attr_reader :track_gems, :ignore, :use_oneshot_lines_coverage
|
|
15
|
+
|
|
16
|
+
#####
|
|
17
|
+
# TODO: This is is brittle and not a great solution to avoid deploy time
|
|
18
|
+
# actions polluting the 'runtime' metrics
|
|
19
|
+
#
|
|
20
|
+
# * should we skip /bin/rails webpacker:compile ?
|
|
21
|
+
# * Perhaps detect heroku deployment ENV var opposed to tasks?
|
|
22
|
+
#####
|
|
23
|
+
IGNORE_TASKS = ['coverband:clear',
|
|
24
|
+
'coverband:coverage',
|
|
25
|
+
'coverband:coverage_server',
|
|
26
|
+
'coverband:migrate']
|
|
27
|
+
|
|
28
|
+
# Heroku when building assets runs code from a dynamic directory
|
|
29
|
+
# /tmp was added to avoid coverage from /tmp/build directories during
|
|
30
|
+
# heroku asset compilation
|
|
31
|
+
IGNORE_DEFAULTS = %w[vendor .erb$ .slim$ /tmp internal:prelude schema.rb]
|
|
15
32
|
|
|
16
33
|
def initialize
|
|
17
34
|
reset
|
|
@@ -20,12 +37,8 @@ module Coverband
|
|
|
20
37
|
def reset
|
|
21
38
|
@root = Dir.pwd
|
|
22
39
|
@root_paths = []
|
|
23
|
-
|
|
24
|
-
# /tmp was added to avoid coverage from /tmp/build directories during
|
|
25
|
-
# heroku asset compilation
|
|
26
|
-
@ignore = %w[vendor .erb$ .slim$ /tmp]
|
|
40
|
+
@ignore = IGNORE_DEFAULTS.dup
|
|
27
41
|
@additional_files = []
|
|
28
|
-
@reporting_frequency = 0.0
|
|
29
42
|
@verbose = false
|
|
30
43
|
@reporter = 'scov'
|
|
31
44
|
@logger = nil
|
|
@@ -38,6 +51,13 @@ module Coverband
|
|
|
38
51
|
@gem_details = false
|
|
39
52
|
@groups = {}
|
|
40
53
|
@web_debug = false
|
|
54
|
+
@report_on_exit = true
|
|
55
|
+
@use_oneshot_lines_coverage = ENV['ONESHOT'] || false
|
|
56
|
+
@simulate_oneshot_lines_coverage = ENV['SIMULATE_ONESHOT'] || false
|
|
57
|
+
@current_root = nil
|
|
58
|
+
@all_root_paths = nil
|
|
59
|
+
@all_root_patterns = nil
|
|
60
|
+
@password = nil
|
|
41
61
|
|
|
42
62
|
# TODO: should we push these to adapter configs
|
|
43
63
|
@s3_region = nil
|
|
@@ -45,17 +65,21 @@ module Coverband
|
|
|
45
65
|
@s3_access_key_id = nil
|
|
46
66
|
@s3_secret_access_key = nil
|
|
47
67
|
@redis_namespace = nil
|
|
48
|
-
@redis_ttl =
|
|
68
|
+
@redis_ttl = 2_592_000 # in seconds. Default is 30 days.
|
|
49
69
|
end
|
|
50
70
|
|
|
51
71
|
def logger
|
|
52
|
-
@logger ||= if defined?(Rails.logger)
|
|
72
|
+
@logger ||= if defined?(Rails.logger) && Rails.logger
|
|
53
73
|
Rails.logger
|
|
54
74
|
else
|
|
55
75
|
Logger.new(STDOUT)
|
|
56
76
|
end
|
|
57
77
|
end
|
|
58
78
|
|
|
79
|
+
def password
|
|
80
|
+
@password || ENV['COVERBAND_PASSWORD']
|
|
81
|
+
end
|
|
82
|
+
|
|
59
83
|
def s3_bucket
|
|
60
84
|
@s3_bucket || ENV['AWS_BUCKET']
|
|
61
85
|
end
|
|
@@ -77,29 +101,33 @@ module Coverband
|
|
|
77
101
|
end
|
|
78
102
|
|
|
79
103
|
def store=(store)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
104
|
+
raise 'Pass in an instance of Coverband::Adapters' unless store.is_a?(Coverband::Adapters::Base)
|
|
105
|
+
|
|
106
|
+
@store = store
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
###
|
|
110
|
+
# Don't allow the ignore to override things like gem tracking
|
|
111
|
+
###
|
|
112
|
+
def ignore=(ignored_array)
|
|
113
|
+
@ignore = (@ignore + ignored_array).uniq
|
|
85
114
|
end
|
|
86
115
|
|
|
87
116
|
def track_gems=(value)
|
|
88
117
|
@track_gems = value
|
|
89
118
|
return unless @track_gems
|
|
119
|
+
|
|
90
120
|
# by default we ignore vendor where many deployments put gems
|
|
91
121
|
# we will remove this default if track_gems is set
|
|
92
122
|
@ignore.delete('vendor')
|
|
93
123
|
# while we want to allow vendored gems we don't want to track vendored ruby STDLIB
|
|
94
|
-
@ignore << 'vendor/ruby-*'
|
|
124
|
+
@ignore << 'vendor/ruby-*' unless @ignore.include?('vendor/ruby-*')
|
|
95
125
|
add_group('App', root)
|
|
96
126
|
# TODO: rework support for multiple gem paths
|
|
97
|
-
#
|
|
98
|
-
#
|
|
99
|
-
#
|
|
100
|
-
|
|
101
|
-
# end
|
|
102
|
-
add_group('Gems', gem_paths.first)
|
|
127
|
+
# this works but seems hacky and error prone
|
|
128
|
+
# basically since it is converted to a regex we join all the paths
|
|
129
|
+
# with a regex 'OR' using '|'
|
|
130
|
+
add_group('Gems', gem_paths.join('|'))
|
|
103
131
|
end
|
|
104
132
|
|
|
105
133
|
#
|
|
@@ -125,17 +153,23 @@ module Coverband
|
|
|
125
153
|
end
|
|
126
154
|
|
|
127
155
|
def current_root
|
|
128
|
-
File.expand_path(Coverband.configuration.root)
|
|
156
|
+
@current_root ||= File.expand_path(Coverband.configuration.root).freeze
|
|
129
157
|
end
|
|
130
158
|
|
|
131
159
|
def all_root_paths
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
160
|
+
return @all_root_paths if @all_root_paths
|
|
161
|
+
|
|
162
|
+
@all_root_paths = Coverband.configuration.root_paths.dup
|
|
163
|
+
@all_root_paths += Coverband.configuration.gem_paths.dup if Coverband.configuration.track_gems
|
|
164
|
+
@all_root_paths << "#{Coverband.configuration.current_root}/"
|
|
165
|
+
@all_root_paths
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def all_root_patterns
|
|
169
|
+
@all_root_patterns ||= all_root_paths.map { |path| /^#{path}/ }.freeze
|
|
136
170
|
end
|
|
137
171
|
|
|
138
|
-
SKIPPED_SETTINGS = %w
|
|
172
|
+
SKIPPED_SETTINGS = %w[@s3_secret_access_key @store]
|
|
139
173
|
def to_h
|
|
140
174
|
instance_variables
|
|
141
175
|
.each_with_object('gem_paths': gem_paths) do |var, hash|
|
|
@@ -143,6 +177,16 @@ module Coverband
|
|
|
143
177
|
end
|
|
144
178
|
end
|
|
145
179
|
|
|
180
|
+
def use_oneshot_lines_coverage=(value)
|
|
181
|
+
raise(Exception, 'One shot line coverage is only available in ruby >= 2.6') unless one_shot_coverage_implemented_in_ruby_version? || !value
|
|
182
|
+
|
|
183
|
+
@use_oneshot_lines_coverage = value
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def one_shot_coverage_implemented_in_ruby_version?
|
|
187
|
+
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.6.0')
|
|
188
|
+
end
|
|
189
|
+
|
|
146
190
|
private
|
|
147
191
|
|
|
148
192
|
def redis_url
|
|
@@ -7,6 +7,7 @@ module Coverband
|
|
|
7
7
|
|
|
8
8
|
def self.stop
|
|
9
9
|
return unless @thread
|
|
10
|
+
|
|
10
11
|
@semaphore.synchronize do
|
|
11
12
|
if @thread
|
|
12
13
|
@thread.exit
|
|
@@ -16,7 +17,7 @@ module Coverband
|
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
def self.running?
|
|
19
|
-
@thread
|
|
20
|
+
@thread&.alive?
|
|
20
21
|
end
|
|
21
22
|
|
|
22
23
|
def self.start
|
|
@@ -25,12 +26,15 @@ module Coverband
|
|
|
25
26
|
logger = Coverband.configuration.logger
|
|
26
27
|
@semaphore.synchronize do
|
|
27
28
|
return if running?
|
|
28
|
-
|
|
29
|
+
|
|
30
|
+
logger.debug('Coverband: Starting background reporting')
|
|
29
31
|
sleep_seconds = Coverband.configuration.background_reporting_sleep_seconds
|
|
30
32
|
@thread = Thread.new do
|
|
31
33
|
loop do
|
|
32
|
-
Coverband.report_coverage
|
|
33
|
-
|
|
34
|
+
Coverband.report_coverage
|
|
35
|
+
if Coverband.configuration.verbose
|
|
36
|
+
logger.debug("Coverband: background reporting coverage (#{Coverband.configuration.store.type}). Sleeping #{sleep_seconds}s")
|
|
37
|
+
end
|
|
34
38
|
sleep(sleep_seconds)
|
|
35
39
|
end
|
|
36
40
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Coverband
|
|
4
|
-
class
|
|
4
|
+
class BackgroundMiddleware
|
|
5
5
|
def initialize(app)
|
|
6
6
|
@app = app
|
|
7
7
|
end
|
|
@@ -10,11 +10,7 @@ module Coverband
|
|
|
10
10
|
@app.call(env)
|
|
11
11
|
ensure
|
|
12
12
|
AtExit.register
|
|
13
|
-
if Coverband.configuration.background_reporting_enabled
|
|
14
|
-
Background.start
|
|
15
|
-
else
|
|
16
|
-
Collectors::Coverage.instance.report_coverage
|
|
17
|
-
end
|
|
13
|
+
Background.start if Coverband.configuration.background_reporting_enabled
|
|
18
14
|
end
|
|
19
15
|
end
|
|
20
16
|
end
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
Resque.after_fork do |
|
|
3
|
+
Resque.after_fork do |_job|
|
|
4
4
|
Coverband.start
|
|
5
5
|
Coverband.runtime_coverage!
|
|
6
|
-
# no reason to miss coverage on a first resque job
|
|
7
|
-
Coverband::Collectors::Delta.set_default_results
|
|
8
6
|
end
|
|
9
7
|
|
|
10
8
|
Resque.before_first_fork do
|
|
11
9
|
Coverband.eager_loading_coverage!
|
|
12
10
|
Coverband.configuration.background_reporting_enabled = false
|
|
13
11
|
Coverband::Background.stop
|
|
14
|
-
Coverband
|
|
12
|
+
Coverband.report_coverage
|
|
15
13
|
end
|
|
16
14
|
|
|
17
15
|
module Coverband
|
|
@@ -19,7 +17,7 @@ module Coverband
|
|
|
19
17
|
def perform
|
|
20
18
|
super
|
|
21
19
|
ensure
|
|
22
|
-
Coverband.report_coverage
|
|
20
|
+
Coverband.report_coverage
|
|
23
21
|
end
|
|
24
22
|
end
|
|
25
23
|
end
|