coverband 4.2.0 → 4.2.2

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 (99) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +29 -9
  3. data/.travis.yml +10 -8
  4. data/CODE_OF_CONDUCT.md +76 -0
  5. data/Gemfile +3 -1
  6. data/Gemfile.rails4 +1 -0
  7. data/README.md +72 -43
  8. data/Rakefile +14 -3
  9. data/changes.md +66 -11
  10. data/coverband.gemspec +2 -5
  11. data/lib/coverband/adapters/base.rb +64 -45
  12. data/lib/coverband/adapters/file_store.rb +15 -9
  13. data/lib/coverband/adapters/hash_redis_store.rb +182 -0
  14. data/lib/coverband/adapters/redis_store.rb +33 -11
  15. data/lib/coverband/at_exit.rb +2 -11
  16. data/lib/coverband/collectors/coverage.rb +34 -40
  17. data/lib/coverband/collectors/delta.rb +34 -28
  18. data/lib/coverband/collectors/view_tracker.rb +124 -0
  19. data/lib/coverband/configuration.rb +96 -32
  20. data/lib/coverband/integrations/background.rb +9 -4
  21. data/lib/coverband/integrations/{middleware.rb → background_middleware.rb} +2 -6
  22. data/lib/coverband/integrations/bundler.rb +8 -0
  23. data/lib/coverband/integrations/report_middleware.rb +15 -0
  24. data/lib/coverband/integrations/resque.rb +3 -5
  25. data/lib/coverband/reporters/base.rb +40 -16
  26. data/lib/coverband/reporters/console_report.rb +1 -0
  27. data/lib/coverband/reporters/html_report.rb +21 -27
  28. data/lib/coverband/reporters/web.rb +19 -21
  29. data/lib/coverband/utils/absolute_file_converter.rb +47 -0
  30. data/lib/coverband/utils/file_hasher.rb +16 -0
  31. data/lib/coverband/utils/file_list.rb +16 -5
  32. data/lib/coverband/utils/html_formatter.rb +37 -8
  33. data/lib/coverband/utils/lines_classifier.rb +5 -0
  34. data/lib/coverband/utils/railtie.rb +20 -9
  35. data/lib/coverband/utils/relative_file_converter.rb +41 -0
  36. data/lib/coverband/utils/result.rb +1 -37
  37. data/lib/coverband/utils/results.rb +51 -0
  38. data/lib/coverband/utils/s3_report.rb +2 -2
  39. data/lib/coverband/utils/source_file.rb +31 -8
  40. data/lib/coverband/utils/tasks.rb +10 -10
  41. data/lib/coverband/version.rb +5 -1
  42. data/lib/coverband.rb +39 -22
  43. data/public/application.css +6 -6
  44. data/public/application.js +27 -0
  45. data/test/benchmarks/benchmark.rake +167 -73
  46. data/test/benchmarks/init_rails.rake +10 -0
  47. data/test/coverband/adapters/base_test.rb +73 -42
  48. data/test/coverband/adapters/file_store_test.rb +48 -37
  49. data/test/coverband/adapters/hash_redis_store_test.rb +190 -0
  50. data/test/coverband/adapters/redis_store_test.rb +92 -59
  51. data/test/coverband/at_exit_test.rb +0 -2
  52. data/test/coverband/collectors/coverage_test.rb +62 -10
  53. data/test/coverband/collectors/delta_test.rb +36 -6
  54. data/test/coverband/collectors/view_tracker_test.rb +77 -0
  55. data/test/coverband/configuration_test.rb +47 -7
  56. data/test/coverband/coverband_test.rb +14 -2
  57. data/test/coverband/integrations/background_middleware_test.rb +44 -0
  58. data/test/coverband/integrations/background_test.rb +1 -3
  59. data/test/coverband/integrations/report_middleware_test.rb +44 -0
  60. data/test/coverband/integrations/resque_worker_test.rb +6 -6
  61. data/test/coverband/integrations/test_resque_job.rb +3 -1
  62. data/test/coverband/reporters/base_test.rb +2 -79
  63. data/test/coverband/reporters/console_test.rb +2 -6
  64. data/test/coverband/reporters/html_test.rb +58 -19
  65. data/test/coverband/reporters/web_test.rb +0 -10
  66. data/test/coverband/utils/absolute_file_converter_test.rb +56 -0
  67. data/test/coverband/utils/file_groups_test.rb +11 -5
  68. data/test/coverband/utils/file_hasher_test.rb +29 -0
  69. data/test/coverband/utils/file_list_test.rb +5 -5
  70. data/test/coverband/utils/html_formatter_test.rb +43 -0
  71. data/test/coverband/utils/relative_file_converter_test.rb +39 -0
  72. data/test/coverband/utils/result_test.rb +6 -47
  73. data/test/coverband/utils/results_test.rb +54 -0
  74. data/test/coverband/utils/s3_report_test.rb +2 -0
  75. data/test/coverband/utils/source_file_test.rb +50 -0
  76. data/test/dog.rb.erb +12 -0
  77. data/test/forked/rails_full_stack_test.rb +106 -0
  78. data/test/forked/rails_rake_full_stack_test.rb +48 -0
  79. data/test/integration/full_stack_test.rb +17 -16
  80. data/test/rails4_dummy/Rakefile +6 -0
  81. data/test/rails4_dummy/config/application.rb +8 -9
  82. data/test/rails4_dummy/config/coverband.rb +5 -3
  83. data/test/rails5_dummy/Rakefile +6 -0
  84. data/test/rails5_dummy/config/application.rb +6 -10
  85. data/test/rails5_dummy/config/coverband.rb +4 -2
  86. data/test/rails_test_helper.rb +22 -5
  87. data/test/test_helper.rb +45 -8
  88. data/test/unique_files.rb +17 -9
  89. data/views/file_list.erb +2 -2
  90. data/views/gem_list.erb +10 -1
  91. data/views/layout.erb +6 -18
  92. data/views/nav.erb +35 -0
  93. data/views/source_file.erb +13 -4
  94. data/views/source_file_loader.erb +1 -1
  95. data/views/view_tracker.erb +37 -0
  96. metadata +59 -25
  97. data/lib/coverband/utils/file_path_helper.rb +0 -57
  98. data/test/coverband/integrations/middleware_test.rb +0 -96
  99. data/test/integration/rails_full_stack_test.rb +0 -95
