oneshot_coverage 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d60a116028cbd90801d1a0883c3bedbdd497c591458f91f9a8e285adf2d85100
4
- data.tar.gz: e5e04c825c36bab7e1405920a9b159d034152f8367fdc6432028269ec494ce0a
3
+ metadata.gz: 2b39908101b69a0d652f8219df289b541f44dd763586f938f714da7990aa801e
4
+ data.tar.gz: 9f71dd33954f1cc1e8e88f46a71cd99800f41afea57197851a9d4e46a9c98c49
5
5
  SHA512:
6
- metadata.gz: cab0f5ece8e3d3c258c3524af5f5ea16d60ff8dcab2f64cc9c7b109008420f29be4fda94c2ac64433b25229966a804a975464134c345bdb19b2c81d4a974d319
7
- data.tar.gz: 6d95ce0b3b5fc2d40cca0827e12805f125ed9d3c168b6a1ce467e021c8627dd1d86f7f006adc845e21fc3c993de58be75da8eb6f78e7e39af23059e31e10405d
6
+ metadata.gz: cf5c1b77da9e902783c2d62b65fb20827b78e7601cf9322ee0ac2802444d08db108a793634ae50a4891e1bf5809acb9203cd22fe7ad29351717f8f92787be56d
7
+ data.tar.gz: 9bad05fb306ccdf11c4ef94e8838f2eb63d24f69444c614439d578a812f2fd8decea5d8e3882256750c17fe8ec9b07f3539385d1c6bb89b01488449f27933a52
data/README.md CHANGED
@@ -35,7 +35,7 @@ Or install it yourself as:
35
35
  OneshotCoverage.configure(
36
36
  target_path: '/base/project/path',
37
37
  logger: OneshotCoverage::Logger::NullLogger.new,
38
- max_emit_at_once: nil, # Flush all when it set to `nil`, which is default
38
+ emit_term: nil, # emit per `emit_term` seconds. It tries to emit per request when `nil`.
39
39
  )
40
40
  OneshotCoverage.start
41
41
  ```
@@ -44,25 +44,44 @@ As default, OneshotCoverage supports 2 logger.
44
44
 
45
45
  - OneshotCoverage::Logger::NullLogger (default)
46
46
  - OneshotCoverage::Logger::StdoutLogger
47
+ - OneshotCoverage::Logger::FileLogger
47
48
 
48
49
  Only required interface is `#post` instance method, so you could implement
49
50
  by yourself easily.
50
51
 
51
52
  ```ruby
52
- class SampleFluentLogger
53
- def initialize
54
- @logger = Fluent::Logger::FluentLogger.new('tag_prefix')
53
+ class FileLogger
54
+ def initialize(log_path)
55
+ @log_path = log_path
55
56
  end
56
57
 
57
- def post(path:, md5_hash:, lineno:)
58
- @logger.post(nil, path: path, md5_hash: md5_hash, lineno: lineno)
58
+ # new_logs: Struct.new(:path, :md5_hash, :lines)
59
+ def post(new_logs)
60
+ current_coverage = fetch
61
+
62
+ new_logs.each do |new_log|
63
+ key = "#{new_log.path}-#{new_log.md5_hash}"
64
+
65
+ logged_lines = current_coverage.fetch(key, [])
66
+ current_coverage[key] = logged_lines | new_log.lines
67
+ end
68
+ save(current_coverage)
69
+ end
70
+
71
+ private
72
+
73
+ def fetch
74
+ JSON.load(File.read(@log_path))
75
+ rescue Errno::ENOENT
76
+ {}
77
+ end
78
+
79
+ def save(data)
80
+ File.write(@log_path, JSON.dump(data))
59
81
  end
60
82
  end
61
83
  ```
62
84
 
63
- Please note that it will retry to send data if `#post` returns falsy value.
64
- Hence, make sure to return `true` if you don't want to retry.
65
-
66
85
  ### Emit logs
67
86
 
68
87
  #### With rack application
@@ -19,29 +19,50 @@ module OneshotCoverage
19
19
  end
20
20
  end
21
21
 
22
+ OneshotLog = Struct.new(:path, :md5_hash, :lines)
23
+
22
24
  class Reporter
23
- def initialize(target_path:, logger:, max_emit_at_once:)
25
+ def initialize(target_path:, logger:, emit_term: nil)
24
26
  @target_path = target_path
25
27
  @logger = logger
26
- @buffer = []
27
- @max_emit_at_once = max_emit_at_once
28
+ @emit_term = emit_term
29
+ if @emit_term
30
+ @next_emit_time = Time.now.to_i + rand(@emit_term)
31
+ end
32
+
28
33
  if defined?(Bundler)
29
34
  @bundler_path = Bundler.bundle_path.to_s
30
35
  end
31
36
  end
32
37
 
33
- def emit
34
- Coverage.result(clear: true, stop: false).
38
+ def emit(force_emit)
39
+ if !force_emit
40
+ if !time_to_emit?
41
+ return true
42
+ end
43
+ end
44
+
45
+ logs =
46
+ Coverage.result(clear: true, stop: false).
35
47
  select { |k, v| is_target?(k, v) }.
36
- flat_map { |k, v| transform(k, v) }.
37
- each { |row| @buffer << row }
48
+ map do |filepath, v|
49
+ OneshotLog.new(relative_path(filepath), md5_hash_for(filepath), v[:oneshot_lines])
50
+ end
51
+
52
+ @logger.post(logs)
53
+ end
38
54
 
