coverband 4.1.1 → 4.2.0

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/README.md +50 -43
  4. data/changes.md +31 -4
  5. data/lib/coverband/adapters/base.rb +24 -1
  6. data/lib/coverband/adapters/redis_store.rb +28 -7
  7. data/lib/coverband/at_exit.rb +19 -2
  8. data/lib/coverband/collectors/coverage.rb +35 -79
  9. data/lib/coverband/collectors/delta.rb +67 -0
  10. data/lib/coverband/integrations/background.rb +4 -3
  11. data/lib/coverband/integrations/rack_server_check.rb +4 -1
  12. data/lib/coverband/integrations/resque.rb +4 -0
  13. data/lib/coverband/reporters/base.rb +21 -14
  14. data/lib/coverband/reporters/html_report.rb +40 -15
  15. data/lib/coverband/reporters/web.rb +29 -6
  16. data/lib/coverband/utils/html_formatter.rb +20 -4
  17. data/lib/coverband/utils/railtie.rb +8 -0
  18. data/lib/coverband/utils/result.rb +3 -2
  19. data/lib/coverband/utils/results.rb +63 -0
  20. data/lib/coverband/utils/source_file.rb +5 -0
  21. data/lib/coverband/version.rb +1 -1
  22. data/lib/coverband.rb +23 -3
  23. data/public/application.css +5 -0
  24. data/public/application.js +108 -1644
  25. data/public/dependencies.js +1581 -0
  26. data/test/coverband/adapters/redis_store_test.rb +26 -9
  27. data/test/coverband/collectors/coverage_test.rb +15 -9
  28. data/test/coverband/collectors/delta_test.rb +52 -0
  29. data/test/coverband/coverband_test.rb +7 -0
  30. data/test/coverband/integrations/background_test.rb +14 -11
  31. data/test/coverband/integrations/middleware_test.rb +1 -0
  32. data/test/coverband/integrations/resque_worker_test.rb +7 -1
  33. data/test/coverband/reporters/base_test.rb +4 -4
  34. data/test/coverband/reporters/console_test.rb +1 -1
  35. data/test/coverband/reporters/html_test.rb +6 -7
  36. data/test/integration/full_stack_test.rb +10 -8
  37. data/test/integration/rails_full_stack_test.rb +23 -4
  38. data/test/rails4_dummy/config/application.rb +1 -1
  39. data/test/rails4_dummy/config/coverband.rb +4 -1
  40. data/test/rails5_dummy/config/application.rb +1 -1
  41. data/test/rails5_dummy/config/coverband.rb +3 -1
  42. data/test/rails_test_helper.rb +13 -8
  43. data/test/test_helper.rb +8 -1
  44. data/views/file_list.erb +9 -0
  45. data/views/gem_list.erb +1 -1
  46. data/views/layout.erb +4 -3
  47. data/views/source_file.erb +16 -4
  48. data/views/source_file_loader.erb +7 -0
  49. metadata +8 -4
  50. data/test/integration/rails_gems_full_stack_test.rb +0 -36
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e029eb4a5ce229ca0ce9dd7ac6638bc3b9776e07a724269a495b2832228119d
4
- data.tar.gz: 0f37d401fafe727024665b096e337138e53f8be139521dea9e149695b44f39ce
3
+ metadata.gz: 1e214b1bd6119046657daa64ed6d69f77f821c6c670b72e98d307ede5f08e61f
4
+ data.tar.gz: 469d9470799f90b5b52d53d3a630fae75b3b6bff0390375987902331878f530e
5
5
  SHA512:
