coverband 4.1.0.alpha → 4.1.0.beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dee2efe6e6763457859da3c235858f9de0a17189
4
- data.tar.gz: 441347a296e06c2189f02a26b3d966825a90e354
3
+ metadata.gz: 455614fde267b2ba0264e2949996587a342059f0
4
+ data.tar.gz: 6246b3c559c1d68d895928ceccdd8ebb8211934a
5
5
  SHA512:
6
- metadata.gz: b9c5b36fbb46b80da1bb4ca4a098d12dbfec941059a1b7eb297d1d77f065674183df7cd115ac965289db3751f2f9595abfe81e947771c6fc4b5a9155726c8c1b
7
- data.tar.gz: 68e90213cc0af16924c4e681b59e6ac8d77463921ec7ba019ac8b4bc3579805e62a0ad10e51a793a18b3bd037af09a9e13bfb9e245d8a5e9b309b2960d8a70bd
6
+ metadata.gz: e2c4d201b82e29c772bc201aea5eecc5d3edc79746dbaf0838497b73def8fbb23c8b394b4e218ae9fd6a0e0b9a9df05fd71baa63ecbbf88768afe67fb0259dcb
7
+ data.tar.gz: ebce43a1554a11de5c8f0c280a32b89a762e44e8a68228e7fb63e3ef1855e0617018bfb6e052492b664708061e0ffc4d6350a2ce02b1f5bed568022b8f3c597f
data/Gemfile CHANGED
@@ -5,3 +5,5 @@ source 'https://rubygems.org'
5
5
  # Specify your gem's dependencies in coverband.gemspec
6
6
  gemspec
7
7
  gem 'rails', '~>5'
8
+ # this is used for testing gem tracking
9
+ gem 'rainbow', require: false
@@ -5,3 +5,5 @@ source 'https://rubygems.org'
5
5
  # Specify your gem's dependencies in coverband.gemspec
6
6
  gemspec
7
7
  gem 'rails', '~>4'
8
+ # this is used for testing gem tracking
9
+ gem 'rainbow', require: false
data/changes.md CHANGED
@@ -35,7 +35,8 @@ Will be the fully modern release that drops maintenance legacy support in favor
35
35
  - more details in this issue: https://github.com/danmayer/coverband/issues/118
36
36
  - Make good video on setup, install, usage
37
37
  - See if we can add support for views / templates
38
- - using this technique https://github.com/ioquatix/covered
38
+ - using this technique https://github.com/ioquatix/covered
39
+ - Better default grouping (could use groups features for gems for rails controllers, models, lib, etc)
39
40
 
40
41
  ### Coverband_jam_session
41
42
 
@@ -62,9 +63,21 @@ Feature Ideas:
62
63
 
63
64
  # Alpha
64
65
 
65
- ### Coverband 4.0.2.alpha
66
+ ### Coverband 4.2.0.alpha
67
+
68
+ ???
69
+
70
+ ### Coverband 4.1.0.beta
66
71
 
67
72
  - default disabled web clear, add config option to allow it
73
+ - out of the box support for resque
74
+ - readme improvements
75
+ - fix on regression of merging directory changing deployments
76
+ - pilot release of Gems tracking (disabled by default)
77
+ - todos
78
+ - support multiple gem paths (various version managers setup multiple gem paths)
79
+ - speed up page load by allowing multiple pages
80
+ - added web settings and debug views
68
81
 
69
82
  # Released
70
83
 
@@ -76,7 +89,7 @@ Feature Ideas:
76
89
  - reduced the S3 dependencies to minimal set (not loading all of aws-sdk, only aws-sdk-s3), ensured they are optional
77
90
  - Improved Coverband web admin
78
91
  - Coverage reports include timestamps of Coverage collection
79
- - Added Coveralls to the dev process thanks @dondonz
92
+ - Added Coveralls to the dev process thanks @dondonz
80
93
  - now tested under Ruby 2.6.0 thanks @Kbaum
81
94
  - improved full stack testing for Rails 5 & 4
82
95
  - warning before clear coverage on coverband web
@@ -14,7 +14,9 @@ require 'coverband/utils/s3_report'
14
14
  require 'coverband/utils/html_formatter'
15
15
  require 'coverband/utils/result'
16
16
  require 'coverband/utils/file_list'
17
+ require 'coverband/utils/gem_list'
17
18
  require 'coverband/utils/source_file'
19
+ require 'coverband/utils/file_groups'
18
20
  require 'coverband/utils/lines_classifier'
19
21
  require 'coverband/utils/railtie' if defined? ::Rails::Railtie
20
22
  require 'coverband/collectors/coverage'
@@ -90,12 +90,6 @@ module Coverband
90
90
  def array_add(latest, original)
91
91
  latest.map.with_index { |v, i| (v && original[i]) ? v + original[i] : nil }
92
92
  end
93
-
94
- def simple_report(report)
95
- report.each_with_object({}) do |(key, extended_data), simple|
96
- simple[key] = extended_data['data']
97
- end
98
- end
99
93
  end
100
94
  end
101
95
  end
@@ -24,6 +24,7 @@ module Coverband
24
24
  @logger = Coverband.configuration.logger
25
25
  @current_thread = Thread.current
26
26
  @test_env = Coverband.configuration.test_env
27
+ @track_gems = Coverband.configuration.track_gems
27
28
  @@previous_results = nil
28
29
  Thread.current[:coverband_instance] = nil
29
30
  self
@@ -48,10 +49,18 @@ module Coverband
48
49
 
49
50
  protected
50
51
 
52
+ ###
53
+ # Normally I would break this out into additional methods
54
+ # and improve the readability but this is in a tight loop
55
+ # on the critical performance path, and any refactoring I come up with
56
+ # would slow down the performance.
57
+ ###
51
58
  def track_file?(file)
52
59
  @ignore_patterns.none? do |pattern|
53
60
  file.include?(pattern)
54
- end && file.start_with?(@project_directory)
61
+ end && (file.start_with?(@project_directory) ||
62
+ (@track_gems &&
63
+ Coverband.configuration.gem_paths.any? { |path| file.start_with?(path) }))
55
64
  end
56
65
 
57
66
  private
@@ -8,9 +8,10 @@ module Coverband
8
8
  :redis_namespace, :redis_ttl,
9
9
  :safe_reload_files, :background_reporting_enabled,
10
10
  :background_reporting_sleep_seconds, :test_env,
11
- :web_enable_clear
11
+ :web_enable_clear, :gem_details, :web_debug
12
12
 
13
13
  attr_writer :logger, :s3_region, :s3_bucket, :s3_access_key_id, :s3_secret_access_key
14
+ attr_reader :track_gems
14
15
 
15
16
  def initialize
16
17
  reset
@@ -19,7 +20,7 @@ module Coverband
19
20
  def reset
20
21
  @root = Dir.pwd
21
22
  @root_paths = []
22
- @ignore = %w(vendor .erb$ .slim$)
23
+ @ignore = %w[vendor .erb$ .slim$]
23
24
  @additional_files = []
24
25
  @reporting_frequency = 0.0
25
26
  @verbose = false
@@ -30,6 +31,10 @@ module Coverband
30
31
  @background_reporting_sleep_seconds = 30
31
32
  @test_env = nil
32
33
  @web_enable_clear = false
34
+ @track_gems = false
35
+ @gem_details = false
36
+ @groups = {}
37
+ @web_debug = false
33
38
 
34
39
  # TODO: should we push these to adapter configs
