coverband 4.1.0.alpha → 4.1.0.beta

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