coverband 6.0.2 → 6.0.3.rc.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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +10 -0
  3. data/.github/workflows/main.yml +2 -3
  4. data/.standard.yml +1 -1
  5. data/Gemfile +1 -1
  6. data/LICENSE +1 -1
  7. data/README.md +3 -2
  8. data/Rakefile +1 -1
  9. data/changes.md +1 -1
  10. data/coverband.gemspec +3 -3
  11. data/lib/coverband/adapters/base.rb +10 -10
  12. data/lib/coverband/adapters/file_store.rb +1 -1
  13. data/lib/coverband/adapters/hash_redis_store.rb +69 -15
  14. data/lib/coverband/adapters/null_store.rb +1 -1
  15. data/lib/coverband/adapters/stdout_store.rb +1 -1
  16. data/lib/coverband/adapters/web_service_store.rb +5 -7
  17. data/lib/coverband/collectors/route_tracker.rb +1 -1
  18. data/lib/coverband/collectors/translation_tracker.rb +2 -2
  19. data/lib/coverband/collectors/view_tracker.rb +1 -1
  20. data/lib/coverband/configuration.rb +5 -5
  21. data/lib/coverband/integrations/rack_server_check.rb +1 -3
  22. data/lib/coverband/reporters/base.rb +7 -7
  23. data/lib/coverband/reporters/html_report.rb +12 -4
  24. data/lib/coverband/reporters/json_report.rb +42 -4
  25. data/lib/coverband/reporters/web.rb +16 -2
  26. data/lib/coverband/reporters/web_pager.rb +28 -0
  27. data/lib/coverband/utils/absolute_file_converter.rb +19 -19
  28. data/lib/coverband/utils/file_hasher.rb +3 -3
  29. data/lib/coverband/utils/html_formatter.rb +4 -4
  30. data/lib/coverband/utils/method_definition_scanner.rb +1 -1
  31. data/lib/coverband/utils/railtie.rb +4 -6
  32. data/lib/coverband/utils/relative_file_converter.rb +7 -7
  33. data/lib/coverband/utils/results.rb +1 -5
  34. data/lib/coverband/utils/source_file.rb +2 -2
  35. data/lib/coverband/utils/tasks.rb +1 -1
  36. data/lib/coverband/version.rb +1 -1
  37. data/lib/coverband.rb +19 -3
  38. data/public/application.js +35 -0
  39. data/public/dependencies.js +1 -1
  40. data/roadmap.md +1 -1
  41. data/test/benchmarks/benchmark.rake +5 -5
  42. data/test/coverband/adapters/file_store_test.rb +1 -1
  43. data/test/coverband/collectors/coverage_test.rb +1 -1
  44. data/test/coverband/reporters/json_test.rb +1 -1
  45. data/test/coverband/utils/source_file_test.rb +11 -11
  46. data/test/fixtures/casting_invitor.rb +1 -1
  47. data/test/fixtures/sample.rb +2 -2
  48. data/test/fixtures/skipped_and_executed.rb +1 -1
  49. data/test/forked/rails_rake_full_stack_test.rb +1 -1
  50. data/test/test_helper.rb +3 -5
  51. data/test/unique_files.rb +1 -1
  52. data/views/file_list.erb +38 -32
  53. data/views/layout.erb +3 -3
  54. metadata +12 -136
  55. data/LICENSE.txt +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e834afa9139c4fc6b0e17a151476a7e9769f082ff435d93a58f3d1a8c44ff1a
4
- data.tar.gz: 935efdfe633f5ccafc3d43d4d5237558b8032545526f0a7320b11ba64a04c7c1
3
+ metadata.gz: f25f2799e62201b31472588ed6ee3d00697b6ab8eba5beb04c3a76cb7e52d962
4
+ data.tar.gz: 599a0d1a4ef26b9b353d4ae341db2287f15b5119b9d9d3ed3d2b0e796c6e1fae
5
5
  SHA512:
