oneshot_coverage 0.3.0 → 0.4.1

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: 2b39908101b69a0d652f8219df289b541f44dd763586f938f714da7990aa801e
4
- data.tar.gz: 9f71dd33954f1cc1e8e88f46a71cd99800f41afea57197851a9d4e46a9c98c49
3
+ metadata.gz: 074f86971202b3cb656203277d3032b669b36bd62fe6938633e57b0c50e6a151
4
+ data.tar.gz: 0c8660a5997eba0e6bb17b8b2c444bae52100c5bff099c90246637e9a9fb005d
5
5
  SHA512:
6
- metadata.gz: cf5c1b77da9e902783c2d62b65fb20827b78e7601cf9322ee0ac2802444d08db108a793634ae50a4891e1bf5809acb9203cd22fe7ad29351717f8f92787be56d
7
- data.tar.gz: 9bad05fb306ccdf11c4ef94e8838f2eb63d24f69444c614439d578a812f2fd8decea5d8e3882256750c17fe8ec9b07f3539385d1c6bb89b01488449f27933a52
6
+ metadata.gz: 6ce75ffbfe041e4f86b5e685fd0e7b8c2c5b58e7ece2095fc526243d129ec20d09a3c875e1a33cd5b779e10cf8b770ba936ae563c5cb3cc26b540d63bada3636
7
+ data.tar.gz: 977016fc11910a04de1d690a23bd6bb44a6bcf4e74ef2384b1d1aca01c1da784c95f8f97973781e52c142e4a27868bc6b431dd5495a3876521bb056556c33074
@@ -0,0 +1,19 @@
1
+ name: Ruby
2
+
3
+ on: [push,pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+ strategy:
9
+ matrix:
10
+ ruby: [ '2.6', '2.7', '3.0' ]
11
+ name: Test on Ruby ${{ matrix.ruby }}
12
+ steps:
13
+ - uses: actions/checkout@v2
14
+ - uses: ruby/setup-ruby@v1
15
+ with:
16
+ ruby-version: ${{ matrix.ruby }}
17
+ bundler-cache: true
18
+ - name: Execute test
19
+ run: bundle exec rake
data/.gitignore CHANGED
@@ -41,6 +41,7 @@ Temporary Items
41
41
  /test/tmp/
42
42
  /test/version_tmp/
43
43
  /tmp/
44
+ Gemfile.lock
44
45
 
45
46
  # Used by dotenv library to load environment variables.
46
47
  # .env
@@ -93,3 +94,6 @@ build-iPhoneSimulator/
93
94
  /pkg/
94
95
  /spec/reports/
95
96
  /tmp/
97
+
98
+ target_app/coverage.json
99
+ target_app/coverage/
data/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ ## 0.4.1
2
+
3
+ - Add SimplecovReporter
4
+
5
+ ## 0.4.0
6
+
7
+ - Provide options for checking bundle_path (#7)
8
+ - Fix error when empty log file is exist (#4)
data/Gemfile CHANGED
@@ -4,3 +4,8 @@ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in oneshot_coverage.gemspec
6
6
  gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+ gem "bundler", "> 1.17"
10
+
11
+ gem "minitest", "~> 5.0"
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # OneshotCoverage
2
2
 
3
- This gem may not be very useful when you want to use [Coverage onetshot mode](https://bugs.ruby-lang.org/issues/15022),
3
+ This gem may not be very useful when you want to use [Coverage oneshot mode](https://bugs.ruby-lang.org/issues/15022),
4
4
  however, It could be good example to study how to implement by yourself.
5
5
 
6
6
  This gem provides simple tools to use oneshot mode easier. It gives you:
@@ -9,7 +9,7 @@ This gem provides simple tools to use oneshot mode easier. It gives you:
9
9
  - Pluggable logger interface
10
10
 
11
11
  Please notice that it records code executions under the target path(usually, project base path).
12
- If you have bundle gem path under target path, It will be ignored automatically.
12
+ If you have bundle gem path under target path, It will be ignored by default.
13
13
 
14
14
  ## Installation
15
15
 
@@ -36,6 +36,7 @@ OneshotCoverage.configure(
36
36
  target_path: '/base/project/path',
37
37
  logger: OneshotCoverage::Logger::NullLogger.new,
38
38
  emit_term: nil, # emit per `emit_term` seconds. It tries to emit per request when `nil`.
39
+ cover_bundle_path: false, # record bundle gem path. Default value is false.
39
40
  )
40
41
  OneshotCoverage.start
41
42
  ```
@@ -98,6 +99,28 @@ to emit via `at_exit`.
98
99
  On the other hand, it's not, then you need to emit it manually
99
100
  at proper timing(i.e. when batch finished)
100
101
 
102
+ ### Generate report with simplecov
103
+
104
+ You can generate pretty report using simplecov(confirmed with 0.21.2). Here is some example:
105
+
106
+ ```ruby
107
+ require 'simplecov'
108
+ require 'oneshot_coverage/simplecov_reporter'
109
+
110
+ OneshotCoverage::SimplecovReporter.new(
111
+ project_path: Dir.pwd, # target project path. Dir.pwd is default.
112
+ log_path: 'coverage.json', # oneshot coverage log generated by FileLogger or same scheme json file acceptable
113
+ file_filter: OneshotCoverage::SimplecovReporter::DefaultFilter # Object respond to #call with return true | false. this filter used for coverage target. file_filter.call(path) return false, then path will not be included to report. DefaultFilter is default, which exclude non-ruby file, files under /spec/, /test/, /script/, /config/
114
+ ).run
115
+ ```
116
+
117
+ This code generates html report under 'project_path/`coverage/`'
118
+
119
+ ### Note
120
+
121
+ Note that `cover_bundle_path` only cover managed gem by bundler.
122
+ In the other words, the gem installed with `path` option, which bundler just load it, will not be included by this.
123
+
101
124
  ## License
102
125
 
103
126
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile CHANGED
@@ -1,2 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
- task :default => :spec
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/*_test.rb"]
10
+ end
11
+
12
+ task default: %i[test]
@@ -22,7 +22,14 @@ module OneshotCoverage
22
22
  OneshotLog = Struct.new(:path, :md5_hash, :lines)
23
23
 
24
24
  class Reporter
25
- def initialize(target_path:, logger:, emit_term: nil)
25
+ def initialize(
26
+ coverage_module:,
27
+ target_path:,
28
+ logger:,
29
+ emit_term: nil,
30
+ cover_bundle_path: false
31
+ )
32
+ @coverage_module = coverage_module
26
33
  @target_path = target_path
27
34
  @logger = logger
28
35
  @emit_term = emit_term
@@ -32,24 +39,28 @@ module OneshotCoverage
32
39
 
33
40
  if defined?(Bundler)
34
41
  @bundler_path = Bundler.bundle_path.to_s
42
+ @cover_bundle_path = cover_bundle_path
35
43
  end
36
44
  end
37
45
 
38
46
  def emit(force_emit)
39
47
  if !force_emit
40
48
  if !time_to_emit?
41
- return true
49
+ return
42
50
  end
43
51
  end
44
52
 
45
53
  logs =
46
- Coverage.result(clear: true, stop: false).
54
+ @coverage_module.result(clear: true, stop: false).
47
55
  select { |k, v| is_target?(k, v) }.
48
56
  map do |filepath, v|
49
- OneshotLog.new(relative_path(filepath), md5_hash_for(filepath), v[:oneshot_lines])
57
+ formatted_path = format_filepath(filepath)
58
+ OneshotLog.new(format_filepath(filepath), md5_hash_for(filepath), v[:oneshot_lines])
50
59
  end
51
60
 
52
- @logger.post(logs)
61
+ if logs.size > 0
62
+ @logger.post(logs)
63
+ end
53
64
  end
54
65
 
55
66
  private
@@ -67,13 +78,29 @@ module OneshotCoverage
67
78
 
68
79
  def is_target?(filepath, value)
69
80
  return false if value[:oneshot_lines].empty?
81
+ return @cover_bundle_path if from_bundler?(filepath)
70
82
  return false if !filepath.start_with?(@target_path)
71
- return false if @bundler_path && filepath.start_with?(@bundler_path)
72
83
  true
73
84
  end
74
85
 
86
+ def from_bundler?(filepath)
87
+ @bundler_path && filepath.start_with?(@bundler_path)
88
+ end
89
+
90
+ def format_filepath(filepath)
91
+ if from_bundler?(filepath)
92
+ filepath
93
+ else
94
+ relative_path(filepath)
95
+ end
96
+ end
97
+
75
98
  def relative_path(filepath)
76
- filepath[@target_path.size..-1]
99
+ if filepath.include?(@target_path)
100
+ filepath[@target_path.size..-1]
101
+ else
102
+ filepath
103
+ end
77
104
  end
78
105
 
79
106
  def md5_hash_cache
@@ -104,17 +131,19 @@ module OneshotCoverage
104
131
  @reporter&.emit(force_emit)
105
132
  end
106
133
 
107
- def configure(target_path:, logger: OneshotCoverage::Logger::NullLogger.new, emit_term: nil)
108
- target_path_by_pathname =
109
- if target_path.is_a? Pathname
110
- target_path
111
- else
112
- Pathname.new(target_path)
113
- end
134
+ def configure(
135
+ target_path:,
136
+ logger: OneshotCoverage::Logger::NullLogger.new,
137
+ coverage_module: Coverage,
138
+ emit_term: nil,
139
+ cover_bundle_path: false
140
+ )
114
141
  @reporter = OneshotCoverage::Reporter.new(
115
- target_path: target_path_by_pathname.cleanpath.to_s + "/",
142
+ coverage_module: coverage_module,
143
+ target_path: Pathname.new(target_path).cleanpath.to_s + "/",
116
144
  logger: logger,
117
145
  emit_term: emit_term,
146
+ cover_bundle_path: cover_bundle_path
118
147
  )
119
148
  end
120
149
  end
@@ -22,7 +22,7 @@ module OneshotCoverage
22
22
  private
23
23
 
24
24
  def fetch
25
- JSON.load(File.read(@log_path))
25
+ JSON.load(File.read(@log_path)) || {}
26
26
  rescue Errno::ENOENT
27
27
  {}
28
28
  end
@@ -0,0 +1,95 @@
1
+ require 'coverage'
2
+ require 'find'
3
+ require 'json'
4
+
5
+ module OneshotCoverage
6
+ class SimplecovReporter
7
+ module DefaultFilter
8
+ module_function def call(path)
9
+ return false unless File.extname(path) == '.rb'
10
+ return false if path.include?('/spec/')
11
+ return false if path.include?('/test/')
12
+ return false if path.include?('/script/')
13
+ return false if path.include?('/config/')
14
+
15
+ true
16
+ end
17
+ end
18
+
19
+ # @option log_path [String] oneshot coverage log generated by FileLogger or same scheme json file acceptable
20
+ # @option project_path [String] target project path.
21
+ # @option file_filter [Object] Object respond to #call with return true | false. this filter used for coverage target. file_filter.call(path) return false, then path will not be included to report
22
+ def initialize(
23
+ log_path:,
24
+ project_path: Dir.pwd,
25
+ file_filter: DefaultFilter
26
+ )
27
+ @project_path = project_path.end_with?('/') ? project_path : "#{project_path}/"
28
+ @log_path = log_path
29
+ @file_filter = file_filter
30
+ end
31
+
32
+ def run
33
+ raise "Please install & require 'simplecov' if you want to use this" unless defined? SimpleCov
34
+
35
+ coverages = coverage_stubs
36
+ fill_lines(coverages)
37
+ gen_html(coverages)
38
+ end
39
+
40
+ private
41
+
42
+ def coverage_candidates
43
+ @coverage_candidates ||=
44
+ Find.find(@project_path).
45
+ select { |fp| @file_filter.call(fp) }
46
+ # map { |fp| fp.sub(@project_path, '') }
47
+ end
48
+
49
+ def coverage_stubs
50
+ {}.tap do |stubs|
51
+ coverage_candidates.each do |filepath|
52
+ stub = Coverage.line_stub(filepath)
53
+ stubs[filepath] = stub
54
+ end
55
+ end
56
+ end
57
+
58
+ def oneshot_coverage_logs
59
+ @oneshot_coverage_logs ||= begin
60
+ raise "#{@log_path} isn't exist!" unless File.exist?(@log_path)
61
+
62
+ JSON.parse(File.read(@log_path)).transform_keys do |filepath_with_md5_hash|
63
+ *path_tokens, _md5_hash = filepath_with_md5_hash.split('-')
64
+ "#{@project_path}#{path_tokens.join('-')}"
65
+ end
66
+ end
67
+ end
68
+
69
+ def fill_lines(coverages)
70
+ oneshot_coverage_logs.each do |filepath, linenums|
71
+ linenums.each do |linenum|
72
+ coverages[filepath][linenum - 1] = 1
73
+ end
74
+ end
75
+ end
76
+
77
+ def format_data(coverages)
78
+ coverages.transform_values do |lines|
79
+ { "lines" => lines }
80
+ end
81
+ end
82
+
83
+ def gen_html(coverages)
84
+ coverages_for_simcov = format_data(coverages)
85
+ SimpleCov.root(@project_path)
86
+ result = SimpleCov::Result.from_hash({
87
+ 'oneshot' => {
88
+ 'coverage' => coverages_for_simcov,
89
+ 'timestamp' => Time.now.to_i
90
+ }
91
+ }).first
92
+ SimpleCov::Formatter::HTMLFormatter.new.format(result)
93
+ end
94
+ end
95
+ end
@@ -1,3 +1,3 @@
1
1
  module OneshotCoverage
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.1"
3
3
  end
@@ -36,7 +36,4 @@ Gem::Specification.new do |spec|
36
36
 
37
37
  # Release ruby version lock temperary
38
38
  # spec.required_ruby_version = '>= 2.6'
39
-
40
- spec.add_development_dependency "bundler", "~> 1.17"
41
- spec.add_development_dependency "rake", "~> 10.0"
42
39
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ gem "minitest"
8
+ gem "simplecov"
@@ -0,0 +1,21 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ docile (1.4.0)
5
+ minitest (5.14.4)
6
+ simplecov (0.21.2)
7
+ docile (~> 1.1)
8
+ simplecov-html (~> 0.11)
9
+ simplecov_json_formatter (~> 0.1)
10
+ simplecov-html (0.12.3)
11
+ simplecov_json_formatter (0.1.3)
12
+
13
+ PLATFORMS
14
+ x86_64-darwin-20
15
+
16
+ DEPENDENCIES
17
+ minitest
18
+ simplecov
19
+
20
+ BUNDLED WITH
21
+ 2.2.3
@@ -0,0 +1,10 @@
1
+ class Adder
2
+ def initialize(a, b)
3
+ @a = a
4
+ @b = b
5
+ end
6
+
7
+ def call
8
+ @a + @b
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
2
+ require "oneshot_coverage"
3
+ require "oneshot_coverage/logger/file_logger"
4
+
5
+ OneshotCoverage.configure(
6
+ target_path: Dir.pwd,
7
+ logger: OneshotCoverage::Logger::FileLogger.new('coverage.json'),
8
+ emit_term: nil,
9
+ cover_bundle_path: ENV["COVER_BUNDLE_PATH"] == "1",
10
+ )
11
+
12
+ OneshotCoverage.start
13
+
14
+ require "minitest"
15
+ require_relative "adder"
16
+
17
+ Adder.new(1, 2).call
@@ -0,0 +1,10 @@
1
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
2
+
3
+ require 'simplecov'
4
+ require 'oneshot_coverage/simplecov_reporter'
5
+
6
+ OneshotCoverage::SimplecovReporter.new(
7
+ project_path: Dir.pwd,
8
+ log_path: 'coverage.json',
9
+ file_filter: OneshotCoverage::SimplecovReporter::DefaultFilter
10
+ ).run
metadata CHANGED
@@ -1,43 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oneshot_coverage
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shia
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-16 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.17'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.17'
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '10.0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '10.0'
11
+ date: 2021-07-14 00:00:00.000000000 Z
12
+ dependencies: []
41
13
  description: OneshotCoverage will help you to measure oneshot coverage on production
42
14
  email:
43
15
  - rise.shia@gmail.com
@@ -45,10 +17,11 @@ executables: []
45
17
  extensions: []
46
18
  extra_rdoc_files: []
47
19
  files:
20
+ - ".github/workflows/main.yml"
48
21
  - ".gitignore"
22
+ - CHANGELOG.md
49
23
  - CODE_OF_CONDUCT.md
50
24
  - Gemfile
51
- - Gemfile.lock
52
25
  - LICENSE.txt
53
26
  - README.md
54
27
  - Rakefile
@@ -59,8 +32,14 @@ files:
59
32
  - lib/oneshot_coverage/logger/null_logger.rb
60
33
  - lib/oneshot_coverage/logger/stdout_logger.rb
61
34
  - lib/oneshot_coverage/railtie.rb
35
+ - lib/oneshot_coverage/simplecov_reporter.rb
62
36
  - lib/oneshot_coverage/version.rb
63
37
  - oneshot_coverage.gemspec
38
+ - target_app/Gemfile
39
+ - target_app/Gemfile.lock
40
+ - target_app/adder.rb
41
+ - target_app/cover_code_test.rb
42
+ - target_app/gen_simplecov_report.rb
64
43
  homepage: https://github.com/riseshia/oneshot_coverage
65
44
  licenses:
66
45
  - MIT
@@ -68,7 +47,7 @@ metadata:
68
47
  homepage_uri: https://github.com/riseshia/oneshot_coverage
69
48
  source_code_uri: https://github.com/riseshia/oneshot_coverage
70
49
  changelog_uri: https://github.com/riseshia/oneshot_coverage
71
- post_install_message:
50
+ post_install_message:
72
51
  rdoc_options: []
73
52
  require_paths:
74
53
  - lib
@@ -83,8 +62,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
83
62
  - !ruby/object:Gem::Version
84
63
  version: '0'
85
64
  requirements: []
86
- rubygems_version: 3.0.3
87
- signing_key:
65
+ rubygems_version: 3.2.3
66
+ signing_key:
88
67
  specification_version: 4
89
68
  summary: Simple toolbox for oneshot coverage
90
69
  test_files: []
data/Gemfile.lock DELETED
@@ -1,20 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- oneshot_coverage (0.1.0)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- rake (10.5.0)
10
-
11
- PLATFORMS
12
- ruby
13
-
14
- DEPENDENCIES
15
- bundler (~> 1.17)
16
- oneshot_coverage!
17
- rake (~> 10.0)
18
-
19
- BUNDLED WITH
20
- 1.17.2