@@ -10,7 +10,7 @@
10
10
  module Coverband
11
11
  module Utils
12
12
  class SourceFile
13
- include Coverband::Utils::FilePathHelper
13
+ # TODO: Refactor Line into its own file
14
14
  # Representation of a single line in a source file including
15
15
  # this specific line's source code, line_number and code coverage,
16
16
  # with the coverage being either nil (coverage not applicable, e.g. comment
@@ -35,6 +35,7 @@ module Coverband
35
35
  raise ArgumentError, 'Only String accepted for source' unless src.is_a?(String)
36
36
  raise ArgumentError, 'Only Integer accepted for line_number' unless line_number.is_a?(Integer)
37
37
  raise ArgumentError, 'Only Integer and nil accepted for coverage' unless coverage.is_a?(Integer) || coverage.nil?
38
+
38
39
  @src = src
39
40
  @line_number = line_number
40
41
  @coverage = coverage
@@ -48,7 +49,7 @@ module Coverband
48
49
 
49
50
  # Returns true if this is a line that has been covered
50
51
  def covered?
51
- !never? && !skipped? && coverage > 0
52
+ !never? && !skipped? && coverage.positive?
52
53
  end
53
54
 
54
55
  # Returns true if this line is not relevant for coverage
@@ -64,7 +65,7 @@ module Coverband
64
65
  # Returns true if this line was skipped, false otherwise. Lines are skipped if they are wrapped with
65
66
  # # :nocov: comment lines.
66
67
  def skipped?
67
- !!skipped
68
+ skipped
68
69
  end
69
70
 
70
71
  # The status of this line - either covered, missed, skipped or never. Useful i.e. for direct use
@@ -90,18 +91,27 @@ module Coverband
90
91
 
91
92
  def initialize(filename, file_data)
92
93
  @filename = filename
94
+ @runtime_relavant_lines = nil
93
95
  if file_data.is_a?(Hash)
94
96
  @coverage = file_data['data']
95
97
  @first_updated_at = @last_updated_at = NOT_AVAILABLE
96
98
  @first_updated_at = Time.at(file_data['first_updated_at']) if file_data['first_updated_at']
97
99
  @last_updated_at = Time.at(file_data['last_updated_at']) if file_data['last_updated_at']
98
100
  else
101
+ # TODO: Deprecate this code path this was backwards compatability from 3-4
99
102
  @coverage = file_data
100
103
  @first_updated_at = NOT_AVAILABLE
101
104
  @last_updated_at = NOT_AVAILABLE
102
105
  end
103
106
  end
104
107
 