6
- metadata.gz: de37c02bb694b58b25dad7b31f8fd9bbe09f0c963d779f5094e1db8db6e971b4df4501722657e00a7772a3e0a1622d9538e75b8e4625996ce4e60e3faadf27a3
7
- data.tar.gz: 8ce7d73882bbc4e501dedde77f58358165e16143e59794d779e7568ec2b15bbbe0dc5f286f995808283c1c8616b7b03704137ec22a28392cff0df95c0fc97d35
6
+ metadata.gz: b58f4486c028a9ed4f2e3444ed164a43b620b4cc213f91e9b7aef93c2ef1c394840aade62466b216f29ade57851314989e0ed3f3bca2a7f692deddd106efe7a3
7
+ data.tar.gz: 6569ffaeb15feb24b4eb40d5e0403bcf4fcc6fc381a7fd30e64a9e6a7fee06498e05ffe2832c7a99545c51a8b25a12cf6264daf672ef82485ccf10e03a3895a3
@@ -0,0 +1,10 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "bundler"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ - package-ecosystem: "github-actions"
8
+ directory: "/"
9
+ schedule:
10
+ interval: "weekly"
@@ -20,13 +20,12 @@ jobs:
20
20
  # truffleruby-head,
21
21
  # removing jruby again to flaky
22
22
  gemfile: [ Gemfile.rails6.0, Gemfile.rails6.1, Gemfile.rails7.0, Gemfile.rails7.1 ]
23
- # ruby: [2.3, 2.4, 2.5, 2.6, 2.7, "3.0", "3.1", jruby]
24
23
  # need to add support for multiple gemfiles
25
- ruby: ["2.7", "3.0", "3.1", "3.2"]
24
+ ruby: ["2.7", "3.0", "3.1", "3.2", "3.3"]
26
25
  redis-version: [4, 5, 6, 7]
27
26
  runs-on: ${{ matrix.os }}-latest
28
27
  steps:
29
- - uses: actions/checkout@v3
28
+ - uses: actions/checkout@v4
30
29
  - uses: supercharge/redis-github-action@1.2.0
31
30
  with:
32
31
  redis-version: ${{ matrix.redis-version }}
data/.standard.yml CHANGED
@@ -1,4 +1,4 @@
1
- ruby_version: 2.3
1
+ ruby_version: 2.7
2
2
  fix: false # default: false
3
3
  parallel: true # default: false
4
4
  format: progress # default: Standard::Formatter
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ source "https://rubygems.org"
4
4
 
5
5
  # Specify your gem's dependencies in coverband.gemspec
6
6
  gemspec
7
- gem "rails", "~>6"
7
+ gem "rails", "~>7"
8
8
  gem "haml"
9
9
  gem "slim"
10
10
  gem "webrick"
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2010-2018 Dan Mayer
3
+ Copyright (c) 2010 Dan Mayer
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
data/README.md CHANGED
@@ -79,7 +79,7 @@ run ActionController::Dispatcher.new
79
79
 