39
- @buffer.shift(emit_at_once).each do |row|
40
- # Retry when fail to post
41
- unless @logger.post(row)
42
- @buffer << row
55
+ private
56
+
57
+ def time_to_emit?
58
+ if @emit_term
59
+ if @next_emit_time > Time.now.to_i
60
+ return false # Do not emit until next_emit_time
61
+ else
62
+ @next_emit_time += @emit_term
43
63
  end
44
64
  end
65
+ true
45
66
  end
46
67
 
47
68
  def is_target?(filepath, value)
@@ -51,30 +72,20 @@ module OneshotCoverage
51
72
  true
52
73
  end
53
74
 
54
- def transform(filepath, value)
55
- rel_path = filepath[@target_path.size..-1]
56
- md5_hash =
57
- if md5_hash_cache.key?(filepath)
58
- md5_hash_cache[filepath]
59
- else
60
- md5_hash_cache[filepath] = Digest::MD5.file(filepath).hexdigest
61
- end
62
-
63
- value[:oneshot_lines].map do |line|
64
- {
65
- path: rel_path,
66
- md5_hash: md5_hash,
67
- lineno: line
68
- }
69
- end
75
+ def relative_path(filepath)
76
+ filepath[@target_path.size..-1]
70
77
  end
71
78
 
72
79
  def md5_hash_cache
73
80
  @md5_hash_cache ||= {}
74
81
  end
75
82
 
76
- def emit_at_once
77
- @max_emit_at_once || @buffer.size
83
+ def md5_hash_for(filepath)
84
+ if md5_hash_cache.key? filepath
85
+ md5_hash_cache[filepath]
86
+ else
87
+ md5_hash_cache[filepath] = Digest::MD5.file(filepath).hexdigest
88
+ end
78
89
  end
79
90
  end
80
91
 
@@ -85,15 +96,15 @@ module OneshotCoverage
85
96
 
86
97
  # To handle execution with exit immediatly
87
98
  at_exit do
88
- OneshotCoverage.emit
99
+ OneshotCoverage.emit(force_emit: true)
89
100
  end
90
101
  end
91
102
 
92
- def emit
93
- @reporter&.emit
103
+ def emit(force_emit: false)
104
+ @reporter&.emit(force_emit)
94
105
  end
95
106
 
96
- def configure(target_path:, logger: OneshotCoverage::Logger::NullLogger.new, max_emit_at_once: nil)
107
+ def configure(target_path:, logger: OneshotCoverage::Logger::NullLogger.new, emit_term: nil)
97
108
  target_path_by_pathname =
98
109
  if target_path.is_a? Pathname
99
110
  target_path
@@ -103,7 +114,7 @@ module OneshotCoverage
103
114
  @reporter = OneshotCoverage::Reporter.new(
104
115
  target_path: target_path_by_pathname.cleanpath.to_s + "/",
105
116
  logger: logger,
106
- max_emit_at_once: max_emit_at_once
117
+ emit_term: emit_term,
107
118
  )
108
119
  end
109
120
  end
@@ -0,0 +1,35 @@
1
+ require 'json'
2
+
3
+ module OneshotCoverage
4
+ module Logger
5
+ class FileLogger
6
+ def initialize(log_path)
7
+ @log_path = log_path
8
+ end
9
+
10
+ def post(new_logs)
11
+ current_coverage = fetch
12
+
13
+ new_logs.each do |new_log|
14
+ key = "#{new_log.path}-#{new_log.md5_hash}"
15
+
16
+ logged_lines = current_coverage.fetch(key, [])
17
+ current_coverage[key] = logged_lines | new_log.lines
18
+ end
19
+ save(current_coverage)
20
+ end
21
+
22
+ private
23
+
24
+ def fetch
25
+ JSON.load(File.read(@log_path))
26
+ rescue Errno::ENOENT
27
+ {}
28
+ end
29
+
30
+ def save(data)
31
+ File.write(@log_path, JSON.dump(data))
32
+ end
33
+ end
34
+ end
35
+ end
@@ -3,7 +3,6 @@ module OneshotCoverage
3
3
  class NullLogger
4
4
  def post(_row)
5
5
  # Do nothing
6
- true
7
6
  end
8
7
  end
9
8
  end
@@ -1,11 +1,12 @@
1
1
  module OneshotCoverage
2
2
  module Logger
3
3
  class StdoutLogger
4
- def post(path:, md5_hash:, lineno:)
5
- $stdout.puts(
6
- "[OneshotCoverage] logged path: #{path}, md5_hash: #{md5_hash}, lineno: #{lineno}"
7
- )
8
- true
4
+ def post(logs)
5
+ logs.each do |log|
6
+ $stdout.puts(
7
+ "[OneshotCoverage] logged path: #{log.path}, md5_hash: #{log.md5_hash}, executed_lines: #{log.lines}"
8
+ )
9
+ end
9
10
  end
10
11
  end
11
12
  end
@@ -1,3 +1,3 @@
1
1
  module OneshotCoverage
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oneshot_coverage
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shia
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-27 00:00:00.000000000 Z
11
+ date: 2019-04-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -55,6 +55,7 @@ files:
55
55
  - bin/console
56
56
  - bin/setup
57
57
  - lib/oneshot_coverage.rb
58
+ - lib/oneshot_coverage/logger/file_logger.rb
58
59
  - lib/oneshot_coverage/logger/null_logger.rb
59
60
  - lib/oneshot_coverage/logger/stdout_logger.rb
60
61
  - lib/oneshot_coverage/railtie.rb