6
- metadata.gz: c0d51d0263c37369abffc5839a367cdebd5fad7d8132362044163614fca33e2bc8617770bb36d3dd268eb34a4f0243e5fe4a1fad516f724a9da122aa5739a8be
7
- data.tar.gz: db40dfd936b39d159e7d92b470b186761cfea6ce944e55ff8079d70279af8c84a3602c5c873317c58d76b08aa0a654e653eb10df8a608ba646e4bd37b006105b
6
+ metadata.gz: f1b0f503941ab9dbc2dee6a184fe6d6d937a5f505a5c9112ae7343197372586d6cb42df758f24effde0ee30fb359c0e2e651c64a1f5ee4c9a588a4499683dc73
7
+ data.tar.gz: ee700abfe4c730011dcc5c1c8521f55a2cc7ec5149e44b08187c8d09419023160a0f7c8aaba4b2aa0bb405eb13f4aeee1d8ce9cabce4860738d4ea94cac63c04
data/.gitignore CHANGED
@@ -5,6 +5,8 @@
5
5
  .yardoc
6
6
  .idea/
7
7
  .ruby-version
8
+ assets/.DS_Store
9
+ .DS_Store
8
10
  Gemfile*lock
9
11
  InstalledFiles
10
12
  _yardoc
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ <img src="https://raw.github.com/danmayer/coverband/master/docs/assets/logo/heads.svg?sanitize=true" width='300'>
2
+
1
3
  # Coverband
2
4
 