80
80
  ![image](https://raw.github.com/danmayer/coverband/master/docs/coverband_web_ui.png)
81
81
 
82
- > The web index is available on the [Coverband Demo site](https://coverband-demo.herokuapp.com/coverage?#_Coverage).
82
+ > You can check it out locally by running the [Coverband Demo App](https://github.com/danmayer/coverband_rails_example).
83
83
 
84
84
  - View overall coverage information
85
85
 
@@ -438,6 +438,7 @@ If you submit a change please make sure the tests and benchmarks are passing.
438
438
  - **Coverband, [Elastic APM](https://github.com/elastic/apm-agent-ruby) and resque**
439
439
  - In an environment that uses the Elastic APM ruby agent, resque jobs will fail with `Transactions may not be nested. Already inside #<ElasticAPM::Transaction>` if the `elastic-apm` gem is loaded _before_ the `coverband` gem
440
440
  - Put `coverage` ahead of `elastic-apm` in your Gemfile
441
+ - **Bootsnap**, The methods used by [bootsnap do not support having coverage enabled](https://github.com/Shopify/bootsnap/blob/main/lib/bootsnap/compile_cache/iseq.rb#L87), so you can either have Coverband or bootsnap, but not both.
441
442
 
442
443
  ### Debugging Redis Store
443
444
 
@@ -462,4 +463,4 @@ The Coverband logo was created by [Dave Woodall](http://davewoodall.com). Thanks
462
463
  # License
463
464
 
464
465
  This is a MIT License project...
465
- See the file license.txt for copying permission.
466
+ See the file [LICENSE](LICENSE) for copying permission.
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ RuboCop::RakeTask.new
8
8
 
9
9
  task default: %i[test]
10
10
 
11
- task 'test:all': %i[rubocop test forked_tests benchmarks:memory benchmarks]
11
+ task "test:all": %i[rubocop test forked_tests benchmarks:memory benchmarks]
12
12
 
13
13
  task :test
14
14
  require "rake/testtask"
data/changes.md CHANGED
@@ -135,7 +135,7 @@ __NOTE: the current RCs include below, but this might turn into coverband 6.0__
135
135
  - added support to download coverage and view data in JSON format
136
136
  - documentation about working with environment variables
137
137
  - add cache wiggle to avoid Redis CPU spikes (cache stampede on Redis server)
138
- - make the nocov consistant on the data download and html view
138
+ - make the nocov consistent on the data download and html view
139
139
  - small performance improvements
140
140
 
141
141
  ### Coverband 4.2.3
data/coverband.gemspec CHANGED
@@ -18,10 +18,9 @@ Gem::Specification.new do |spec|
18
18
 
19
19
  spec.files = `git ls-files`.split("\n").reject { |f| f.start_with?("docs") }
20
20
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
21
  spec.require_paths = %w[lib]
23
22
 
24
- spec.required_ruby_version = ">= 2.3"
23
+ spec.required_ruby_version = ">= 2.7"
25
24
 
26
25
  spec.metadata = {
27
26
  "homepage_uri" => "https://github.com/danmayer/coverband",
@@ -40,11 +39,12 @@ Gem::Specification.new do |spec|
40
39
  spec.add_development_dependency "minitest-fork_executor"
41
40
  spec.add_development_dependency "minitest-stub-const"
42
41
  spec.add_development_dependency "mocha", "~> 1.7.0"
42
+ # spec.add_development_dependency "spy"
43
43
  spec.add_development_dependency "rack"
44
44
  spec.add_development_dependency "rack-test"
45
45
  spec.add_development_dependency "rake"
46
46
  spec.add_development_dependency "resque"
47
- spec.add_development_dependency "standard", "= 0.2.5"
47
+ spec.add_development_dependency "standard", "~> 1.34.0"
48
48
  spec.add_development_dependency "standardrb"
49
49
 
50
50
  spec.add_development_dependency "coveralls"
@@ -35,7 +35,7 @@ module Coverband
35
35
  raise ABSTRACT_KEY
36
36
  end
37
37
 
38
- def coverage(_local_type = nil)
38
+ def coverage(_local_type = nil, opts = {})
39
39
  raise ABSTRACT_KEY
40
40
  end
41
41
 
@@ -51,9 +51,9 @@ module Coverband
51
51
  raise "abstract"
52
52
  end
53
53
 
54
- def get_coverage_report
54
+ def get_coverage_report(options = {})
55
55
  coverage_cache = {}
56
- data = Coverband.configuration.store.split_coverage(Coverband::TYPES, coverage_cache)
56
+ data = Coverband.configuration.store.split_coverage(Coverband::TYPES, coverage_cache, options)
57
57
  data.merge(Coverband::MERGED_TYPE => Coverband.configuration.store.merged_coverage(Coverband::TYPES, coverage_cache))
58
58
  end
59
59
 
@@ -67,12 +67,12 @@ module Coverband
67
67
 
68
68
  protected
69
69
 
70
- def split_coverage(types, coverage_cache)
70
+ def split_coverage(types, coverage_cache, options = {})
71
71
  types.reduce({}) do |data, type|
72
72
  if type == Coverband::RUNTIME_TYPE && Coverband.configuration.simulate_oneshot_lines_coverage
73
73
  data.update(type => coverage_cache[type] ||= simulated_runtime_coverage)
74
74
  else
75
- data.update(type => coverage_cache[type] ||= coverage(type))
75
+ data.update(type => coverage_cache[type] ||= coverage(type, options))
76
76
  end
77
77
  end
78
78
  end
@@ -100,7 +100,7 @@ module Coverband
100
100
  def expand_report(report)
101
101
  expanded = {}
102
102
  report_time = Time.now.to_i
103
- updated_time = type == Coverband::EAGER_TYPE ? nil : report_time
103
+ updated_time = (type == Coverband::EAGER_TYPE) ? nil : report_time
104
104
  report.each_pair do |key, line_data|
105
105
  extended_data = {
106
106
  FIRST_UPDATED_KEY => report_time,
@@ -115,7 +115,7 @@ module Coverband
115
115
 
116
116
  def merge_reports(new_report, old_report, options = {})
117
117
  # transparently update from RUNTIME_TYPE = nil to RUNTIME_TYPE = :runtime
118
- # transparent update for format coveband_3_2
118
+ # transparent update for format coverband_3_2
119
119
  old_report = coverage(nil, override_type: nil) if old_report.nil? && type == Coverband::RUNTIME_TYPE
120
120
  new_report = expand_report(new_report) unless options[:skip_expansion]
121
121
  keys = (new_report.keys + old_report.keys).uniq
@@ -145,11 +145,11 @@ module Coverband
145
145
  # TODO: This should only be 2 cases get our dup / not dups aligned
146
146
  def array_add(latest, original)
147
147
  if Coverband.configuration.use_oneshot_lines_coverage
148
- latest.map!.with_index { |v, i| (v + original[i] >= 1 ? 1 : 0) if v && original[i] }
148
+ latest.map!.with_index { |v, i| ((v + original[i] >= 1) ? 1 : 0) if v && original[i] }
149
149
  elsif Coverband.configuration.simulate_oneshot_lines_coverage
150
- latest.map.with_index { |v, i| (v + original[i] >= 1 ? 1 : 0) if v && original[i] }
150
+ latest.map.with_index { |v, i| ((v + original[i] >= 1) ? 1 : 0) if v && original[i] }
151
151
  else
152
- latest.map.with_index { |v, i| v && original[i] ? v + original[i] : nil }
152
+ latest.map.with_index { |v, i| (v && original[i]) ? v + original[i] : nil }
153
153
  end
154
154
  end
155
155
  end
@@ -52,7 +52,7 @@ module Coverband
52
52
  raise NotImplementedError, "FileStore doesn't support migrations"
53
53
  end
54
54
 
55
- def coverage(_local_type = nil)
55
+ def coverage(_local_type = nil, opts = {})
56
56
  if merge_mode
57
57
  data = {}
58
58
  Dir[path.sub(/\.\d+/, ".*")].each do |path|
@@ -34,12 +34,10 @@ module Coverband
34
34
  else
35
35
  if lock!(local_type)
36
36
  Thread.new do
37
- begin
38
- result = yield(deferred_time)
39
- set(local_type, JSON.generate(result))
40
- ensure
41
- unlock!(local_type)
42
- end
37
+ result = yield(deferred_time)
38
+ set(local_type, JSON.generate(result))
39
+ ensure
40
+ unlock!(local_type)
43
41
  end
44
42
  end
45
43
  JSON.parse(cached_result)
@@ -53,12 +51,22 @@ module Coverband
53
51
  end
54
52
  end
55
53
 
54
+ protected
55
+
56
+ def split_coverage(types, coverage_cache, options = {})
57
+ if types.is_a?(Array)
58
+ coverage_for_types(types, options)
59
+ else
60
+ super
61
+ end
62
+ end
63
+
56
64
  private
57
65
 
58
66
  # sleep in between to avoid holding other redis commands..
59
67
  # with a small random offset so runtime and eager types can be processed "at the same time"
60
68
  def deferred_time
61
- rand(3.0..4.0)
69
+ rand(2.0..3.0)
62
70
  end
63
71
 
64
72
  def del(local_type)
@@ -109,7 +117,7 @@ module Coverband
109
117
  @relative_file_converter = opts[:relative_file_converter] || Utils::RelativeFileConverter
110
118
 
111
119
  @get_coverage_cache = if opts[:get_coverage_cache]
112
- key_prefix = [REDIS_STORAGE_FORMAT_VERSION, @redis_namespace].compact.join(".")
120
+ key_prefix = [REDIS_STORAGE_FORMAT_VERSION, @redis_namespace, "v2"].compact.join(".")
113
121
  GetCoverageRedisCacheStore.new(redis, key_prefix)
114
122
  else
115
123
  GetCoverageNullCacheStore
@@ -130,6 +138,7 @@ module Coverband
130
138
  file_keys = files_set
131
139
  @redis.del(*file_keys) if file_keys.any?
132
140
  @redis.del(files_key)
141
+ @redis.del(files_key(type))
133
142
  @get_coverage_cache.clear!(type)
134
143
  end
135
144
  self.type = old_type
@@ -147,7 +156,7 @@ module Coverband
147
156
 
148
157
  def save_report(report)
149
158
  report_time = Time.now.to_i
150
- updated_time = type == Coverband::EAGER_TYPE ? nil : report_time
159
+ updated_time = (type == Coverband::EAGER_TYPE) ? nil : report_time
151
160
  keys = []
152
161
  report.each_slice(@save_report_batch_size) do |slice|
153
162
  files_data = slice.map { |(file, data)|
@@ -173,12 +182,19 @@ module Coverband
173
182
  @redis.sadd(files_key, keys) if keys.any?
174
183
  end
175
184
 
176
- def coverage(local_type = nil)
185
+ # TODO: refactor this and the method below and consider removing all the cached results stuff
186
+ def coverage(local_type = nil, opts = {})
187
+ page_size = opts[:page_size] || 250
177
188
  cached_results = @get_coverage_cache.fetch(local_type || type) do |sleep_time|
178
- files_set = files_set(local_type)
179
-
189
+ files_set = if opts[:page]
190
+ files_set(local_type).each_slice(page_size).to_a[opts[:page] - 1] || {}
191
+ elsif opts[:filename]
192
+ files_set(local_type).select { |filepath| filepath == opts[:filename] } || {}
193
+ else
194
+ files_set(local_type)
195
+ end
180
196
  # use batches with a sleep in between to avoid overloading redis
181
- files_set.each_slice(250).flat_map do |key_batch|
197
+ files_set.each_slice(page_size).flat_map do |key_batch|
182
198
  sleep sleep_time
183
199
  @redis.pipelined do |pipeline|
184
200
  key_batch.each do |key|
@@ -193,6 +209,44 @@ module Coverband
193
209
  end
194
210
  end
195
211
 
212
+ # NOTE: when using paging we need to ensure we have the same set of files per page in runtime and eager
213
+ def coverage_for_types(types, opts = {})
214
+ page_size = opts[:page_size] || 250
215
+
216
+ local_type = Coverband::RUNTIME_TYPE
217
+ hash_data = {}
218
+
219
+ runtime_file_set = if opts[:page]
220
+ files_set(local_type).each_slice(page_size).to_a[opts[:page] - 1] || {}
221
+ elsif opts[:filename]
222
+ files_set(local_type).select { |filepath| filepath == opts[:filename] } || {}
223
+ else
224
+ files_set(local_type)
225
+ end
226
+ hash_data[Coverband::RUNTIME_TYPE] = runtime_file_set.each_slice(page_size).flat_map do |key_batch|
227
+ @redis.pipelined do |pipeline|
228
+ key_batch.each do |key|
229
+ pipeline.hgetall(key)
230
+ end
231
+ end
232
+ end
233
+
234
+ matched_file_set = files_set(Coverband::EAGER_TYPE)
235
+ .select { |filepath| runtime_file_set.include?(filepath) } || {}
236
+ hash_data[Coverband::EAGER_TYPE] = matched_file_set.each_slice(page_size).flat_map do |key_batch|
237
+ @redis.pipelined do |pipeline|
238
+ key_batch.each do |key|
239
+ pipeline.hgetall(key)
240
+ end
241
+ end
242
+ end
243
+ hash_data
244
+ end
245
+
246
+ def file_count(local_type = nil)
247
+ files_set(local_type).count { |filename| !Coverband.configuration.ignore.any? { |i| filename.match(i) } }
248
+ end
249
+
196
250
  def raw_store
197
251
  @redis
198
252
  end
@@ -215,7 +269,7 @@ module Coverband
215
269
 
216
270
  data = coverage_data_from_redis(data_from_redis)
217
271
  hash[file] = data_from_redis.select { |meta_data_key, _value| META_DATA_KEYS.include?(meta_data_key) }.merge!("data" => data)
218
- hash[file][LAST_UPDATED_KEY] = hash[file][LAST_UPDATED_KEY].nil? || hash[file][LAST_UPDATED_KEY] == "" ? nil : hash[file][LAST_UPDATED_KEY].to_i
272
+ hash[file][LAST_UPDATED_KEY] = (hash[file][LAST_UPDATED_KEY].nil? || hash[file][LAST_UPDATED_KEY] == "") ? nil : hash[file][LAST_UPDATED_KEY].to_i
219
273
  hash[file].merge!(LAST_UPDATED_KEY => hash[file][LAST_UPDATED_KEY], FIRST_UPDATED_KEY => hash[file][FIRST_UPDATED_KEY].to_i)
220
274
  end
221
275
 
@@ -223,7 +277,7 @@ module Coverband
223
277
  max = data_from_redis[FILE_LENGTH_KEY].to_i - 1
224
278
  Array.new(max + 1) do |index|
225
279
  line_coverage = data_from_redis[index.to_s]
226
- line_coverage.nil? ? nil : line_coverage.to_i
280
+ line_coverage&.to_i
227
281
  end
228
282
  end
229
283
 
@@ -26,7 +26,7 @@ module Coverband
26
26
  raise NotImplementedError, "NullStore doesn't support migrations"
27
27
  end
28
28
 
29
- def coverage(_local_type = nil)
29
+ def coverage(_local_type = nil, opts = {})
30
30
  {}
31
31
  end
32
32
 
@@ -25,7 +25,7 @@ module Coverband
25
25
  raise NotImplementedError, "StdoutStore doesn't support migrations"
26
26
  end
27
27
 
28
- def coverage(_local_type = nil)
28
+ def coverage(_local_type = nil, opts = {})
29
29
  {}
30
30
  end
31
31
 
@@ -42,7 +42,7 @@ module Coverband
42
42
 
43
43
  ###
44
44
  # Fetch coverband coverage via the API
45
- # This would allow one to expore from the service and move back to the open source
45
+ # This would allow one to explore from the service and move back to the open source
46
46
  # without having to reset coverage
47
47
  ###
48
48
  def coverage(local_type = nil, opts = {})
@@ -98,12 +98,10 @@ module Coverband
98
98
  def retry_failed_reports
99
99
  retries = []
100
100
  @failed_coverage_reports.any? do
101
- begin
102
- report_body = @failed_coverage_reports.pop
103
- send_report_body(report_body)
104
- rescue
105
- retries << report_body
106
- end
101
+ report_body = @failed_coverage_reports.pop
102
+ send_report_body(report_body)
103
+ rescue
104
+ retries << report_body
107
105
  end
108
106
  retries.each do |report_body|
109
107
  add_retry_message(report_body)
@@ -65,7 +65,7 @@ module Coverband
65
65
 
66
66
  # NOTE: This event was instrumented in Aug 10th 2022, but didn't make the 7.0.4 release and should be in the next release
67
67
  # https://github.com/rails/rails/pull/43755
68
- # Automatic tracking of redirects isn't avaible before Rails 7.1.0 (currently tested against the 7.1.0.alpha)
68
+ # Automatic tracking of redirects isn't available before Rails 7.1.0 (currently tested against the 7.1.0.alpha)
69
69
  # We could consider back porting or patching a solution that works on previous Rails versions
70
70
  ActiveSupport::Notifications.subscribe("redirect.action_dispatch") do |name, start, finish, id, payload|
71
71
  Coverband.configuration.route_tracker.track_key(payload)
@@ -36,7 +36,7 @@ module Coverband
36
36
  app_translation_keys = []
37
37
  app_translation_files = ::I18n.load_path.select { |f| f.match(/config\/locales/) }
38
38
  app_translation_files.each do |file|
39
- app_translation_keys += flatten_hash(YAML.load_file(file)).keys
39
+ app_translation_keys += flatten_hash(YAML.load_file(file, aliases: true)).keys
40
40
  end
41
41
  app_translation_keys.uniq
42
42
  else
@@ -48,7 +48,7 @@ module Coverband
48
48
  hash.each_with_object({}) do |(k, v), h|
49
49
  if v.is_a? Hash
50
50
  flatten_hash(v).map do |h_k, h_v|
51
- h["#{k}.#{h_k}".to_sym] = h_v
51
+ h[:"#{k}.#{h_k}"] = h_v
52
52
  end
53
53
  else
54
54
  h[k] = v
@@ -81,7 +81,7 @@ module Coverband
81
81
  end
82
82
 
83
83
  def unused_keys(used_views = nil)
84
- recently_used_views = (used_keys || used_keys).keys
84
+ recently_used_views = used_keys.keys
85
85
  unused_views = all_keys - recently_used_views
86
86
  # since layouts don't include format we count them used if they match with ANY formats
87
87
  unused_views.reject { |view| view.match(/\/layouts\//) && recently_used_views.any? { |used_view| view.include?(used_view) } }
@@ -93,7 +93,7 @@ module Coverband
93
93
  @coverband_timeout = nil
94
94
  @service_dev_mode = nil
95
95
  @service_test_mode = nil
96
- @proces_type = nil
96
+ @process_type = nil
97
97
 
98
98
  @redis_url = nil
99
99
  @redis_namespace = nil
@@ -154,7 +154,7 @@ module Coverband
154
154
  def background_reporting_sleep_seconds
155
155
  @background_reporting_sleep_seconds ||= if service?
156
156
  # default to 10m for service
157
- Coverband.configuration.coverband_env == "production" ? 600 : 60
157
+ (Coverband.configuration.coverband_env == "production") ? 600 : 60
158
158
  elsif store.is_a?(Coverband::Adapters::HashRedisStore)
159
159
  # Default to 5 minutes if using the hash redis store
160
160
  300
@@ -180,7 +180,7 @@ module Coverband
180
180
  def store=(store)
181
181
  raise "Pass in an instance of Coverband::Adapters" unless store.is_a?(Coverband::Adapters::Base)
182
182
  raise "invalid configuration: only coverband service expects an API Key" if api_key && store.class.to_s != "Coverband::Adapters::WebServiceStore"
183
- raise "invalid configuration: coverband service shouldn't have redis url set" if ENV["COVERBAND_REDIS_URL"] && store.class.to_s == "Coverband::Adapters::WebServiceStore"
183
+ raise "invalid configuration: coverband service shouldn't have redis url set" if ENV["COVERBAND_REDIS_URL"] && store.instance_of?(::Coverband::Adapters::WebServiceStore)
184
184
 
185
185
  @store = store
186
186
  end
@@ -262,11 +262,11 @@ module Coverband
262
262
  end
263
263
 
264
264
  def coverband_env
265
- ENV["RACK_ENV"] || ENV["RAILS_ENV"] || (defined?(Rails) && Rails.respond_to?(:env) ? Rails.env : "unknown")
265
+ ENV["RACK_ENV"] || ENV["RAILS_ENV"] || ((defined?(Rails) && Rails.respond_to?(:env)) ? Rails.env : "unknown")
266
266
  end
267
267
 
268
268
  def coverband_timeout
269
- @coverband_timeout ||= coverband_env == "development" ? 5 : 2
269
+ @coverband_timeout ||= (coverband_env == "development") ? 5 : 2
270
270
  end
271
271
 
272
272
  def service_dev_mode
@@ -20,10 +20,8 @@ module Coverband
20
20
 
21
21
  def rails_server?
22
22
  @stack.any? do |location|
23
- (
24
- location.path.include?("rails/commands/commands_tasks.rb") && location.label == "server" ||
23
+ location.path.include?("rails/commands/commands_tasks.rb") && location.label == "server" ||
25
24
  location.path.include?("rails/commands/server/server_command.rb") && location.label == "perform"
26
- )
27
25
  end
28
26
  end
29
27
  end
@@ -4,15 +4,15 @@ module Coverband
4
4
  module Reporters
5
5
  ###
6
6
  # This is the base clase for report generation
7
- # it helps with filtering, normalization, etc for final reprort generation
7
+ # it helps with filtering, normalization, etc for final report generation
8
8
  ###
9
9
  class Base
10
10
  class << self
11
11
  DATA_KEY = "data"
12
12
 
13
- def report(store, _options = {})
13
+ def report(store, options = {})
14
14
  all_roots = Coverband.configuration.all_root_paths
15
- scov_style_report = get_current_scov_data_imp(store, all_roots)
15
+ get_current_scov_data_imp(store, all_roots, options)
16
16
 
17
17
  # These are extremelhy verbose but useful during coverband development, not generally for users
18
18
  # Only available by uncommenting this mode is never released
@@ -20,7 +20,6 @@ module Coverband
20
20
  # # msg = "report:\n #{scov_style_report.inspect}"
21
21
  # # Coverband.configuration.logger.debug msg
22
22
  # end
23
- scov_style_report
24
23
  end
25
24
 
26
25
  ###
@@ -71,7 +70,7 @@ module Coverband
71
70
  # > [nil,0,0,1,0,1]
72
71
  def merge_arrays(first, second)
73
72
  merged = []
74
- longest = first.length > second.length ? first : second
73
+ longest = (first.length > second.length) ? first : second
75
74
 
76
75
  longest.each_with_index do |_line, index|
77
76
  merged[index] = if first[index] || second[index]
@@ -86,12 +85,13 @@ module Coverband
86
85
  # why do we need to merge covered files data?
87
86
  # basically because paths on machines or deployed hosts could be different, so
88
87
  # two different keys could point to the same filename or `line_key`
88
+ # this happens when deployment has a dynmaic path or the path change during deployment (hot code reload)
89
89
  # TODO: think we are filtering based on ignore while sending to the store
90
90
  # and as we also pull it out here
91
91
  ###
92
- def get_current_scov_data_imp(store, roots)
92
+ def get_current_scov_data_imp(store, roots, options = {})
93
93
  scov_style_report = {}
94
- store.get_coverage_report.each_pair do |name, data|
94
+ store.get_coverage_report(options).each_pair do |name, data|
95
95
  data.each_pair do |key, line_data|
96
96
  next if Coverband.configuration.ignore.any? { |i| key.match(i) }
97
97
  next unless line_data
@@ -4,17 +4,23 @@ module Coverband
4
4
  module Reporters
5
5
  class HTMLReport < Base
6
6
  attr_accessor :filtered_report_files, :open_report, :notice,
7
- :base_path, :filename
7
+ :base_path, :filename, :page
8
8
 
9
9
  def initialize(store, options = {})
10
- coverband_reports = Coverband::Reporters::Base.report(store, options)
10
+ self.page = options.fetch(:page) { nil }
11
11
  self.open_report = options.fetch(:open_report) { true }
12
12
  # TODO: refactor notice out to top level of web only
13
13
  self.notice = options.fetch(:notice) { nil }
14
14
  self.base_path = options.fetch(:base_path) { "./" }
15
15
  self.filename = options.fetch(:filename) { nil }
16
16
 
17
- self.filtered_report_files = self.class.fix_reports(coverband_reports)
17
+ coverband_reports = Coverband::Reporters::Base.report(store, options)
18
+ # NOTE: at the moment the optimization around paging and filenames only works for hash redis store
19
+ self.filtered_report_files = if (page || filename) && store.is_a?(Coverband::Adapters::HashRedisStore)
20
+ coverband_reports
21
+ else
22
+ self.class.fix_reports(coverband_reports)
23
+ end
18
24
  end
19
25
 
20
26
  def file_details
@@ -36,12 +42,14 @@ module Coverband
36
42
  def report_dynamic_html
37
43
  Coverband::Utils::HTMLFormatter.new(filtered_report_files,
38
44
  base_path: base_path,
39
- notice: notice).format_dynamic_html!
45
+ notice: notice,
46
+ page: page).format_dynamic_html!
40
47
  end
41
48
 
42
49
  def report_dynamic_data
43
50
  Coverband::Utils::HTMLFormatter.new(filtered_report_files,
44
51
  base_path: base_path,
52
+ page: page,
45
53
  notice: notice).format_dynamic_data!
46
54
  end
47
55
  end