108
+ def runtime_relavant_calculations(runtime_relavant_lines)
109
+ @runtime_relavant_lines = runtime_relavant_lines
110
+ yield self
111
+ ensure
112
+ @runtime_relavant_lines = nil
113
+ end
114
+
105
115
  # The path to this source file relative to the projects directory
106
116
  def project_filename
107
117
  @filename.sub(/^#{Coverband.configuration.root}/, '')
@@ -148,7 +158,12 @@ module Coverband
148
158
 
149
159
  return 0.0 if relevant_lines.zero?
150
160
 
151
- Float(covered_lines.size * 100.0 / relevant_lines.to_f)
161
+ # handle edge case where runtime in dev can go over 100%
162
+ [Float(covered_lines.size * 100.0 / relevant_lines.to_f), 100.0].min
163
+ end
164
+
165
+ def formatted_covered_percent
166
+ covered_percent&.round(2)
152
167
  end
153
168
 
154
169
  def covered_strength
@@ -166,7 +181,7 @@ module Coverband
166
181
  end
167
182
 
168
183
  def relevant_lines
169
- lines.size - never_lines.size - skipped_lines.size
184
+ @runtime_relavant_lines || (lines.size - never_lines.size - skipped_lines.size)
170
185
  end
171
186
 
172
187
  # Returns all covered lines as SimpleCov::SourceFile::Line
@@ -174,6 +189,14 @@ module Coverband
174
189
  @covered_lines ||= lines.select(&:covered?)
175
190
  end
176
191
 
192
+ def covered_lines_count
193
+ covered_lines&.count
194
+ end
195
+
196
+ def line_coverage(index)
197
+ lines[index]&.coverage
198
+ end
199
+
177
200
  # Returns all lines that should have been, but were not covered
178
201
  # as instances of SimpleCov::SourceFile::Line
179
202
  def missed_lines
@@ -216,12 +239,12 @@ module Coverband
216
239
  # I had previously patched this in my local Rails app
217
240
  def short_name
218
241
  filename.sub(/^#{Coverband.configuration.root}/, '.')
219
- .sub(%r{^.*\/gems}, '.')
242
+ .sub(%r{^.*\/gems\/}, '.')
220
243
  .gsub(%r{^\.\/}, '')
221
244
  end
222
245
 
223
246
  def relative_path
224
- full_path_to_relative(filename)
247
+ RelativeFileConverter.convert(filename)
225
248
  end
226
249
 
227
250
  def gem?
@@ -229,7 +252,7 @@ module Coverband
229
252
  end
230
253
 
231
254
  def gem_name
232
- gem? ? short_name.split('/').first : nil
255
+ gem? ? short_name.split('/').first.gsub(%r{^\.}, '') : nil
233
256
  end
234
257
 
235
258
  private
@@ -1,37 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  namespace :coverband do
4
- Coverband.configure
5
-
6
- def environment
7
- Rake.application['environment'].invoke if Rake::Task.task_defined?('environment')
8
- end
4
+ # handles configuring in require => false and COVERBAND_DISABLE_AUTO_START cases
5
+ Coverband.configure unless Coverband.configured?
9
6
 
10
7
  desc 'report runtime Coverband code coverage'
11
8
  task :coverage do
12
- environment
13
9
  if Coverband.configuration.reporter == 'scov'
14
- Coverband::Reporters::HTMLReport.report(Coverband.configuration.store)
10
+ Coverband::Reporters::HTMLReport.new(Coverband.configuration.store).report
15
11
  else
16
12
  Coverband::Reporters::ConsoleReport.report(Coverband.configuration.store)
17
13
  end
18
14
  end
19
15
 
16
+ desc 'report runtime Coverband code coverage'
17
+ task :coverage_server do
18
+ Rake.application['environment'].invoke if Rake::Task.task_defined?('environment')
19
+ Rack::Server.start app: Coverband::Reporters::Web.new, Port: ENV.fetch('COVERBAND_COVERAGE_PORT', 1022).to_i
20
+ end
21
+
20
22
  ###
21
23
  # clear data helpful for development or after configuration issues
22
24
  ###
23
25
  desc 'reset Coverband coverage data, helpful for development, debugging, etc'
24
26
  task :clear do
25
- environment
26
27
  Coverband.configuration.store.clear!
27
28
  end
28
29
 
29
30
  ###
30
- # clear data helpful for development or after configuration issues
31
+ # Updates the data in the coverband store from one format to another
31
32
  ###
32
33
  desc 'upgrade previous Coverband datastore to latest format'
33
34
  task :migrate do
34
- environment
35
35
  Coverband.configuration.store.migrate!
36
36
  end
37
37
  end
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ ###
4
+ # ensure we properly do release candidate versioning; https://github.com/danmayer/coverband/issues/288
5
+ # use format '4.2.1.rc.1' ~> 4.2.1.rc to prerelease versions like v4.2.1.rc.2 and v4.2.1.rc.3
6
+ ###
3
7
  module Coverband
4
- VERSION = '4.2.0'
8
+ VERSION = '4.2.2'
5
9
  end
data/lib/coverband.rb CHANGED
@@ -6,10 +6,13 @@ require 'redis'
6
6
  require 'coverband/version'
7
7
  require 'coverband/at_exit'
8
8
  require 'coverband/configuration'
9
- require 'coverband/utils/file_path_helper'
9
+ require 'coverband/utils/relative_file_converter'
10
+ require 'coverband/utils/absolute_file_converter'
10
11
  require 'coverband/adapters/base'
11
12
  require 'coverband/adapters/redis_store'
13
+ require 'coverband/adapters/hash_redis_store'
12
14
  require 'coverband/adapters/file_store'
15
+ require 'coverband/utils/file_hasher'
13
16
  require 'coverband/utils/s3_report'
14
17
  require 'coverband/utils/html_formatter'
15
18
  require 'coverband/utils/result'
@@ -20,27 +23,26 @@ require 'coverband/utils/file_groups'
20
23
  require 'coverband/utils/lines_classifier'
21
24
  require 'coverband/utils/results'
22
25
  require 'coverband/collectors/coverage'
26
+ require 'coverband/collectors/view_tracker'
23
27
  require 'coverband/reporters/base'
24
28
  require 'coverband/reporters/html_report'
25
29
  require 'coverband/reporters/console_report'
26
- require 'coverband/integrations/background'
27
- require 'coverband/integrations/rack_server_check'
28
30
  require 'coverband/reporters/web'
29
- require 'coverband/integrations/middleware'
30
31
  require 'coverband/integrations/background'
32
+ require 'coverband/integrations/background_middleware'
33
+ require 'coverband/integrations/rack_server_check'
34
+
35
+ Coverband::Adapters::RedisStore = Coverband::Adapters::HashRedisStore if ENV['COVERBAND_HASH_REDIS_STORE']
31
36
 
32
37
  module Coverband
38
+ @@configured = false
33
39
  CONFIG_FILE = './config/coverband.rb'
34
- RUNTIME_TYPE = nil
40
+ RUNTIME_TYPE = :runtime
35
41
  EAGER_TYPE = :eager_loading
36
42
  MERGED_TYPE = :merged
37
43
  TYPES = [RUNTIME_TYPE, EAGER_TYPE]
38
44
  ALL_TYPES = TYPES + [:merged]
39
45
 
40
- class << self
41
- attr_accessor :configuration_data
42
- end
43
-
44
46
  def self.configure(file = nil)
45
47
  configuration_file = file || ENV.fetch('COVERBAND_CONFIG', CONFIG_FILE)
46
48
  configuration
@@ -49,45 +51,60 @@ module Coverband
49
51
  elsif File.exist?(configuration_file)
50
52
  load configuration_file
51
53
  else
52
- configuration.logger&.debug('using default configuration')
54
+ configuration.logger.debug('using default configuration')
53
55
  end
54
- coverage.reset_instance
56
+ @@configured = true
57
+ coverage_instance.reset_instance
55
58
  end
56
59
 
57
- def self.report_coverage(force_report = false)
58
- Coverband::Collectors::Coverage.instance.report_coverage(force_report)
60
+ def self.configured?
61
+ @@configured
62
+ end
63
+
64
+ def self.report_coverage
65
+ coverage_instance.report_coverage
59
66
  end
60
67
 
61
68
  def self.configuration
62
- self.configuration_data ||= Configuration.new
69
+ @configuration ||= Configuration.new
63
70
  end
64
71
 
65
72
  def self.start
66
73
  Coverband::Collectors::Coverage.instance
67
- # TODO Railtie sets up at_exit after forks, via middleware, perhaps this hsould be
74
+ # TODO: Railtie sets up at_exit after forks, via middleware, perhaps this should be
68
75
  # added if not rails or if rails but not rackserverrunning
69
- AtExit.register
70
- Background.start if configuration.background_reporting_enabled && !RackServerCheck.running?
76
+ AtExit.register unless tasks_to_ignore?
77
+ Background.start if configuration.background_reporting_enabled && !RackServerCheck.running? && !tasks_to_ignore?
78
+ end
79
+
80
+ def self.tasks_to_ignore?
81
+ (defined?(Rake) &&
82
+ Rake.respond_to?(:application) &&
83
+ (Rake&.application&.top_level_tasks || []).any? { |task| Coverband::Configuration::IGNORE_TASKS.include?(task) })
71
84
  end
72
85
 
73
86
  def self.eager_loading_coverage!
74
- coverage.eager_loading!
87
+ coverage_instance.eager_loading!
88
+ end
89
+
90
+ def self.eager_loading_coverage(&block)
91
+ coverage_instance.eager_loading(&block)
75
92
  end
76
93
 
77
94
  def self.runtime_coverage!
78
- coverage.runtime!
95
+ coverage_instance.runtime!
79
96
  end
80
97
 
81
- def self.coverage
98
+ private_class_method def self.coverage_instance
82
99
  Coverband::Collectors::Coverage.instance
83
100
  end
84
-
85
101
  unless ENV['COVERBAND_DISABLE_AUTO_START']
86
102
  # Coverband should be setup as early as possible
87
103
  # to capture usage of things loaded by initializers or other Rails engines
88
104
  configure
89
105
  start
90
106
  require 'coverband/utils/railtie' if defined? ::Rails::Railtie
91
- require 'coverband/integrations/resque' if defined? Resque
107
+ require 'coverband/integrations/resque' if defined? ::Resque
108
+ require 'coverband/integrations/bundler' if defined? ::Bundler
92
109
  end
93
110
  end
@@ -634,15 +634,15 @@ abbr.timeago {
634
634
  float: right;
635
635
  color: #dddddd; }
636
636
 
637
- .group_tabs {
637
+ .group_tabs, .extra_tabs {
638
638
  list-style: none;
639
639
  float: left;
640
640
  margin: 0;
641
641
  padding: 0; }
642
- .group_tabs li {
642
+ .group_tabs li, .extra_tabs li {
643
643
  display: inline;
644
644
  float: left; }
645
- .group_tabs li a {
645
+ .group_tabs li a, .extra_tabs li a {
646
646
  font-family: Helvetica, Arial, sans-serif;
647
647
  display: block;
648
648
  float: left;
@@ -664,15 +664,15 @@ abbr.timeago {
664
664
  -moz-border-radius-topright: 2px;
665
665
  border-top-left-radius: 2px;
666
666
  border-top-right-radius: 2px; }
667
- .group_tabs li a:hover {
667
+ .group_tabs li a:hover, .extra_tabs li a:hover {
668
668
  background-color: #cccccc;
669
669
  background: -webkit-gradient(linear, 0 0, 0 bottom, from(#eeeeee), to(#aaaaaa));
670
670
  background: -moz-linear-gradient(#eeeeee, #aaaaaa);
671
671
  background: linear-gradient(#eeeeee, #aaaaaa); }
672
- .group_tabs li a:active {
672
+ .group_tabs li a:active, .extra_tabs li a:active {
673
673
  padding-top: 5px;
674
674
  padding-bottom: 3px; }
675
- .group_tabs li.active a {
675
+ .group_tabs li.active a, .extra_tabs li.active a {
676
676
  color: black;
677
677
  text-shadow: white 1px 1px 0px;
678
678
  background-color: #dddddd;
@@ -1,4 +1,14 @@
1
1
  $(document).ready(function() {
2
+ // remove the url params like notice=message so they don't stick around
3
+ window.history.replaceState(
4
+ "object or string",
5
+ "Coverband",
6
+ window.location.href.replace(/notice=.*/, "")
7
+ );
8
+ $(".notice")
9
+ .delay(3000)
10
+ .fadeOut("slow");
11
+
2
12
  $(".del").click(function() {
3
13
  if (!confirm("Do you want to delete")) {
4
14
  return false;
@@ -13,8 +23,25 @@ $(document).ready(function() {
13
23
  aoColumns: [
14
24
  null,
15
25
  { sType: "percent" },
26
+ { sType: "percent" },
27
+ null,
28
+ null,
29
+ null,
16
30
  null,
17
31
  null,
32
+ null
33
+ ]
34
+ });
35
+
36
+ // Configuration for fancy sortable tables for source file groups
37
+ $(".gem_list").dataTable({
38
+ aaSorting: [[1, "asc"]],
39
+ bPaginate: false,
40
+ bJQueryUI: true,
41
+ aoColumns: [
42
+ null,
43
+ { sType: "percent" },
44
+ { sType: "percent" },
18
45
  null,
19
46
  null,
20
47
  null,