35
40
  @s3_region = nil
@@ -76,6 +81,54 @@ module Coverband
76
81
  end
77
82
  end
78
83
 
84
+ def track_gems=(value)
85
+ @track_gems = value
86
+ return unless @track_gems
87
+ # by default we ignore vendor where many deployments put gems
88
+ # we will remove this default if track_gems is set
89
+ @ignore.delete('vendor')
90
+ # while we want to allow vendored gems we don't want to track vendored ruby STDLIB
91
+ @ignore << 'vendor/ruby-*'
92
+ add_group('App', root)
93
+ # TODO: rework support for multiple gem paths
94
+ # currently this supports GEM_HOME (which should be first path)
95
+ # but various gem managers setup multiple gem paths
96
+ # gem_paths.each_with_index do |path, index|
97
+ # add_group("gems_#{index}", path)
98
+ # end
99
+ add_group('Gems', gem_paths.first)
100
+ end
101
+
102
+ #
103
+ # Returns the configured groups. Add groups using SimpleCov.add_group
104
+ #
105
+ def groups
106
+ @groups ||= {}
107
+ end
108
+
109
+ #
110
+ # Define a group for files. Works similar to add_filter, only that the first
111
+ # argument is the desired group name and files PASSING the filter end up in the group
112
+ # (while filters exclude when the filter is applicable).
113
+ #
114
+ def add_group(group_name, filter_argument = nil)
115
+ groups[group_name] = filter_argument
116
+ end
117
+
118
+ def gem_paths
119
+ # notes ignore any paths that aren't on this system, resolves
120
+ # bug related to multiple ruby version managers / bad dot files
121
+ Gem::PathSupport.new(ENV).path.select { |path| File.exist?(path) }
122
+ end
123
+
124
+ SKIPPED_SETTINGS = %w[@s3_secret_access_key @store]
125
+ def to_h
126
+ instance_variables
127
+ .each_with_object('gem_paths': gem_paths) do |var, hash|
128
+ hash[var.to_s.delete('@')] = instance_variable_get(var) unless SKIPPED_SETTINGS.include?(var.to_s)
129
+ end
130
+ end
131
+
79
132
  private
80
133
 
81
134
  def redis_url
@@ -22,6 +22,7 @@ module Coverband
22
22
 
23
23
  def root_paths
24
24
  roots = Coverband.configuration.root_paths
25
+ roots += Coverband.configuration.gem_paths if Coverband.configuration.track_gems
25
26
  roots << "#{current_root}/"
26
27
  roots
27
28
  end
@@ -38,8 +39,10 @@ module Coverband
38
39
  # normalize names across servers
39
40
  report_hash.each_with_object({}) do |(key, vals), fixed_report|
40
41
  filename = filename_from_key(key, roots)
41
- fixed_report[filename] = if fixed_report.key?(filename)
42
- merge_arrays(fixed_report[filename], vals)
42
+ fixed_report[filename] = if fixed_report.key?(filename) && fixed_report[filename]['data'] && vals['data']
43
+ merged_data = merge_arrays(fixed_report[filename]['data'], vals['data'])
44
+ vals['data'] = merged_data
45
+ vals
43
46
  else
44
47
  vals
45
48
  end
@@ -61,23 +64,44 @@ module Coverband
61
64
  merged
62
65
  end
63
66
 
67
+ ###
68
+ # filename_from_key code takes:
69
+ # key: which is a full path the same as reported by Coverage
70
+ # roots: if a collection of all possible full app paths
71
+ # EX: [Coverband.configuration.root_paths, "#{current_root}/"]
72
+ # The LAST item should be the current file system root
73
+ # it expands that expands and adds a '/' as that isn't there from Dir.pwd
74
+ #
75
+ # NOTEs on configuration.root_paths usage
76
+ # strings: matching is pretty simple for full string paths
77
+ # regex: to get regex to work for changing deploy directories
78
+ # the regex must be double escaped in double quotes
79
+ # (if using \d for example)
80
+ # or use single qoutes
81
+ # example: '/box/apps/app_name/releases/\d+/'
82
+ # example: '/var/local/company/company.d/[0-9]*/'
83
+ ###
64
84
  def filename_from_key(key, roots)
65
- filename = key
85
+ relative_filename = key
86
+ local_filename = relative_filename
66
87
  roots.each do |root|
