coverband 2.0.3 → 3.0.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/.rubocop.yml +73 -0
- data/.travis.yml +0 -3
- data/README.md +3 -3
- data/changes.md +65 -49
- data/coverband.gemspec +1 -1
- data/lib/coverband.rb +9 -6
- data/lib/coverband/adapters/base.rb +22 -2
- data/lib/coverband/adapters/file_store.rb +11 -11
- data/lib/coverband/adapters/redis_store.rb +22 -57
- data/lib/coverband/collectors/coverage.rb +57 -53
- data/lib/coverband/configuration.rb +6 -14
- data/lib/coverband/integrations/background.rb +7 -0
- data/lib/coverband/{middleware.rb → integrations/middleware.rb} +1 -3
- data/lib/coverband/reporters/base.rb +37 -82
- data/lib/coverband/reporters/console_report.rb +3 -0
- data/lib/coverband/reporters/simple_cov_report.rb +4 -3
- data/lib/coverband/reporters/web.rb +38 -35
- data/lib/coverband/utils/s3_report_writer.rb +59 -0
- data/lib/coverband/{tasks.rb → utils/tasks.rb} +0 -0
- data/lib/coverband/version.rb +1 -1
- data/test/benchmarks/benchmark.rake +3 -3
- data/test/test_helper.rb +18 -17
- data/test/unit/adapters_base_test.rb +29 -0
- data/test/unit/adapters_file_store_test.rb +2 -2
- data/test/unit/adapters_redis_store_test.rb +14 -51
- data/test/unit/collectors_coverage_test.rb +3 -107
- data/test/unit/configuration_test.rb +2 -9
- data/test/unit/full_stack_test.rb +47 -0
- data/test/unit/middleware_test.rb +21 -57
- data/test/unit/reports_base_test.rb +12 -71
- data/test/unit/reports_console_test.rb +9 -22
- data/test/unit/reports_simple_cov_test.rb +3 -37
- data/test/unit/reports_web_test.rb +4 -0
- data/test/unit/{s3_report_writer_test.rb → utils_s3_report_writer_test.rb} +1 -1
- metadata +29 -18
- data/lib/coverband/adapters/memory_cache_store.rb +0 -53
- data/lib/coverband/collectors/base.rb +0 -126
- data/lib/coverband/collectors/trace.rb +0 -122
- data/lib/coverband/s3_report_writer.rb +0 -49
- data/test/unit/adapters_memory_cache_store_test.rb +0 -66
- data/test/unit/collectors_base_test.rb +0 -104
- data/test/unit/collectors_trace_test.rb +0 -106
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff8f54b9c75fc882bc548834903c232af3ff9e74
|
4
|
+
data.tar.gz: 72cbf124e7484c096bc8316f8940a5d1128ba4de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f964fca6d95868d170694bb4dfb5a064b9d8df717e63a5d79b941dda8beaa6e6acbc3b149f98891030538da8c5b88d46a89edfbd9d97e668230e802fa222102e
|
7
|
+
data.tar.gz: de616d37895b9446425e2947d435db919776019f8658d45183430de3c95675e40591e49bcf0539a5306389f1ee52f5ae15372fa2521b13a71ead5a738ff79340
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.4
|
3
|
+
Exclude:
|
4
|
+
- docs/**/*
|
5
|
+
Documentation:
|
6
|
+
Enabled: false
|
7
|
+
Metrics/MethodLength:
|
8
|
+
Enabled: false
|
9
|
+
Metrics/LineLength:
|
10
|
+
Max: 120
|
11
|
+
Metrics/BlockNesting:
|
12
|
+
Max: 5
|
13
|
+
Bundler/OrderedGems:
|
14
|
+
Enabled: false
|
15
|
+
Metrics/CyclomaticComplexity:
|
16
|
+
Enabled: false
|
17
|
+
Metrics/PerceivedComplexity:
|
18
|
+
Enabled: false
|
19
|
+
Metrics/AbcSize:
|
20
|
+
Enabled: false
|
21
|
+
Metrics/ClassLength:
|
22
|
+
Enabled: false
|
23
|
+
Metrics/BlockLength:
|
24
|
+
Enabled: false
|
25
|
+
Metrics/BlockNesting:
|
26
|
+
Max: 10
|
27
|
+
Metrics/ModuleLength:
|
28
|
+
Enabled: false
|
29
|
+
Metrics/ParameterLists:
|
30
|
+
Max: 10
|
31
|
+
Naming/AccessorMethodName:
|
32
|
+
Enabled: false
|
33
|
+
Naming/PredicateName:
|
34
|
+
Enabled: false
|
35
|
+
Style/FormatStringToken:
|
36
|
+
Enabled: false
|
37
|
+
Style/TernaryParentheses:
|
38
|
+
Enabled: false
|
39
|
+
Style/MutableConstant:
|
40
|
+
Enabled: false
|
41
|
+
Style/FrozenStringLiteralComment:
|
42
|
+
Enabled: true
|
43
|
+
Style/GuardClause:
|
44
|
+
Enabled: true
|
45
|
+
Style/NumericPredicate:
|
46
|
+
Enabled: false
|
47
|
+
Style/NumericLiterals:
|
48
|
+
Enabled: false
|
49
|
+
Style/NumericLiteralPrefix:
|
50
|
+
Enabled: false
|
51
|
+
Style/ClassAndModuleChildren:
|
52
|
+
Enabled: false
|
53
|
+
Style/MethodMissingSuper:
|
54
|
+
Enabled: true
|
55
|
+
Style/MissingRespondToMissing:
|
56
|
+
Enabled: false
|
57
|
+
Performance/Casecmp:
|
58
|
+
Enabled: false
|
59
|
+
Layout/EmptyLinesAroundArguments:
|
60
|
+
Enabled: true
|
61
|
+
Layout/MultilineMethodCallIndentation:
|
62
|
+
Enabled: true
|
63
|
+
Layout/MultilineOperationIndentation:
|
64
|
+
Enabled: true
|
65
|
+
Lint/RescueException:
|
66
|
+
Enabled: true
|
67
|
+
Lint/ShadowingOuterLocalVariable:
|
68
|
+
Enabled: true
|
69
|
+
Style/FormatString:
|
70
|
+
Enabled: true
|
71
|
+
Security/Eval:
|
72
|
+
Enabled: true
|
73
|
+
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -179,7 +179,7 @@ module MyApplication
|
|
179
179
|
# any files that get loaded as part of railties will have no coverage
|
180
180
|
config.before_initialize do
|
181
181
|
require 'coverage'
|
182
|
-
Coverband::Collectors::
|
182
|
+
Coverband::Collectors::Coverage.instance.start
|
183
183
|
end
|
184
184
|
|
185
185
|
end
|
@@ -380,9 +380,9 @@ require 'rails'
|
|
380
380
|
# Capture code coverage during our cron jobs
|
381
381
|
class CoverageRunner < ::Rails::Railtie
|
382
382
|
runner do
|
383
|
-
Coverband::Collectors::
|
383
|
+
Coverband::Collectors::Coverage.instance.start
|
384
384
|
at_exit do
|
385
|
-
Coverband::Collectors::
|
385
|
+
Coverband::Collectors::Coverage.instance.report_coverage
|
386
386
|
end
|
387
387
|
end
|
388
388
|
end
|
data/changes.md
CHANGED
@@ -4,22 +4,41 @@
|
|
4
4
|
|
5
5
|
Will be the fully modern release that drops maintenance legacy support in favor of increased performance, ease of use, and maintainability.
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
7
|
+
- expects to drop Tracepoint collection engine
|
8
|
+
- expects to drop anything below Ruby 2.3
|
9
|
+
- Release will be aimed as significantly simplifying ease of use
|
10
|
+
- near zero config setup for Rails apps
|
11
|
+
- add built-in support for easy loading via Railties
|
12
|
+
- built in support for activejob, sidekiq, and other common frameworks
|
13
|
+
- reduced configuration options
|
14
|
+
- options on reporting
|
15
|
+
- background reporting
|
16
|
+
- or middleware reporting
|
17
|
+
- improved web reporting
|
18
|
+
- no longer relying directly on HTML in S3 but dynamically generated from any adapter
|
19
|
+
- additional adapters including Memcache, S3, and ActiveRecord
|
20
|
+
|
21
|
+
### Coverband_jam_session
|
22
|
+
|
23
|
+
This is a possible gem to host experimental or more complex features, which would require tuning, configuration, and performance trade offs
|
24
|
+
|
25
|
+
- additional adapters (tracepoint, ruby-profiler, etc)
|
26
|
+
- code route tracing (entry point to all code executed for example /some_path -> code coverage of that path)
|
27
|
+
- tagging of reported Coverage
|
28
|
+
- allow only to collect coverage based on route (limiting or scoped coverage)
|
29
|
+
- coverage over some other variable like a set of alpha users
|
16
30
|
|
17
31
|
# Alpha
|
18
32
|
|
19
|
-
### 3.0
|
33
|
+
### Coverband 3.0
|
34
|
+
|
35
|
+
* drops Tracepoint
|
36
|
+
* drops Ruby <= 2.3.0
|
37
|
+
* rewrites redis store, for 60X perf
|
38
|
+
* drops various other features not needed without Tracepoint
|
39
|
+
* standardizes on Coverage array format vs sparse hash
|
20
40
|
|
21
|
-
|
22
|
-
* background thread reporter
|
41
|
+
# Released
|
23
42
|
|
24
43
|
# 2.0.3
|
25
44
|
|
@@ -28,9 +47,6 @@ Will be the fully modern release that drops maintenance legacy support in favor
|
|
28
47
|
* various additional benchmarks @danmayer
|
29
48
|
* Filter out files with no coverage thanks @kbaum
|
30
49
|
|
31
|
-
|
32
|
-
# Released
|
33
|
-
|
34
50
|
### 2.0.2
|
35
51
|
|
36
52
|
* fix possible nil error on files that changed since initial recording @viktor-silakov
|
@@ -45,50 +61,50 @@ Will be the fully modern release that drops maintenance legacy support in favor
|
|
45
61
|
|
46
62
|
### 2.0.1
|
47
63
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
64
|
+
- add support for fine grained S3 configuration via Coverband config, thanks @a0s
|
65
|
+
- https://github.com/danmayer/coverband/pull/98
|
66
|
+
- Using the file argument to self.configure in lib/coverband.rb, thanks @ThomasOwens
|
67
|
+
- https://github.com/danmayer/coverband/pull/100
|
68
|
+
- added redis improvements allowing namespace and TTL thx @oded-zahavi
|
69
|
+
- fix warnings about duplicate method definition
|
70
|
+
- Add support for safe_reload_files based on full file path
|
71
|
+
- Add support for Sinatra admin control endpoints
|
72
|
+
- improved documentation
|
57
73
|
|
58
74
|
### 2.0.0
|
59
75
|
|
60
76
|
Major release with various backwards compatibility breaking changes (generally related to the configuration). The 2.0 lifecycle will act as a mostly easy upgrade that supports past users looking to move to the much faster new Coverage Adapter.
|
61
77
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
78
|
+
- Continues to support Ruby 2.0 and up
|
79
|
+
- supports multiple collect engines, introducing the concept of multiple collector adapters
|
80
|
+
- extends the concepts of multiple storage adapters, enabling additional authors to help support Kafka, graphite, other adapters
|
81
|
+
- old require based loading, but working towards deprecating the entire baseline concept
|
82
|
+
- Introduces massive performance enhancements by moving to Ruby `Coverage` based collection
|
83
|
+
- Opposed to sampling this is now a reporting frequency, when using `Coverage` collector
|
84
|
+
- Reduced configuration complexity
|
85
|
+
- Refactoring the code preparing for more varied storage and reporting options
|
86
|
+
- Drop Redis as a gem runtime_dependency
|
71
87
|
|
72
88
|
### 1.5.0
|
73
89
|
|
74
90
|
This is a significant release with significant refactoring a stepping stone for a 2.0 release.
|
75
91
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
92
|
+
- staging a changes.md document!
|
93
|
+
- refactored out full abstraction for stores
|
94
|
+
- supports hit counts vs binary covered / not covered for lines
|
95
|
+
- this will let you find density of code usage just not if it was used
|
96
|
+
- this is a slight performance hit, so you can fall back to the old system if you want `redisstore.new(@redis, array: true)`
|
97
|
+
- this is the primary new feature in 1.5.0
|
98
|
+
- Redis has configurable base name, so I can safely change storage formats between releases
|
99
|
+
- improved documentation
|
100
|
+
- supports `SimpleCov.root`
|
101
|
+
- show files that were never touched
|
102
|
+
- apply coverband filters to ignore files in report not just collection
|
103
|
+
- improved test coverage
|
104
|
+
- improved benchmarks including support for multiple stores ;)
|
89
105
|
|
90
106
|
### 1.3.1
|
91
107
|
|
92
|
-
|
93
|
-
|
94
|
-
|
108
|
+
- This was a small fix release addressing some issues
|
109
|
+
- mostly readme updates
|
110
|
+
- last release prior to having a changes document!
|
data/coverband.gemspec
CHANGED
@@ -31,7 +31,7 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.add_development_dependency 'benchmark-ips'
|
32
32
|
# add when debugging
|
33
33
|
# require 'byebug'; byebug
|
34
|
-
|
34
|
+
spec.add_development_dependency 'byebug'
|
35
35
|
# deprecate when dropping support for older ruby
|
36
36
|
spec.add_runtime_dependency 'json'
|
37
37
|
# todo make an optional dependency for simplecov reports
|
data/lib/coverband.rb
CHANGED
@@ -7,17 +7,15 @@ require 'coverband/version'
|
|
7
7
|
require 'coverband/configuration'
|
8
8
|
require 'coverband/adapters/base'
|
9
9
|
require 'coverband/adapters/redis_store'
|
10
|
-
require 'coverband/adapters/memory_cache_store'
|
11
10
|
require 'coverband/adapters/file_store'
|
12
|
-
require 'coverband/
|
13
|
-
require 'coverband/collectors/trace'
|
11
|
+
require 'coverband/utils/s3_report_writer'
|
14
12
|
require 'coverband/collectors/coverage'
|
15
13
|
require 'coverband/reporters/base'
|
16
14
|
require 'coverband/reporters/simple_cov_report'
|
17
15
|
require 'coverband/reporters/console_report'
|
18
16
|
require 'coverband/reporters/web'
|
19
|
-
require 'coverband/middleware'
|
20
|
-
require 'coverband/
|
17
|
+
require 'coverband/integrations/middleware'
|
18
|
+
require 'coverband/integrations/background'
|
21
19
|
|
22
20
|
module Coverband
|
23
21
|
CONFIG_FILE = './config/coverband.rb'
|
@@ -35,11 +33,16 @@ module Coverband
|
|
35
33
|
elsif File.exist?(configuration_file)
|
36
34
|
require configuration_file
|
37
35
|
else
|
38
|
-
|
36
|
+
msg = "configure requires a block, #{CONFIG_FILE} in project, or file path passed in configure"
|
37
|
+
raise ArgumentError, msg
|
39
38
|
end
|
40
39
|
end
|
41
40
|
|
42
41
|
def self.configuration
|
43
42
|
self.configuration_data ||= Configuration.new
|
44
43
|
end
|
44
|
+
|
45
|
+
def self.start
|
46
|
+
Coverband::Collectors::Coverage.instance
|
47
|
+
end
|
45
48
|
end
|
@@ -11,7 +11,7 @@ module Coverband
|
|
11
11
|
raise 'abstract'
|
12
12
|
end
|
13
13
|
|
14
|
-
def save_report(
|
14
|
+
def save_report(_report)
|
15
15
|
raise 'abstract'
|
16
16
|
end
|
17
17
|
|
@@ -23,9 +23,29 @@ module Coverband
|
|
23
23
|
raise 'abstract'
|
24
24
|
end
|
25
25
|
|
26
|
-
def covered_lines_for_file(
|
26
|
+
def covered_lines_for_file(_file)
|
27
27
|
raise 'abstract'
|
28
28
|
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def merge_reports(new_report, old_report)
|
33
|
+
keys = (new_report.keys + old_report.keys).uniq
|
34
|
+
keys.each do |file|
|
35
|
+
new_report[file] = if new_report[file] && old_report[file]
|
36
|
+
array_add(new_report[file], old_report[file])
|
37
|
+
elsif new_report[file]
|
38
|
+
new_report[file]
|
39
|
+
else
|
40
|
+
old_report[file]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
new_report
|
44
|
+
end
|
45
|
+
|
46
|
+
def array_add(latest, original)
|
47
|
+
latest.map.with_index { |v, i| (v && original[i]) ? v + original[i] : nil }
|
48
|
+
end
|
29
49
|
end
|
30
50
|
end
|
31
51
|
end
|
@@ -2,6 +2,11 @@
|
|
2
2
|
|
3
3
|
module Coverband
|
4
4
|
module Adapters
|
5
|
+
###
|
6
|
+
# FilesStore store a merged coverage file to local disk
|
7
|
+
# Generally this is for testing and development
|
8
|
+
# Not recommended for production deployment
|
9
|
+
###
|
5
10
|
class FileStore < Base
|
6
11
|
attr_accessor :path
|
7
12
|
|
@@ -17,17 +22,8 @@ module Coverband
|
|
17
22
|
end
|
18
23
|
|
19
24
|
def save_report(report)
|
20
|
-
|
21
|
-
report
|
22
|
-
if results.key?(file)
|
23
|
-
# convert the keys to "3" opposed to 3
|
24
|
-
values = JSON.parse(values.to_json)
|
25
|
-
results[file].merge!(values) { |_k, old_v, new_v| old_v.to_i + new_v.to_i }
|
26
|
-
else
|
27
|
-
results[file] = values
|
28
|
-
end
|
29
|
-
end
|
30
|
-
File.open(path, 'w') { |f| f.write(results.to_json) }
|
25
|
+
merge_reports(report, coverage)
|
26
|
+
save_coverage(report)
|
31
27
|
end
|
32
28
|
|
33
29
|
def coverage
|
@@ -46,6 +42,10 @@ module Coverband
|
|
46
42
|
|
47
43
|
private
|
48
44
|
|
45
|
+
def save_coverage(report)
|
46
|
+
File.open(path, 'w') { |f| f.write(report.to_json) }
|
47
|
+
end
|
48
|
+
|
49
49
|
def existing_data(path)
|
50
50
|
if File.exist?(path)
|
51
51
|
JSON.parse(File.read(path))
|
@@ -2,94 +2,59 @@
|
|
2
2
|
|
3
3
|
module Coverband
|
4
4
|
module Adapters
|
5
|
+
###
|
6
|
+
# RedisStore store a merged coverage file to redis
|
7
|
+
###
|
5
8
|
class RedisStore < Base
|
6
|
-
BASE_KEY = '
|
9
|
+
BASE_KEY = 'coverband3'
|
7
10
|
|
8
11
|
def initialize(redis, opts = {})
|
9
|
-
@redis
|
12
|
+
@redis = redis
|
10
13
|
@ttl = opts[:ttl]
|
11
14
|
@redis_namespace = opts[:redis_namespace]
|
12
15
|
end
|
13
16
|
|
14
17
|
def clear!
|
15
|
-
@redis.smembers(base_key).each { |key| @redis.del("#{base_key}.#{key}") }
|
16
18
|
@redis.del(base_key)
|
17
19
|
end
|
18
20
|
|
19
|
-
def base_key
|
20
|
-
@base_key ||= [BASE_KEY, @redis_namespace].compact.join('.')
|
21
|
-
end
|
22
|
-
|
23
21
|
def save_report(report)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
22
|
+
# Note: This could lead to slight races
|
23
|
+
# where multiple processes pull the old coverage and add to it then push
|
24
|
+
# the Coverband 2 had the same issue,
|
25
|
+
# and the tradeoff has always been acceptable
|
26
|
+
merge_reports(report, coverage)
|
27
|
+
save_coverage(base_key, report)
|
30
28
|
end
|
31
29
|
|
32
30
|
def coverage
|
33
|
-
|
34
|
-
redis.smembers(base_key).each do |key|
|
35
|
-
data[key] = covered_lines_for_file(key)
|
36
|
-
end
|
37
|
-
data
|
31
|
+
get_report(base_key)
|
38
32
|
end
|
39
33
|
|
40
34
|
def covered_files
|
41
|
-
|
35
|
+
coverage.keys
|
42
36
|
end
|
43
37
|
|
44
38
|
def covered_lines_for_file(file)
|
45
|
-
|
39
|
+
coverage[file]
|
46
40
|
end
|
47
41
|
|
48
42
|
private
|
49
43
|
|
50
44
|
attr_reader :redis
|
51
|
-
|
52
|
-
def pipelined_save(combined_report)
|
53
|
-
redis.pipelined do
|
54
|
-
combined_report.each do |file, values|
|
55
|
-
existing = values[:existing]
|
56
|
-
new = values[:new]
|
57
|
-
unless values.empty?
|
58
|
-
# in redis all file_keys are strings
|
59
|
-
new_string_values = Hash[new.map {|k, val| [k.to_s, val]}]
|
60
|
-
new_string_values.merge!(existing) {|_k, old_v, new_v| old_v.to_i + new_v.to_i}
|
61
|
-
redis.mapped_hmset(file, new_string_values)
|
62
|
-
redis.expire(file, @ttl) if @ttl
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
45
|
|
68
|
-
def
|
69
|
-
|
70
|
-
file_keys.each do |key|
|
71
|
-
redis.hgetall(key)
|
72
|
-
end
|
73
|
-
end
|
46
|
+
def base_key
|
47
|
+
@base_key ||= [BASE_KEY, @redis_namespace].compact.join('.')
|
74
48
|
end
|
75
49
|
|
76
|
-
def
|
77
|
-
|
78
|
-
|
79
|
-
file_keys.each_with_index do |key, i|
|
80
|
-
combined_report[key] = {
|
81
|
-
new: report.values[i],
|
82
|
-
existing: existing_records[i]
|
83
|
-
}
|
84
|
-
end
|
85
|
-
|
86
|
-
return combined_report
|
50
|
+
def save_coverage(key, data)
|
51
|
+
redis.set key, data.to_json
|
52
|
+
redis.expire(key, @ttl) if @ttl
|
87
53
|
end
|
88
54
|
|
89
|
-
def
|
90
|
-
redis.
|
91
|
-
|
92
|
-
values
|
55
|
+
def get_report(key)
|
56
|
+
data = redis.get key
|
57
|
+
data ? JSON.parse(data) : {}
|
93
58
|
end
|
94
59
|
end
|
95
60
|
end
|