3
5
  [![Build Status](https://travis-ci.org/danmayer/coverband.svg?branch=master)](https://travis-ci.org/danmayer/coverband)
@@ -15,24 +17,24 @@
15
17
 
16
18
  A gem to measure production code usage, showing a counter for the number of times each line of code that is executed. Coverband allows easy configuration to collect and report on production code usage. It reports in the background via a thread or can be used as Rack middleware, or manually configured to meet any need.
17
19
 
18
- __Note:__ Coverband is not intended for test code coverage, for that we recommended using [SimpleCov](https://github.com/colszowka/simplecov).
20
+ **Note:** Coverband is not intended for test code coverage, for that we recommended using [SimpleCov](https://github.com/colszowka/simplecov).
19
21
 
20
22
  ## Key Features
21
23
 
22
24
  The primary goal of Coverband is giving deep insight into your production runtime usage of your application code, while having the least impact on performance possible.
23
25
 
24
- * Low performance overhead
25
- * Very simple setup and configuration
26
- * Out of the box support for all standard code execution paths (web, cron, background jobs, rake tasks, etc)
27
- * Easy to understand actionable insights from the report
28
- * Development mode, offers deep insight of code usage details (number of LOC execution during single request, etc) during development.
29
- * Mountable web interface to easily share reports
26
+ - Low performance overhead
27
+ - Very simple setup and configuration
28
+ - Out of the box support for all standard code execution paths (web, cron, background jobs, rake tasks, etc)
29
+ - Easy to understand actionable insights from the report
30
+ - Development mode, offers deep insight of code usage details (number of LOC execution during single request, etc) during development.
31
+ - Mountable web interface to easily share reports
30
32
 
31
33
  # Installation
32
34
 
33
35
  ## Redis
34
36
 
35
- Coverband stores coverage data in Redis. The Redis endpoint is looked for in this order:
37
+ Coverband stores coverage data in Redis. The Redis endpoint is looked for in this order:
36
38
 
37
39
  1. `ENV['COVERBAND_REDIS_URL']`
38
40
  2. `ENV['REDIS_URL']`
@@ -54,7 +56,6 @@ If [tracking gem usage](#collecting-gem--library-usage), be sure to include cove
54
56
 
55
57
  The Railtie integration means you shouldn't need to do anything anything else other than ensure coverband is required after rails within your Gemfile.
56
58
 
57
-
58
59
  ## Sinatra
59
60
 
60
61
  For the best coverage you want this loaded as early as possible. I have been putting it directly in my `config.ru` but you could use an initializer, though you may end up missing some boot up coverage. To start collection require Coverband as early as possible.
@@ -77,7 +78,7 @@ Rails.application.routes.draw do
77
78
  end
78
79
  ```
79
80
 
80
- But don't forget to *protect your source code with proper authentication*. Something like this when using devise:
81
+ But don't forget to _protect your source code with proper authentication_. Something like this when using devise:
81
82
 
82
83
  ```ruby
83
84
  Rails.application.routes.draw do
@@ -92,11 +93,12 @@ end
92
93
  The web endpoint is a barebones endpoint that you can either expose direct (after authentication) or you can just link to the actions you wish to expose. The index is intended as a example to showcase all the features.
93
94
 
94
95
  ![image](https://raw.github.com/danmayer/coverband/master/docs/coverband_web_update.png)
96
+
95
97
  > The web index as available on the Coverband Demo site
96
98
 
97
- * __force coverage collection:__ This triggers coverage collection on the current webserver process
98
- * __reload Coverband files:__ This has Coverband reload files as configured (force reload of some files that might not capture Coverage on boot). This can be used to reload files on demand.
99
- * __clear coverage report:__ This will clear the coverage data. This wipes out all collected data (__dangerous__)
99
+ - **force coverage collection:** This triggers coverage collection on the current webserver process
100
+ - **reload Coverband files:** This has Coverband reload files as configured (force reload of some files that might not capture Coverage on boot). This can be used to reload files on demand.
101
+ - **clear coverage report:** This will clear the coverage data. This wipes out all collected data (**dangerous**)
100
102
 
101
103
  ### Rake Tasks
102
104
 
@@ -118,17 +120,16 @@ Details on an example Sinatra app
118
120
 
119
121
  # Verify Correct Installation
120
122
 
121
- * boot up your application
122
- * run app and hit a controller (via a web request, at least one request must complete)
123
- * run `rake coverband:coverage` this will show app initialization coverage
124
- * make another request, or enough that your reporting frequency will trigger
125
- * run `rake coverband:coverage` and you should see coverage increasing for the endpoints you hit.
123
+ - boot up your application
124
+ - run app and hit a controller (via a web request, at least one request must complete)
125
+ - run `rake coverband:coverage` this will show app initialization coverage
126
+ - make another request, or enough that your reporting frequency will trigger
127
+ - run `rake coverband:coverage` and you should see coverage increasing for the endpoints you hit.
126
128
 
127
129
  # Coverband Demo
128
130
 
129
131
  Take Coverband for a spin on the live Heroku deployed [Coverband Demo](https://coverband-demo.herokuapp.com/). The [full source code for the demo](https://github.com/danmayer/coverband_demo) is available to help with installation, configuration, and understanding of basic usage.
130
132
 
131
-
132
133
  ### Example apps
133
134
 
134
135
  - [Rails 5.2.x App](https://github.com/danmayer/coverband_demo)
@@ -137,14 +138,12 @@ Take Coverband for a spin on the live Heroku deployed [Coverband Demo](https://c
137
138
 
138
139
  # Advanced Config
139
140
 
140
-
141
141
  If you need to configure coverband, this can be done by creating a `config/coverband.rb` file relative to your project root.
142
142
 
143
- * See [lib/coverband/configuration.rb](https://github.com/danmayer/coverband/blob/master/lib/coverband/configuration.rb) for all options
144
- * By default Coverband will try to stored data to Redis
145
- * Redis endpoint is looked for in this order: `ENV['COVERBAND_REDIS_URL']`, `ENV['REDIS_URL']`, or `localhost`
143
+ - See [lib/coverband/configuration.rb](https://github.com/danmayer/coverband/blob/master/lib/coverband/configuration.rb) for all options
144
+ - By default Coverband will try to stored data to Redis \* Redis endpoint is looked for in this order: `ENV['COVERBAND_REDIS_URL']`, `ENV['REDIS_URL']`, or `localhost`
146
145
 
147
- Below is an example config file for a Rails 5 app:
146
+ Below is an example config file for a Rails 5 app:
148
147
 
149
148
  ```ruby
150
149
  #config/coverband.rb
@@ -170,14 +169,12 @@ end
170
169
  Sometimes you have files that are known to be valuable perhaps in other environments or something that is just run very infrequently. Opposed to having to mentally filter them out of the report, you can just have them ignored in the Coverband reporting by using `config.ignore` as shown below. Ignore takes a string but can also match with regex rules see how below ignores all rake tasks as an example.
171
170
 
172
171
  ```
173
- config.ignore = ['config/application.rb',
172
+ config.ignore += ['config/application.rb',
174
173
  'config/boot.rb',
175
174
  'config/puma.rb',
176
175
  'config/schedule.rb',
177
- 'config/environments/test.rb',
178
- 'config/environments/development.rb',
179
- 'config/environments/staging.rb',
180
- 'config/environments/production.rb',
176
+ 'bin/*'
177
+ 'config/environments/*',
181
178
  'lib/tasks/*']
182
179
  ```
183
180
 
@@ -208,8 +205,7 @@ Between the release of 4.0 and 4.1 our data format changed. This resets all your
208
205
 
209
206
  `rake coverband:migrate`
210
207
 
211
- * We will be working to support migrations going forward, when possible
212
-
208
+ - We will be working to support migrations going forward, when possible
213
209
 
214
210
  ### Clear Coverage
215
211
 
@@ -250,8 +246,8 @@ Coverband.configure do |config|
250
246
  config.safe_reload_files = ['config/coverband.rb']
251
247
  end
252
248
  ```
253
- By adding any files above you will get reporting on those files as part of your coverage runtime report. The files are reloaded when Coverband first starts, you can also trigger a reload via the web interface.
254
249
 
250
+ By adding any files above you will get reporting on those files as part of your coverage runtime report. The files are reloaded when Coverband first starts, you can also trigger a reload via the web interface.
255
251
 
256
252
  ### Collecting Gem / Library Usage
257
253
 
@@ -278,6 +274,17 @@ end
278
274
 
279
275
  This flag exposes line by line usage of gem files. Unfortunately due to the way the coverband report is currently rendered, enabling `gem_details` slows down viewing of the coverage report in the browser and is not yet recommended.
280
276
 
277
+ ### Manually Starting Coverband
278
+
279
+ Coverband starts on require of the the library which is usually done within the Gemfile. This can be disabled by setting the `COVERBAND_DISABLE_AUTO_START` environment variable. This environment variable can be useful to toggle coverband on and off in certain environments.
280
+
281
+ In order to start coverband manually yourself when this flag is enabled, call `Coverband.configure` followed by `Coverband.start`.
282
+
283
+ ```ruby
284
+ Coverband.configure
285
+ Coverband.start
286
+ ```
287
+
281
288
  ### Verbose Debug / Development Mode
282
289
 
283
290
  Note: To debug issues getting Coverband working. I recommend running in development mode, by turning verbose logging on `config.verbose = true` and passing in the Rails.logger `config.logger = Rails.logger` to the Coverband config. This makes it easy to follow in development mode. Be careful to not leave these on in production as they will affect performance.
@@ -304,8 +311,8 @@ If you are trying to debug locally wondering what code is being run during a req
304
311
 
305
312
  # Prerequisites
306
313
 
307
- * Coverband 3.0.X+ requires Ruby 2.3+
308
- * Coverband currently requires Redis for production usage
314
+ - Coverband 3.0.X+ requires Ruby 2.3+
315
+ - Coverband currently requires Redis for production usage
309
316
 
310
317
  # Contributing To Coverband
311
318
 
@@ -322,18 +329,18 @@ If you are working on adding features, PRs, or bugfixes to Coverband this sectio
322
329
 
323
330
  If you submit a change please make sure the tests and benchmarks are passing.
324
331
 
325
- * run tests:
326
- * `bundle exec rake`
327
- * `BUNDLE_GEMFILE=Gemfile.rails4 bundle exec rake` (Same tests using rails 4 instead of 5)
328
- * view test coverage: `open coverage/index.html`
329
- * run the benchmarks before and after your change to see impact
330
- * `rake benchmarks`
332
+ - run tests:
333
+ - `bundle exec rake`
334
+ - `BUNDLE_GEMFILE=Gemfile.rails4 bundle exec rake` (Same tests using rails 4 instead of 5)
335
+ - view test coverage: `open coverage/index.html`
336
+ - run the benchmarks before and after your change to see impact
337
+ - `rake benchmarks`
331
338
 
332
339
  ### Known Issues
333
340
 
334
- * __total fail__ on front end code, because of the precompiled template step basically coverage doesn't work well for `erb`, `slim`, and the like.
335
- * related it will try to report something, but the line numbers reported for `ERB` files are often off and aren't considered useful. I recommend filtering out .erb using the `config.ignore` option. The default configuration excludes these files
336
- * coverage doesn't show for Rails `config/application.rb` or `config/boot.rb` as they get loaded when loading the Rake environment prior to starting the `Coverage` library. See [reload files section](#forcing-coverband-to-track-coverage-on-files-loaded-during-boot-safe_reload_files).
341
+ - **total fail** on front end code, because of the precompiled template step basically coverage doesn't work well for `erb`, `slim`, and the like.
342
+ - related it will try to report something, but the line numbers reported for `ERB` files are often off and aren't considered useful. I recommend filtering out .erb using the `config.ignore` option. The default configuration excludes these files
343
+ - coverage doesn't show for Rails `config/application.rb` or `config/boot.rb` as they get loaded when loading the Rake environment prior to starting the `Coverage` library. See [reload files section](#forcing-coverband-to-track-coverage-on-files-loaded-during-boot-safe_reload_files).
337
344
 
338
345
  ### Debugging Redis Store
339
346
 
data/changes.md CHANGED
@@ -37,6 +37,16 @@ Will be the fully modern release that drops maintenance legacy support in favor
37
37
  - See if we can add support for views / templates
38
38
  - using this technique https://github.com/ioquatix/covered
39
39
  - Better default grouping (could use groups features for gems for rails controllers, models, lib, etc)
40
+ - Improved logging for easier debugging and development
41
+ - drop the verbose mode and better support standard logger levels
42
+ - Possibly setup a build assets system
43
+ - my JS rules expanded the compressed JS at the top of application.js, basically we want to stitch together JS
44
+ - I guess we could also load multiple JS files as most of the JS is just default compressed JS and a tiny amount of actual app JS.
45
+ - lazy load for Coverband results
46
+ - view layer file coverage
47
+ - move all code to work with relative paths leaving only stdlib Coverage working on full paths
48
+ - add gem_safe_lists to track only some gems
49
+ - add gem_details_safe list to report on details on some gems
40
50
 
41
51
  ### Coverband_jam_session
42
52
 
@@ -63,14 +73,31 @@ Feature Ideas:
63
73
 
64
74
  # Alpha
65
75
 
66
- ### Coverband 4.2.0.rc
76
+ ### Coverband 4.3.0?
67
77
 
68
- - loadtime vs runtime coverage
69
- - view coverage
70
- - perf speedup on gem details views
78
+ - further improvements on eager_loading detection
79
+ - ?
71
80
 
72
81
  # Released
73
82
 
83
+ ### Coverband 4.2.0
84
+
85
+ **NOTE:** This release introduces load time and runtime Coverage. To get the full benifit of this feature you need to reset you coverage data (`rake coverband:clear` or clear via the web UI). Until you clear the combined result is still correct, but your runtime data will be mixed with previous data. This is due to an additive change in how we store coverage. We didn't reset by default as the coverage history for some folks may be more important than runtime breakdown.
86
+
87
+ - loadtime vs runtime coverage
88
+ - This fixes the coverage last seen date to exclude just load time data
89
+ - now you can see boot time coverage vs code hit during production execution
90
+ - list view shows runtime percentage and runtime hits
91
+ - file view shows line hits load, runtime, and combined
92
+ - perf speedup on gem details views
93
+ - ajax load code views for more responsive pages on large projects
94
+ - fix for issues with COVERBAND_DISABLE_AUTO_START
95
+ - silence warnings
96
+ - move from thread based reporter instance to process based instance
97
+ - thanks Karl Baum for much of the above mentioned work
98
+ - clear coverage on individual files
99
+ - we have a logo, thanks Dave Woodall
100
+
74
101
  ### Coverband 4.1.1
75
102
 
76
103
  - fix bug on info page when using namespaces
@@ -4,6 +4,7 @@ module Coverband
4
4
  module Adapters
5
5
  class Base
6
6
  include Coverband::Utils::FilePathHelper
7
+ attr_accessor :type
7
8
 
8
9
  def initialize
9
10
  @file_hash_cache = {}
@@ -13,6 +14,10 @@ module Coverband
13
14
  raise 'abstract'
14
15
  end
15
16
 
17
+ def clear_file!(_file)
18
+ raise 'abstract'
19
+ end
20
+
16
21
  def migrate!
17
22
  raise 'abstract'
18
23
  end
@@ -39,6 +44,11 @@ module Coverband
39
44
  get_report
40
45
  end
41
46
 
47
+ def get_coverage_report
48
+ data = Coverband.configuration.store.split_coverage(Coverband::TYPES)
49
+ data.merge(Coverband::MERGED_TYPE => Coverband.configuration.store.merged_coverage(Coverband::TYPES))
50
+ end
51
+
42
52
  def covered_files
43
53
  coverage.keys || []
44
54
  end
@@ -50,6 +60,18 @@ module Coverband
50
60
 
51
61
  protected
52
62
 
63
+ def split_coverage(types)
64
+ types.reduce({}) do |data, type|
65
+ data.update(type => get_report(type))
66
+ end
67
+ end
68
+
69
+ def merged_coverage(types)
70
+ types.reduce({}) do |data, type|
71
+ merge_reports(data, get_report(type), skip_expansion: true)
72
+ end
73
+ end
74
+
53
75
  def save_coverage
54
76
  raise 'abstract'
55
77
  end
@@ -65,10 +87,11 @@ module Coverband
65
87
  def expand_report(report)
66
88
  expanded = {}
67
89
  report_time = Time.now.to_i
90
+ updated_time = self.type == Coverband::EAGER_TYPE ? nil : report_time
68
91
  report.each_pair do |key, line_data|
69
92
  extended_data = {
70
93
  'first_updated_at' => report_time,
71
- 'last_updated_at' => report_time,
94
+ 'last_updated_at' => updated_time,
72
95
  'file_hash' => file_hash(key),
73
96
  'data' => line_data
74
97
  }
@@ -22,7 +22,17 @@ module Coverband
22
22
  end
23
23
 
24
24
  def clear!
25
- @redis.del(base_key)
25
+ Coverband::TYPES.each do |type|
26
+ @redis.del(type_base_key(type))
27
+ end
28
+ end
29
+
30
+ def clear_file!(filename)
31
+ Coverband::TYPES.each do |type|
32
+ data = get_report(type)
33
+ data.delete(filename)
34
+ save_coverage(data, type)
35
+ end
26
36
  end
27
37
 
28
38
  def size
@@ -51,6 +61,11 @@ module Coverband
51
61
  save_coverage(merge_reports(get_report, relative_path_report, skip_expansion: true))
52
62
  end
53
63
 
64
+ def type=(type)
65
+ super
66
+ reset_base_key
67
+ end
68
+
54
69
  private
55
70
 
56
71
  attr_reader :redis
@@ -60,16 +75,22 @@ module Coverband
60
75
  end
61
76
 
62
77
  def base_key
63
- @base_key ||= [@format_version, @redis_namespace].compact.join('.')
78
+ @base_key ||= [@format_version, @redis_namespace, type].compact.join('.')
79
+ end
80
+
81
+ def type_base_key(local_type)
82
+ [@format_version, @redis_namespace, local_type].compact.join('.')
64
83
  end
65
84
 
66
- def save_coverage(data)
67
- redis.set base_key, data.to_json
68
- redis.expire(base_key, @ttl) if @ttl
85
+ def save_coverage(data, local_type = nil)
86
+ local_type ||= type
87
+ redis.set type_base_key(local_type), data.to_json
88
+ redis.expire(type_base_key(local_type), @ttl) if @ttl
69
89
  end
70
90
 
71
- def get_report
72
- data = redis.get base_key
91
+ def get_report(local_type = nil)
92
+ local_type ||= type
93
+ data = redis.get type_base_key(local_type)
73
94
  data ? JSON.parse(data) : {}
74
95
  end
75
96
  end
@@ -4,15 +4,32 @@ module Coverband
4
4
  class AtExit
5
5
  @semaphore = Mutex.new
6
6
 
7
+ @at_exit_registered = nil
7
8
  def self.register
9
+ return if ENV['COVERBAND_DISABLE_AT_EXIT']
8
10
  return if @at_exit_registered
11
+
9
12
  @semaphore.synchronize do
10
13
  return if @at_exit_registered
14
+
11
15
  @at_exit_registered = true
12
16
  at_exit do
13
17
  ::Coverband::Background.stop
14
- Coverband.report_coverage(true)
15
- Coverband.configuration.logger&.debug('Coverband: Reported coverage before exit')
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) }
28
+ # skip reporting
29
+ else
30
+ Coverband.report_coverage(true)
31
+ #Coverband.configuration.logger&.debug('Coverband: Reported coverage before exit')
32
+ end
16
33
  end
17
34
  end
18
35
  end
@@ -1,48 +1,60 @@
1
1
  # frozen_string_literal: true
2
+ require 'singleton'
3
+ require_relative 'delta'
2
4
 
3
5
  module Coverband
4
6
  module Collectors
5
7
  ###
6
- # TODO: look at alternatives to semaphore
7
- # StandardError seems line be better option
8
+ # StandardError seems like be better option
8
9
  # coverband previously had RuntimeError here
9
10
  # but runtime error can let a large number of error crash this method
10
11
  # and this method is currently in a ensure block in middleware and threads
11
12
  ###
12
13
  class Coverage
13
- def self.instance
14
- Thread.current[:coverband_instance] ||= Coverband::Collectors::Coverage.new
15
- end
14
+ include Singleton
16
15
 
17
16
  def reset_instance
18
17
  @project_directory = File.expand_path(Coverband.configuration.root)
19
- @file_line_usage = {}
20
18
  @ignore_patterns = Coverband.configuration.ignore + ['internal:prelude', 'schema.rb']
21
19
  @reporting_frequency = Coverband.configuration.reporting_frequency
22
20
  @store = Coverband.configuration.store
23
21
  @verbose = Coverband.configuration.verbose
24
22
  @logger = Coverband.configuration.logger
25
- @current_thread = Thread.current
26
23
  @test_env = Coverband.configuration.test_env
27
24
  @track_gems = Coverband.configuration.track_gems
28
- @@previous_results = nil
29
- Thread.current[:coverband_instance] = nil
25
+ Delta.reset
30
26
  self
31
27
  end
32
28
 
29
+ def runtime!
30
+ @store.type = nil
31
+ end
32
+
33
+ def eager_loading!
34
+ @store.type = Coverband::EAGER_TYPE
35
+ end
36
+
33
37
  def report_coverage(force_report = false)
34
38
  return if !ready_to_report? && !force_report
35
39
  raise 'no Coverband store set' unless @store
36
40
 
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
+ original_previous_set = Delta.previous_results
42
+ files_with_line_usage = filtered_files(Delta.results)
43
+
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))
51
+ @store.save_report(files_with_line_usage)
52
+ end
41
53
  rescue StandardError => err
42
54
  if @verbose
43
- @logger.error 'coverage failed to store'
44
- @logger.error "error: #{err.inspect} #{err.message}"
45
- @logger.error err.backtrace
55
+ @logger&.error 'coverage failed to store'
56
+ @logger&.error "error: #{err.inspect} #{err.message}"
57
+ @logger&.error err.backtrace
46
58
  end
47
59
  raise err if @test_env
48
60
  end
@@ -59,81 +71,27 @@ module Coverband
59
71
  @ignore_patterns.none? do |pattern|
60
72
  file.include?(pattern)
61
73
  end && (file.start_with?(@project_directory) ||
62
- (@track_gems &&
63
- Coverband.configuration.gem_paths.any? { |path| file.start_with?(path) }))
74
+ (@track_gems &&
75
+ Coverband.configuration.gem_paths.any? { |path| file.start_with?(path) }))
64
76
  end
65
77
 
66
78
  private
67
79
 
68
- def add_filtered_files(new_results)
69
- new_results.each_pair do |file, line_counts|
70
- next unless track_file?(file)
71
- add_file(file, line_counts)
72
- end
80
+ def filtered_files(new_results)
81
+ new_results.each_with_object({}) do |(file, line_counts), file_line_usage|
82
+ file_line_usage[file] = line_counts if track_file?(file)
83
+ end.select { |_file_name, coverage| coverage.any? { |value| value&.nonzero? } }
73
84
  end
74
85
 
75
86
  def ready_to_report?
76
87
  (rand * 100.0) >= (100.0 - @reporting_frequency)
77
88
  end
78
89
 
79
- def get_new_coverage_results
80
- @semaphore.synchronize { new_coverage(::Coverage.peek_result.dup) }
81
- end
82
-
83
- def files_with_line_usage
84
- @file_line_usage.select do |_file_name, coverage|
85
- coverage.any? { |value| value&.nonzero? }
86
- end
87
- end
88
-
89
- def array_diff(latest, original)
90
- latest.map.with_index do |v, i|
91
- if (v && original[i])
92
- [0, v - original[i]].max
93
- else
94
- nil
95
- end
96
- end
97
- end
98
-
99
- def previous_results
100
- @@previous_results
101
- end
102
-
103
- def add_previous_results(val)
104
- @@previous_results = val
105
- end
106
-
107
- def new_coverage(current_coverage)
108
- if previous_results
109
- new_results = {}
110
- current_coverage.each_pair do |file, line_counts|
111
- if previous_results[file]
112
- new_results[file] = array_diff(line_counts, previous_results[file])
113
- else
114
- new_results[file] = line_counts
115
- end
116
- end
117
- else
118
- new_results = current_coverage
119
- end
120
-
121
- add_previous_results(current_coverage)
122
- new_results.dup
123
- end
124
-
125
- def add_file(file, line_counts)
126
- @file_line_usage[file] = line_counts
127
- end
128
-
129
90
  def initialize
130
91
  if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3.0')
131
92
  raise NotImplementedError, 'not supported until Ruby 2.3.0 and later'
132
93
  end
133
- unless defined?(::Coverage)
134
- # puts 'loading coverage'
135
- require 'coverage'
136
- end
94
+ require 'coverage'
137
95
  if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.5.0')
138
96
  ::Coverage.start unless ::Coverage.running?
139
97
  else
@@ -144,8 +102,6 @@ module Coverband
144
102
  load safe_file
145
103
  end
146
104
  end
147
- @semaphore = Mutex.new
148
- @@previous_results = nil
149
105
  reset_instance
150
106
  end
151
107
  end