67
- filename = filename.gsub(/^#{root}/, './')
88
+ relative_filename = relative_filename.gsub(/^#{root}/, './')
68
89
  end
69
- # the filename for SimpleCov is expected to be a full path.
90
+ # the filename for our reports is expected to be a full path.
70
91
  # roots.last should be roots << current_root}/
71
92
  # a fully expanded path of config.root
72
- filename = filename.gsub('./', roots.last)
73
- filename
93
+ # filename = filename.gsub('./', roots.last)
94
+ # above only works for app files
95
+ # we need to rethink some of this logic
96
+ # gems aren't at project root and can have multiple locations
97
+ local_root = roots.find { |root| File.exist?(relative_filename.gsub('./', root)) }
98
+ local_root ? relative_filename.gsub('./', local_root) : local_filename
74
99
  end
75
100
 
76
101
  ###
77
102
  # why do we need to merge covered files data?
78
103
  # basically because paths on machines or deployed hosts could be different, so
79
104
  # two different keys could point to the same filename or `line_key`
80
- # this logic should be pushed to base report
81
105
  # TODO: think we are filtering based on ignore while sending to the store
82
106
  # and as we also pull it out here
83
107
  ###
@@ -35,6 +35,10 @@ module Coverband
35
35
  case request.path_info
36
36
  when /.*\.(css|js|gif|png)/
37
37
  @static.call(env)
38
+ when %r{\/settings}
39
+ [200, { 'Content-Type' => 'text/html' }, [settings]]
40
+ when %r{\/debug_data}
41
+ [200, { 'Content-Type' => 'text/json' }, [debug_data]]
38
42
  when %r{\/$}
39
43
  [200, { 'Content-Type' => 'text/html' }, [index]]
40
44
  else
@@ -53,6 +57,14 @@ module Coverband
53
57
  open_report: false)
54
58
  end
55
59
 
60
+ def settings
61
+ Coverband::Utils::HTMLFormatter.new(nil, base_path: base_path).format_settings!
62
+ end
63
+
64
+ def debug_data
65
+ Coverband.configuration.store.coverage.to_json
66
+ end
67
+
56
68
  def collect_coverage
57
69
  Coverband::Collectors::Coverage.instance.report_coverage(true)
58
70
  notice = 'coverband coverage collected'
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Applies the configured groups to the given array of Coverband::SourceFile items
5
+ #
6
+ module Coverband
7
+ module Utils
8
+ class FileGroups
9
+ def initialize(files)
10
+ @grouped = {}
11
+ @files = files
12
+ filter_to_groups
13
+ end
14
+
15
+ def grouped_results
16
+ @grouped
17
+ end
18
+
19
+ private
20
+
21
+ def filter_to_groups
22
+ grouped_files = []
23
+ Coverband.configuration.groups.each do |name, filter|
24
+ if name == 'Gems'
25
+ gem_lists = gem_files(name, filter)
26
+ grouped_files.concat(gem_lists.flatten) if gem_lists.flatten.any?
27
+ else
28
+ app_files(name, filter)
29
+ grouped_files += @grouped[name]
30
+ end
31
+ end
32
+ if !Coverband.configuration.groups.empty? && !(other_files = @files.reject do |source_file|
33
+ grouped_files.include?(source_file)
34
+ end).empty?
35
+ @grouped['Ungrouped'] = Coverband::Utils::FileList.new(other_files)
36
+ end
37
+ end
38
+
39
+ def gem_files(name, filter)
40
+ grouped_gems = @files.select { |source_file| source_file.filename =~ /#{filter}/ }.group_by(&:gem_name)
41
+ gem_lists = grouped_gems.values.map { |gem_files| Coverband::Utils::FileList.new(gem_files) }
42
+ @grouped[name] = Coverband::Utils::GemList.new(gem_lists) if gem_lists.flatten.any?
43
+ gem_lists
44
+ end
45
+
46
+ def app_files(name, filter)
47
+ @grouped[name] = Coverband::Utils::FileList.new(@files.select do |source_file|
48
+ source_file.filename =~ /#{filter}/ && source_file.filename !~ /#{Coverband.configuration.gem_paths.first}/
49
+ end)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ ####
4
+ # An array of FileLists instances with helpers to roll up the stats
5
+ # methods for calculating coverage across them etc.
6
+ ####
7
+ module Coverband
8
+ module Utils
9
+ class GemList < FileList
10
+ # Returns the count of lines that have coverage
11
+ def covered_lines
12
+ to_a.map(&:covered_lines).inject(:+)
13
+ end
14
+
15
+ # Returns the count of lines that have been missed
16
+ def missed_lines
17
+ to_a.map(&:missed_lines).inject(:+)
18
+ end
19
+
20
+ # Returns the count of lines that are not relevant for coverage
21
+ def never_lines
22
+ to_a.map(&:never_lines).inject(:+)
23
+ end
24
+
25
+ # Returns the count of skipped lines
26
+ def skipped_lines
27
+ to_a.map(&:skipped_lines).inject(:+)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -18,7 +18,7 @@ module Coverband
18
18
  def initialize(report, options = {})
19
19
  @notice = options.fetch(:notice) { nil }
20
20
  @base_path = options.fetch(:base_path) { nil }
21
- @coverage_result = Coverband::Utils::Result.new(report)
21
+ @coverage_result = Coverband::Utils::Result.new(report) if report
22
22
  end
23
23
 
24
24
  def format!
@@ -29,8 +29,16 @@ module Coverband
29
29
  format_html(@coverage_result)
30
30
  end
31
31
 
32
+ def format_settings!
33
+ format_settings
34
+ end
35
+
32
36
  private
33
37
 
38
+ def format_settings
39
+ template('settings').result(binding)
40
+ end
41
+
34
42
  def format(result)
35
43
  Dir[File.join(File.dirname(__FILE__), '../../../public/*')].each do |path|
36
44
  FileUtils.cp_r(path, asset_output_path)
@@ -81,17 +89,30 @@ module Coverband
81
89
  def formatted_source_file(source_file)
82
90
  template('source_file').result(binding)
83
91
  rescue Encoding::CompatibilityError => e
84
- puts "Encoding problems with file #{source_file.filename}. Coverband/ERB can't handle non ASCII characters in filenames. Error: #{e.message}."
92
+ puts "Encoding error file:#{source_file.filename} Coverband/ERB error #{e.message}."
85
93
  end
86
94
 
87
95
  # Returns a table containing the given source files
88
- def formatted_file_list(title, source_files)
96
+ def formatted_file_list(title, source_files, options = {})
89
97
  title_id = title.gsub(/^[^a-zA-Z]+/, '').gsub(/[^a-zA-Z0-9\-\_]/, '')
90
98
  # Silence a warning by using the following variable to assign to itself:
91
99
  # "warning: possibly useless use of a variable in void context"
92
100
  # The variable is used by ERB via binding.
93
101
  title_id = title_id
94
- template('file_list').result(binding)
102
+ options = options
103
+ if title == 'Gems'
104
+ template('gem_list').result(binding)
105
+ else
106
+ template('file_list').result(binding)
107
+ end
108
+ end
109
+
110
+ def view_gems?
111
+ Coverband.configuration.track_gems
112
+ end
113
+
114
+ def gem_details?
115
+ Coverband.configuration.gem_details
95
116
  end
96
117
 
97
118
  def coverage_css_class(covered_percent)
@@ -123,10 +144,13 @@ module Coverband
123
144
  "<abbr class=\"timeago\" title=\"#{time.iso8601}\">#{time.iso8601}</abbr>"
124
145
  end
125
146
 
126
- # a bug that existed in simplecov was not checking that root was at the start of the file name
127
- # I had previously patched this in my local Rails app
128
147
  def shortened_filename(source_file)
129
- source_file.filename.sub(%r{^#{Coverband.configuration.root}}, '.').gsub(/^\.\//, '')
148
+ source_file.short_name
149
+ end
150
+
151
+ def link_to_gem_list(gem_name)
152
+ gem_id = gem_name.gsub(/^[^a-zA-Z]+/, '').gsub(/[^a-zA-Z0-9\-\_]/, '')
153
+ %(<a href="##{gem_id}" class="gem-link" title="#{gem_name}">#{gem_name}</a>)
130
154
  end
131
155
 
132
156
  def link_to_source_file(source_file)
@@ -14,26 +14,28 @@ module Coverband
14
14
  module Utils
15
15
  class Result
16
16
  extend Forwardable
17
- # Returns the original Coverage.result used for this instance of SimpleCov::Result
17
+ # Returns the original Coverage.result used for this instance of Coverband::Result
18
18
  attr_reader :original_result
19
- # Returns all files that are applicable to this result (sans filters!) as instances of SimpleCov::SourceFile. Aliased as :source_files
19
+ # Returns all files that are applicable to this result (sans filters!)
20
+ # as instances of Coverband::SourceFile. Aliased as :source_files
20
21
  attr_reader :files
21
22
  alias source_files files
22
23
  # Explicitly set the Time this result has been created
23
24
  attr_writer :created_at
24
- # Explicitly set the command name that was used for this coverage result. Defaults to SimpleCov.command_name
25
+ # Explicitly set the command name that was used for this coverage result.
26
+ # Defaults to Coverband.command_name
25
27
  attr_writer :command_name
26
28
 
27
29
  def_delegators :files, :covered_percent, :covered_percentages, :least_covered_file, :covered_strength, :covered_lines, :missed_lines
28
30
  def_delegator :files, :lines_of_code, :total_lines
29
31
 
30
- # Initialize a new SimpleCov::Result from given Coverage.result (a Hash of filenames each containing an array of
32
+ # Initialize a new Coverband::Result from given Coverage.result (a Hash of filenames each containing an array of
31
33
  # coverage data)
32
34
  def initialize(original_result)
33
35
  @original_result = original_result.freeze
34
36
  @files = Coverband::Utils::FileList.new(original_result.map do |filename, coverage|
35
37
  Coverband::Utils::SourceFile.new(filename, coverage) if File.file?(filename)
36
- end.compact.sort_by(&:filename))
38
+ end.compact.sort_by(&:short_name))
37
39
  filter!
38
40
  end
39
41
 
@@ -42,15 +44,9 @@ module Coverband
42
44
  files.map(&:filename)
43
45
  end
44
46
 
45
- # Returns a Hash of groups for this result. Define groups using SimpleCov.add_group 'Models', 'app/models'
46
- # Coverband doesn't currently support groups
47
+ # Returns a Hash of groups for this result. Define groups using Coverband.add_group 'Models', 'app/models'
47
48
  def groups
48
- @groups ||= [] # SimpleCov.grouped(files)
49
- end
50
-
51
- # Applies the configured SimpleCov.formatter on this result
52
- def format!
53
- # SimpleCov.formatter.new.format(self)
49
+ @groups ||= FileGroups.new(files).grouped_results
54
50
  end
55
51
 
56
52
  # Defines when this result has been created. Defaults to Time.now
@@ -59,9 +55,9 @@ module Coverband
59
55
  end
60
56
 
61
57
  # The command name that launched this result.
62
- # Delegated to SimpleCov.command_name if not set manually
58
+ # Delegated to Coverband.command_name if not set manually
63
59
  def command_name
64
- @command_name ||= 'SimpleCov.command_name'
60
+ @command_name ||= 'Coverband'
65
61
  end
66
62
 
67
63
  # Returns a hash representation of this Result that can be used for marshalling it into JSON
@@ -69,7 +65,7 @@ module Coverband
69
65
  { command_name => { 'coverage' => coverage, 'timestamp' => created_at.to_i } }
70
66
  end
71
67
 
72
- # Loads a SimpleCov::Result#to_hash dump
68
+ # Loads a Coverband::Result#to_hash dump
73
69
  def self.from_hash(hash)
74
70
  command_name, data = hash.first
75
71
  result = new(data['coverage'])
@@ -100,7 +96,7 @@ module Coverband
100
96
  Hash[keys.zip(original_result.values_at(*keys))]
101
97
  end
102
98
 
103
- # Applies all configured SimpleCov filters on this result's source files
99
+ # Applies all configured Coverband filters on this result's source files
104
100
  def filter!
105
101
  @files = files
106
102
  end
@@ -133,7 +133,7 @@ module Coverband
133
133
 
134
134
  # Warning to identify condition from Issue #56
135
135
  def coverage_exceeding_source_warn
136
- warn "Warning: coverage data provided by Coverage [#{coverage.size}] exceeds number of lines in #{filename} [#{src.size}]"
136
+ warn "Warning: coverage data from Coverage [#{coverage.size}] exceeds line count in #{filename} [#{src.size}]"
137
137
  end
138
138
 
139
139
  # Access SimpleCov::SourceFile::Line source lines by line number
@@ -210,6 +210,23 @@ module Coverband
210
210
  end
211
211
  end
212
212
 
213
+ # a bug that existed in simplecov was not checking that root
214
+ # was at the start of the file name
215
+ # I had previously patched this in my local Rails app
216
+ def short_name
217
+ filename.sub(/^#{Coverband.configuration.root}/, '.')
218
+ .sub(%r{^.*\/gems}, '.')
219
+ .gsub(%r{^\.\/}, '')
220
+ end
221
+
222
+ def gem?
223
+ filename =~ %r{^.*\/gems\/}
224
+ end
225
+
226
+ def gem_name
227
+ gem? ? short_name.split('/').first : nil
228
+ end
229
+
213
230
  private
214
231
 
215
232
  # ruby 1.9 could use Float#round(places) instead
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Coverband
4
- VERSION = '4.1.0.alpha'
4
+ VERSION = '4.1.0.beta'
5
5
  end
@@ -1684,24 +1684,37 @@ $(document).ready(function() {
1684
1684
  if (!$(this).parent().hasClass('active')) {
1685
1685
  $('.group_tabs a').parent().removeClass('active');
1686
1686
  $(this).parent().addClass('active');
1687
- $('.file_list_container').hide();
1688
- $(".file_list_container" + $(this).attr('href')).show();
1689
- window.location.href = window.location.href.split('#')[0] + $(this).attr('href').replace('#', '#_');
1690
-
1691
- // Force favicon reload - otherwise the location change containing anchor would drop the favicon...
1692
- // Works only on firefox, but still... - Anyone know a better solution to force favicon on local file?
1693
- $('link[rel="shortcut icon"]').remove();
1694
- $('head').append('<link rel="shortcut icon" type="image/png" href="'+ favicon_path +'" />');
1695
1687
  };
1688
+ $('.file_list_container').hide();
1689
+ $(".file_list_container" + $(this).attr('href')).show();
1690
+ window.location.href = window.location.href.split('#')[0] + $(this).attr('href').replace('#', '#_');
1691
+
1692
+ // Force favicon reload - otherwise the location change containing anchor would drop the favicon...
1693
+ // Works only on firefox, but still... - Anyone know a better solution to force favicon on local file?
1694
+ $('link[rel="shortcut icon"]').remove();
1695
+ $('head').append('<link rel="shortcut icon" type="image/png" href="'+ favicon_path +'" />');
1696
+ return false;
1697
+ });
1698
+
1699
+ $('a.gem-link').live('click', function(){
1700
+ $('.file_list_container').hide();
1701
+ $(".file_list_container" + $(this).attr('href')).show();
1702
+ window.location.href = window.location.href.split('#')[0] + $(this).attr('href').replace('#', '#_');
1696
1703
  return false;
1697
1704
  });
1698
1705
 
1699
1706
  if (jQuery.url.attr('anchor')) {
1700
1707
  var anchor = jQuery.url.attr('anchor')
1708
+ // source file hash
1701
1709
  if (anchor.length == 40) {
1702
1710
  $('a.src_link[href=#' + anchor + ']').click();
1703
1711
  } else {
1704
- $('.group_tabs a.'+anchor.replace('_', '')).click();
1712
+ if ($('.group_tabs a.'+anchor.replace('_', '')).length > 0) {
1713
+ $('.group_tabs a.'+anchor.replace('_', '')).click();
1714
+ } else {
1715
+ $('a.gem-link[href=#' + anchor.replace('_', '') + ']').click();
1716
+ }
1717
+
1705
1718
  }
1706
1719
  } else {
1707
1720
  $('.group_tabs a:first').click();
@@ -95,6 +95,10 @@ def source_fixture(filename)
95
95
  File.expand_path(File.join(File.dirname(__FILE__), 'fixtures', filename))
96
96
  end
97
97
 
98
+ def test_root
99
+ File.expand_path(File.join(File.dirname(__FILE__)))
100
+ end
101
+
98
102
  # Taken from http://stackoverflow.com/questions/4459330/how-do-i-temporarily-redirect-stderr-in-ruby
99
103
  def capture_stderr
100
104
  # The output stream must be an IO-like object. In this case we capture it in
@@ -21,6 +21,17 @@ class BaseTest < Minitest::Test
21
21
  assert_equal ['vendor', 'internal:prelude', 'schema.rb'], coverband.instance_variable_get('@ignore_patterns')
22
22
  end
23
23
 
24
+ test 'gem_paths ' do
25
+ Coverband::Collectors::Coverage.instance.reset_instance
26
+ assert Coverband.configuration.gem_paths.first != nil
27
+ end
28
+
29
+ test 'groups ' do
30
+ Coverband::Collectors::Coverage.instance.reset_instance
31
+ Coverband.configuration.track_gems = true
32
+ assert_equal %w(App Gems), Coverband.configuration.groups.keys
33
+ end
34
+
24
35
  test 's3 options' do
25
36
  Coverband::Collectors::Coverage.instance.reset_instance
26
37
  Coverband.configure do |config|
@@ -38,6 +38,19 @@ class FullStackTest < Minitest::Test
38
38
  assert_equal expected, Coverband.configuration.store.coverage[@rack_file]['data']
39
39
  end
40
40
 
41
+ test 'call app with gem tracking' do
42
+ Coverband.configuration.track_gems = true
43
+ Coverband::Collectors::Coverage.instance.reset_instance
44
+ require 'rainbow'
45
+ Rainbow('this text is red').red
46
+ request = Rack::MockRequest.env_for('/anything.json')
47
+ middleware = Coverband::Middleware.new(fake_app_with_lines)
48
+ results = middleware.call(request)
49
+ assert_equal 'Hello Rack!', results.last
50
+ sleep(0.1)
51
+ assert Coverband.configuration.store.coverage.keys.any? { |key| key.end_with?('rainbow/null_presenter.rb') }
52
+ end
53
+
41
54
  private
42
55
 
43
56
  def fake_app_with_lines
@@ -8,7 +8,7 @@ class RailsFullStackTest < Minitest::Test
8
8
 
9
9
  def setup
10
10
  super
11
- #The normal relative directory lookup of coverband won't work for our dummy rails project
11
+ # The normal relative directory lookup of coverband won't work for our dummy rails project
12
12
  Coverband.configure("./test/rails#{Rails::VERSION::MAJOR}_dummy/config/coverband.rb")
13
13
  Coverband.start
14
14
  end
@@ -24,7 +24,7 @@ class RailsFullStackTest < Minitest::Test
24
24
  assert_content('I am no dummy')
25
25
  sleep 0.2
26
26
  visit '/coverage'
27
- within page.find('a', text: /dummy_controller.rb/).find(:xpath, "../..") do
27
+ within page.find('a', text: /dummy_controller.rb/).find(:xpath, '../..') do
28
28
  assert_selector('td', text: '100.0 %')
29
29
  end
30
30
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('../rails_test_helper', File.dirname(__FILE__))
4
+
5
+ class RailsGemsFullStackTest < Minitest::Test
6
+ include Capybara::DSL
7
+ include Capybara::Minitest::Assertions
8
+
9
+ def setup
10
+ super
11
+ # The normal relative directory lookup of coverband won't work for our dummy rails project
12
+ Coverband.configure("./test/rails#{Rails::VERSION::MAJOR}_dummy/config/coverband.rb")
13
+ Coverband.configuration.track_gems = true
14
+ Coverband.configuration.gem_details = true
15
+ Coverband.start
16
+ require 'rainbow'
17
+ Rainbow('this text is red').red
18
+ end
19
+
20
+ def teardown
21
+ super
22
+ Capybara.reset_sessions!
23
+ Capybara.use_default_driver
24
+ end
25
+
26
+ test 'this is how gem it' do
27
+ visit '/dummy/show'
28
+ assert_content('I am no dummy')
29
+ sleep 0.2
30
+ visit '/coverage'
31
+ assert_content('Coverband Admin')
32
+ assert_content('Gems')
33
+ assert page.html.match('rainbow/wrapper.rb')
34
+ end
35
+ end
@@ -14,36 +14,46 @@ class ReportsBaseTest < Minitest::Test
14
14
  roots = ['/app/', '/full/remote_app/path/']
15
15
 
16
16
  expected_path = '/full/remote_app/path/is/a/path.rb'
17
+ File.expects(:exist?).with(key).returns(false)
18
+ File.expects(:exist?).with(expected_path).returns(true)
17
19
  assert_equal expected_path, Coverband::Reporters::Base.send(:filename_from_key, key, roots)
18
20
  end
19
21
 
20
- test 'filename_from_key fix filename a changing deploy path with double quotes' do
22
+ test 'filename_from_key fix filename a changing deploy path with quotes' do
21
23
  Coverband.configure do |config|
22
24
  config.reporter = 'std_out'
23
25
  config.root = '/full/remote_app/path'
24
26
  end
25
27
 
26
- key = '/box/apps/app_name/releases/20140725203539/app/models/user.rb'
27
- # the code takes config.root expands and adds a '/' for the final path in roots
28
- # note to get regex to work for changing deploy directories it must be double escaped in double quotes or use single qoutes
29
- roots = ['/box/apps/app_name/releases/\\d+/', '/full/remote_app/path/']
30
-
31
28
  expected_path = '/full/remote_app/path/app/models/user.rb'
29
+ key = '/box/apps/app_name/releases/20140725203539/app/models/user.rb'
30
+ roots = ["/box/apps/app_name/releases/\\d+/", '/full/remote_app/path/']
31
+ File.expects(:exist?).with('/box/apps/app_name/releases/\\d+/app/models/user.rb').returns(false)
32
+ File.expects(:exist?).with(expected_path).returns(true)
33
+ assert_equal expected_path, Coverband::Reporters::Base.send(:filename_from_key, key, roots)
34
+ File.expects(:exist?).with('/box/apps/app_name/releases/\\d+/app/models/user.rb').returns(false)
35
+ File.expects(:exist?).with(expected_path).returns(true)
36
+ roots = ['/box/apps/app_name/releases/\d+/', '/full/remote_app/path/']
32
37
  assert_equal expected_path, Coverband::Reporters::Base.send(:filename_from_key, key, roots)
33
38
  end
34
39
 
35
- test 'filename_from_key fix filename a changing deploy path with single quotes' do
40
+ test 'filename_from_key fix filename a changing deploy path real world examples' do
41
+ current_app_root = '/var/local/company/company.d/79'
36
42
  Coverband.configure do |config|
37
43
  config.reporter = 'std_out'
38
- config.root = '/full/remote_app/path'
44
+ config.root = current_app_root
39
45
  end
40
46
 
41
- key = '/box/apps/app_name/releases/20140725203539/app/models/user.rb'
42
- # the code takes config.root expands and adds a '/' for the final path in roots
43
- # note to get regex to work for changing deploy directories it must be double escaped in double quotes or use single qoutes
44
- roots = ['/box/apps/app_name/releases/\d+/', '/full/remote_app/path/']
47
+ expected_path = '/var/local/company/company.d/79/app/controllers/dashboard_controller.rb'
48
+ key = '/var/local/company/company.d/78/app/controllers/dashboard_controller.rb'
45
49
 
46
- expected_path = '/full/remote_app/path/app/models/user.rb'
50
+ File.expects(:exist?).with('/var/local/company/company.d/[0-9]*/app/controllers/dashboard_controller.rb').returns(false)
51
+ File.expects(:exist?).with(expected_path).returns(true)
52
+ roots = ['/var/local/company/company.d/[0-9]*/', "#{current_app_root}/"]
53
+ assert_equal expected_path, Coverband::Reporters::Base.send(:filename_from_key, key, roots)
54
+ File.expects(:exist?).with('/var/local/company/company.d/[0-9]*/app/controllers/dashboard_controller.rb').returns(false)
55
+ File.expects(:exist?).with(expected_path).returns(true)
56
+ roots = ["/var/local/company/company.d/[0-9]*/", "#{current_app_root}/"]
47
57
  assert_equal expected_path, Coverband::Reporters::Base.send(:filename_from_key, key, roots)
48
58
  end
49
59
 
@@ -92,7 +102,6 @@ class ReportsBaseTest < Minitest::Test
92
102
 
93
103
  Coverband.configure do |config|
94
104
  config.reporter = 'std_out'
95
- config.ignore = %w(vendor .erb$ .slim$)
96
105
  config.root = '/full/remote_app/path'
97
106
  config.store = store
98
107
  end
@@ -106,4 +115,54 @@ class ReportsBaseTest < Minitest::Test
106
115
 
107
116
  assert_equal expected, Coverband::Reporters::Base.send(:get_current_scov_data_imp, store, roots)
108
117
  end
118
+
119
+ ###
120
+ # This test uses real world example data which helped uncover a bug
121
+ # The copied data doesn't format easily and isn't worth the effort to meet
122
+ # string style
123
+ # rubocop:disable all
124
+ ###
125
+ test '#get_current_scov_data_imp merges multiples of file data' do
126
+ coverage = {'/base/66/app/controllers/dashboard_controller.rb' =>
127
+ {"first_updated_at"=>1549610119,
128
+ "last_updated_at"=>1549610200,
129
+ "file_hash"=>"14dc84e940e26cbfb9ac79b43862e762",
130
+ "data"=>[1, 1, 1, nil, 1, 1, nil, nil, 1, nil, 1, 26, 26, nil, 26, 26, 26, 26, 26, 26, 26, nil, nil, 1, nil, 1, 26, 19, 0, 0, 0, 0, nil, nil, nil, nil, 0, 0, nil, nil, 1, 26, 26, 26, nil, nil, nil, nil, nil, 1, 26, nil, nil, 1, 26, nil, nil]},
131
+ '/base/78/app/controllers/dashboard_controller.rb' =>
132
+ {"first_updated_at"=>1549658574,
133
+ "last_updated_at"=>1549729830,
134
+ "file_hash"=>"14dc84e940e26cbfb9ac79b43862e762",
135
+ "data"=>[21, 21, 21, nil, 21, 21, nil, nil, 21, nil, 21, 22, 22, nil, 22, 22, 22, 22, 22, 22, 22, nil, nil, 21, nil, 21, 22, 13, 0, 0, 0, 0, nil, nil, nil, nil, 0, 0, nil, nil, 21, 22, 22, 22, nil, nil, nil, nil, nil, 21, 22, nil, nil, 21, 22, nil, nil]},
136
+ '/base/70/app/controllers/dashboard_controller.rb' =>
137
+ {"first_updated_at"=>1549617873,
138
+ "last_updated_at"=>1549618094,
139
+ "file_hash"=>"14dc84e940e26cbfb9ac79b43862e762",
140
+ "data"=>[16, 16, 16, nil, 16, 16, nil, nil, 16, nil, 16, 32, 32, nil, 32, 32, 32, 32, 32, 32, 32, nil, nil, 16, nil, 16, 32, 23, 0, 0, 0, 0, nil, nil, nil, nil, 0, 0, nil, nil, 16, 32, 32, 32, nil, nil, nil, nil, nil, 16, 32, nil, nil, 16, 32, nil, nil]}
141
+ }
142
+ @redis = Redis.new
143
+ store = Coverband::Adapters::RedisStore.new(@redis)
144
+ store.clear!
145
+
146
+ Coverband.configure do |config|
147
+ config.reporter = 'std_out'
148
+ config.root = '/base/78/app/'
149
+ config.store = store
150
+ end
151
+
152
+ key = '/base/78/app/app/controllers/dashboard_controller.rb'
153
+ roots = ['/base/[0-9]*/', '/base/78/app/']
154
+
155
+ lines_hit = [1, 3, 6]
156
+ store.stubs(:coverage).returns(coverage)
157
+ File.expects(:exist?).at_least_once
158
+ .with('/base/[0-9]*/app/controllers/dashboard_controller.rb')
159
+ .returns(false)
160
+ File.expects(:exist?).at_least_once.with(key).returns(true)
161
+
162
+ expected = {"first_updated_at"=>1549617873,
163
+ "last_updated_at"=>1549618094,
164
+ "file_hash"=>"14dc84e940e26cbfb9ac79b43862e762",
165
+ "data"=>[38, 38, 38, nil, 38, 38, nil, nil, 38, nil, 38, 80, 80, nil, 80, 80, 80, 80, 80, 80, 80, nil, nil, 38, nil, 38, 80, 55, 0, 0, 0, 0, nil, nil, nil, nil, 0, 0, nil, nil, 38, 80, 80, 80, nil, nil, nil, nil, nil, 38, 80, nil, nil, 38, 80, nil, nil]}
166
+ assert_equal expected, Coverband::Reporters::Base.send(:get_current_scov_data_imp, store, roots)[key]
167
+ end
109
168
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('../../test_helper', File.dirname(__FILE__))
4
+
5
+ describe Coverband::Utils::FileGroups do
6
+ FAKE_GEM_PATH = 'fake/gem/path'
7
+ subject do
8
+ controller_lines = [nil, 2, 2, 0, nil, nil, 0, nil, nil, nil]
9
+ files = [
10
+ Coverband::Utils::SourceFile.new(source_fixture('sample.rb'), [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil]),
11
+ Coverband::Utils::SourceFile.new(source_fixture('app/models/user.rb'), [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil]),
12
+ Coverband::Utils::SourceFile.new(source_fixture('app/controllers/sample_controller.rb'), controller_lines),
13
+ Coverband::Utils::SourceFile.new("#{FAKE_GEM_PATH}/gem_name.rb", controller_lines)
14
+ ]
15
+ Coverband.configuration.expects(:gem_paths).at_least_once.returns([FAKE_GEM_PATH])
16
+ Coverband.configuration.track_gems = true
17
+ Coverband::Utils::FileGroups.new(files)
18
+ end
19
+
20
+ it 'has app files' do
21
+ assert_equal 'test/fixtures/sample.rb', subject.grouped_results['App'].first.short_name
22
+ end
23
+
24
+ it 'has gem files' do
25
+ assert_equal "#{FAKE_GEM_PATH}/gem_name.rb", subject.grouped_results['Gems'].first.first.short_name
26
+ end
27
+ end
28
+
29
+ describe Coverband::Utils::FileGroups, :vendored_gems do
30
+ FAKE_VENDOR_GEM_PATH = "#{test_root}/app/vendor/bundle/ruby/2.5.0/gems"
31
+ subject do
32
+ controller_lines = [nil, 2, 2, 0, nil, nil, 0, nil, nil, nil]
33
+ files = [
34
+ Coverband::Utils::SourceFile.new(source_fixture('sample.rb'), [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil]),
35
+ Coverband::Utils::SourceFile.new(source_fixture('app/models/user.rb'), [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil]),
36
+ Coverband::Utils::SourceFile.new(source_fixture('app/controllers/sample_controller.rb'), controller_lines),
37
+ Coverband::Utils::SourceFile.new("#{FAKE_VENDOR_GEM_PATH}/gem_name.rb", controller_lines)
38
+ ]
39
+ Coverband.configuration.expects(:gem_paths).at_least_once.returns([FAKE_VENDOR_GEM_PATH])
40
+ Coverband.configuration.track_gems = true
41
+ Coverband::Utils::FileGroups.new(files)
42
+ end
43
+
44
+ it 'has app files' do
45
+ assert_equal 'test/fixtures/sample.rb', subject.grouped_results['App'].first.short_name
46
+ end
47
+
48
+ it "doesn't include vendor gems in app files app files" do
49
+ assert_nil subject.grouped_results['App'].select { |files| files.short_name.match(/gem_name/) }.first
50
+ end
51
+
52
+ it 'does has gem files' do
53
+ assert_equal 'gem_name.rb', subject.grouped_results['Gems'].first.first.short_name
54
+ end
55
+ end
@@ -6,7 +6,7 @@ require File.expand_path('../../test_helper', File.dirname(__FILE__))
6
6
  # Thanks for all the help SimpleCov https://github.com/colszowka/simplecov-html
7
7
  # initial version of test pulled into Coverband from Simplecov 12/19/2018
8
8
  ####
9
- describe Coverband::Utils::Result do
9
+ describe Coverband::Utils::FileList do
10
10
  subject do
11
11
  original_result = {
12
12
  source_fixture('sample.rb') => [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil],
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('../../test_helper', File.dirname(__FILE__))
4
+
5
+ ####
6
+ # Thanks for all the help SimpleCov https://github.com/colszowka/simplecov-html
7
+ # initial version of test pulled into Coverband from Simplecov 12/19/2018
8
+ ####
9
+ describe Coverband::Utils::GemList do
10
+ subject do
11
+ controller_lines = [nil, 2, 2, 0, nil, nil, 0, nil, nil, nil]
12
+ gem_files = [
13
+ Coverband::Utils::SourceFile.new(source_fixture('sample.rb'), [nil, 1, 1, 1, nil, nil, 1, 1, nil, nil]),
14
+ Coverband::Utils::SourceFile.new(source_fixture('app/models/user.rb'), [nil, 1, 1, 1, nil, nil, 1, 0, nil, nil]),
15
+ Coverband::Utils::SourceFile.new(source_fixture('app/controllers/sample_controller.rb'), controller_lines)
16
+ ]
17
+ gem_lists = [Coverband::Utils::FileList.new(gem_files), Coverband::Utils::FileList.new(gem_files)]
18
+ Coverband::Utils::GemList.new(gem_lists)
19
+ end
20
+
21
+ it 'has 22 covered lines' do
22
+ assert_equal 22, subject.covered_lines
23
+ end
24
+
25
+ it 'has 6 missed lines' do
26
+ assert_equal 6, subject.missed_lines
27
+ end
28
+
29
+ it 'has 34 never lines' do
30
+ assert_equal 34, subject.never_lines
31
+ end
32
+
33
+ it 'has 28 lines of code' do
34
+ assert_equal 28, subject.lines_of_code
35
+ end
36
+
37
+ it 'has 10 skipped lines' do
38
+ assert_equal 10, subject.skipped_lines
39
+ end
40
+
41
+ it 'has the correct covered percent' do
42
+ assert_equal 78.57142857142857, subject.covered_percent
43
+ end
44
+
45
+ it 'has the correct covered strength' do
46
+ assert_equal 0.9285714285714286, subject.covered_strength
47
+ end
48
+ end
@@ -79,7 +79,7 @@ describe Coverband::Utils::SourceFile do
79
79
  subject.lines
80
80
  end
81
81
 
82
- assert(captured_output.match(/^Warning: coverage data provided/))
82
+ assert(captured_output.match(/^Warning: coverage data/))
83
83
  end
84
84
  end
85
85
 
@@ -1,18 +1,20 @@
1
1
  <div class="file_list_container" id="<%= title_id %>">
2
- <h2>
3
- <span class="group_name"><%= title %></span>
4
- (<span class="covered_percent"><span class="<%= coverage_css_class(source_files.covered_percent) %>"><%= source_files.covered_percent.round(2) %>%</span></span>
5
- covered at
6
- <span class="covered_strength">
7
- <span class="<%= strength_css_class(source_files.covered_strength) %>">
8
- <%= source_files.covered_strength.round(2) %>
9
- </span>
10
- </span> hits/line)
11
- </h2>
2
+ <% unless options[:skip_nav] %>
3
+ <h2>
4
+ <span class="group_name"><%= title %></span>
5
+ (<span class="covered_percent"><span class="<%= coverage_css_class(source_files.covered_percent) %>"><%= source_files.covered_percent.round(2) %>%</span></span>
6
+ covered at
7
+ <span class="covered_strength">
8
+ <span class="<%= strength_css_class(source_files.covered_strength) %>">
9
+ <%= source_files.covered_strength.round(2) %>
10
+ </span>
11
+ </span> hits/line)
12
+ </h2>
13
+ <% end %>
12
14
  <a name="<%= title_id %>"></a>
13
15
  <div>
14
16
  <b><%= source_files.length %></b> files in total.
15
- <b><%= source_files.lines_of_code %></b> relevant lines.
17
+ <b><%= source_files.lines_of_code %></b> relevant lines.
16
18
  <span class="green"><b><%= source_files.covered_lines %></b> lines covered</span> and
17
19
  <span class="red"><b><%= source_files.missed_lines %></b> lines missed </span>
18
20
  </div>
@@ -30,15 +32,17 @@
30
32
  </thead>
31
33
  <tbody>
32
34
  <% source_files.each do |source_file| %>
33
- <tr>
34
- <td class="strong"><%= link_to_source_file(source_file) %></td>
35
- <td class="<%= coverage_css_class(source_file.covered_percent) %> strong"><%= source_file.covered_percent.round(2).to_s %> %</td>
36
- <td><%= source_file.lines.count %></td>
37
- <td><%= source_file.covered_lines.count + source_file.missed_lines.count %></td>
38
- <td><%= source_file.covered_lines.count %></td>
39
- <td><%= source_file.missed_lines.count %></td>
40
- <td><%= source_file.covered_strength %></td>
41
- </tr>
35
+ <tr>
36
+ <td class="strong">
37
+ <%= link_to_source_file(source_file) %>
38
+ </td>
39
+ <td class="<%= coverage_css_class(source_file.covered_percent) %> strong"><%= source_file.covered_percent.round(2).to_s %> %</td>
40
+ <td><%= source_file.lines.count %></td>
41
+ <td><%= source_file.covered_lines.count + source_file.missed_lines.count %></td>
42
+ <td><%= source_file.covered_lines.count %></td>
43
+ <td><%= source_file.missed_lines.count %></td>
44
+ <td><%= source_file.covered_strength %></td>
45
+ </tr>
42
46
  <% end %>
43
47
  </tbody>
44
48
  </table>
@@ -0,0 +1,54 @@
1
+ <div class="file_list_container" id="<%= title_id %>">
2
+ <h2>
3
+ <span class="group_name"><%= title %></span>
4
+ (<span class="covered_percent"><span class="<%= coverage_css_class(source_files.covered_percent) %>"><%= source_files.covered_percent.round(2) %>%</span></span>
5
+ covered at
6
+ <span class="covered_strength">
7
+ <span class="<%= strength_css_class(source_files.covered_strength) %>">
8
+ <%= source_files.covered_strength.round(2) %>
9
+ </span>
10
+ </span> hits/line)
11
+ </h2>
12
+ <div>
13
+ <b><%= source_files.length %></b> files in total.
14
+ <b><%= source_files.lines_of_code %></b> relevant lines.
15
+ <span class="green"><b><%= source_files.covered_lines %></b> lines covered</span> and
16
+ <span class="red"><b><%= source_files.missed_lines %></b> lines missed </span>
17
+ </div>
18
+ <table class="gem_list">
19
+ <thead>
20
+ <tr>
21
+ <th>Gem</th>
22
+ <th>% covered</th>
23
+ <th>Relevant Lines</th>
24
+ <th>Lines covered</th>
25
+ <th>Lines missed</th>
26
+ <th>Avg. Hits / Line</th>
27
+ </tr>
28
+ </thead>
29
+ <tbody>
30
+ <% source_files.each do |source_file| %>
31
+ <tr>
32
+ <td class="strong">
33
+ <% if gem_details? %>
34
+ <%= link_to_gem_list(source_file.first.gem_name) %>
35
+ <% else %>
36
+ <%= source_file.first.gem_name %>
37
+ <% end %>
38
+ </td>
39
+ <td class="<%= coverage_css_class(source_file.covered_percent) %> strong"><%= source_file.covered_percent.round(2).to_s %> %</td>
40
+ <td><%= source_file.covered_lines + source_file.missed_lines %></td>
41
+ <td><%= source_file.covered_lines %></td>
42
+ <td><%= source_file.missed_lines %></td>
43
+ <td><%= source_file.covered_strength %></td>
44
+ </tr>
45
+ <% end %>
46
+ </tbody>
47
+ </table>
48
+ </div>
49
+
50
+ <% if gem_details? %>
51
+ <% source_files.each do |gem_files| %>
52
+ <%= formatted_file_list(gem_files.first.gem_name, gem_files, skip_nav: true) %>
53
+ <% end %>
54
+ <% end %>
@@ -16,11 +16,15 @@
16
16
  <div id="wrapper" style="display:none;">
17
17
  <div id="header">
18
18
  <a href='<%= base_path %>'>Coverband Admin</a> &nbsp;
19
+ <a href='<%= base_path %>settings'>Settings</a> &nbsp;
19
20
  <%= button("#{base_path}collect_coverage", 'force coverage collection') %> &nbsp;
20
21
  <%= button("#{base_path}reload_files", 'reload Coverband files') %> &nbsp;
21
22
  <% if Coverband.configuration.web_enable_clear %>
22
23
  <%= button("#{base_path}clear", 'clear coverage report', delete: true) %>
23
24
  <% end %>
25
+ <% if Coverband.configuration.web_debug %>
26
+ <a href='<%= base_path %>debug_data'>Debug Data</a> &nbsp;
27
+ <% end %>
24
28
  </div>
25
29
  <% if notice.to_s.length > 0 %>
26
30
  <div class="notice"><%= notice %></div>
@@ -29,7 +33,7 @@
29
33
  <ul class="group_tabs"></ul>
30
34
 
31
35
  <div id="content">
32
- <%= formatted_file_list("All Files", result.source_files) %>
36
+ <%= formatted_file_list("All Files", result.source_files) unless view_gems? %>
33
37
 
34
38
  <% result.groups.each do |name, files| %>
35
39
  <%= formatted_file_list(name, files) %>
@@ -42,7 +46,9 @@
42
46
 
43
47
  <div class="source_files">
44
48
  <% result.source_files.each do |source_file| %>
45
- <%= formatted_source_file(source_file) %>
49
+ <% if (!source_file.gem? || (view_gems? && gem_details? && source_file.gem? )) %>
50
+ <%= formatted_source_file(source_file) %>
51
+ <% end %>
46
52
  <% end %>
47
53
  </div>
48
54
  </div>
@@ -0,0 +1,30 @@
1
+ <!DOCTYPE html>
2
+ <html xmlns='http://www.w3.org/1999/xhtml'>
3
+ <head>
4
+ <title>Coverband Settings: <%= Coverband::VERSION %></title>
5
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
6
+ <script src='<%= assets_path('application.js') %>' type='text/javascript'></script>
7
+ <link href='<%= assets_path('application.css') %>' media='screen, projection, print' rel='stylesheet' type='text/css'>
8
+ <link rel="icon" type="image/png" href="<%= assets_path('favicon.png') %>" />
9
+ </head>
10
+
11
+ <body>
12
+ <div id="wrapper" style="">
13
+ <div id="header">
14
+ <a href='<%= base_path %>'>Coverband Admin</a> &nbsp;
15
+ <a href='<%= base_path %>settings'>Settings</a> &nbsp;
16
+ </div>
17
+ <div id="content">
18
+ <dl>
19
+ <% Coverband.configuration.to_h.each_pair do |key,value| %>
20
+ <dt><%= key %></dt>
21
+ <dd><%= value %></dd>
22
+ <% end %>
23
+ </dl>
24
+ </div>
25
+ <div id="footer">
26
+ Generated by <a href="http://github.com/danmayer/coverband">Coverband</a> v<%= Coverband::VERSION %>
27
+ </div>
28
+ </div>
29
+ </body>
30
+ </html>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coverband
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0.alpha
4
+ version: 4.1.0.beta
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Mayer
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-02-02 00:00:00.000000000 Z
12
+ date: 2019-02-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: aws-sdk-s3
@@ -255,7 +255,9 @@ files:
255
255
  - lib/coverband/reporters/console_report.rb
256
256
  - lib/coverband/reporters/html_report.rb
257
257
  - lib/coverband/reporters/web.rb
258
+ - lib/coverband/utils/file_groups.rb
258
259
  - lib/coverband/utils/file_list.rb
260
+ - lib/coverband/utils/gem_list.rb
259
261
  - lib/coverband/utils/html_formatter.rb
260
262
  - lib/coverband/utils/lines_classifier.rb
261
263
  - lib/coverband/utils/railtie.rb
@@ -329,20 +331,25 @@ files:
329
331
  - test/unit/middleware_test.rb
330
332
  - test/unit/rack_server_checkout_test.rb
331
333
  - test/unit/rails_full_stack_test.rb
334
+ - test/unit/rails_gems_full_stack_test.rb
332
335
  - test/unit/reports_base_test.rb
333
336
  - test/unit/reports_console_test.rb
334
337
  - test/unit/reports_html_test.rb
335
338
  - test/unit/reports_web_test.rb
336
339
  - test/unit/resque_worker_test.rb
337
340
  - test/unit/test_resque_job.rb
341
+ - test/unit/utils/file_groups_test.rb
338
342
  - test/unit/utils/file_list_test.rb
343
+ - test/unit/utils/gem_list_test.rb
339
344
  - test/unit/utils/lines_classifier_test.rb
340
345
  - test/unit/utils/result_test.rb
341
346
  - test/unit/utils/s3_report_test.rb
342
347
  - test/unit/utils/source_file_line_test.rb
343
348
  - test/unit/utils/source_file_test.rb
344
349
  - views/file_list.erb
350
+ - views/gem_list.erb
345
351
  - views/layout.erb
352
+ - views/settings.erb
346
353
  - views/source_file.erb
347
354
  homepage: https://github.com/danmayer/coverband
348
355
  licenses:
@@ -364,7 +371,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
364
371
  version: 1.3.1
365
372
  requirements: []
366
373
  rubyforge_project:
367
- rubygems_version: 2.5.2.3
374
+ rubygems_version: 2.5.1
368
375
  signing_key:
369
376
  specification_version: 4
370
377
  summary: Rack middleware to help measure production code usage (LOC runtime usage)
@@ -410,13 +417,16 @@ test_files:
410
417
  - test/unit/middleware_test.rb
411
418
  - test/unit/rack_server_checkout_test.rb
412
419
  - test/unit/rails_full_stack_test.rb
420
+ - test/unit/rails_gems_full_stack_test.rb
413
421
  - test/unit/reports_base_test.rb
414
422
  - test/unit/reports_console_test.rb
415
423
  - test/unit/reports_html_test.rb
416
424
  - test/unit/reports_web_test.rb
417
425
  - test/unit/resque_worker_test.rb
418
426
  - test/unit/test_resque_job.rb
427
+ - test/unit/utils/file_groups_test.rb
419
428
  - test/unit/utils/file_list_test.rb
429
+ - test/unit/utils/gem_list_test.rb
420
430
  - test/unit/utils/lines_classifier_test.rb
421
431
  - test/unit/utils/result_test.rb
422
432
  - test/unit/utils/s3_report_test.rb