coverband 6.0.2 → 6.0.3.rc.1

Sign up to get free protection for your applications and to get access to all the features.
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