undercover 0.6.6 → 0.7.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 +4 -4
- data/.github/workflows/ruby.yml +4 -4
- data/.tool-versions +1 -0
- data/CHANGELOG.md +12 -1
- data/Gemfile +2 -1
- data/README.md +37 -13
- data/docs/actions.yml +19 -0
- data/docs/circleci_advanced.yml +3 -3
- data/docs/circleci_config.yml +1 -1
- data/lib/undercover/changeset.rb +0 -1
- data/lib/undercover/cli.rb +1 -1
- data/lib/undercover/lcov_parser.rb +14 -4
- data/lib/undercover/options.rb +18 -0
- data/lib/undercover/result.rb +17 -4
- data/lib/undercover/root_to_relative_paths.rb +24 -0
- data/lib/undercover/simplecov_formatter.rb +59 -0
- data/lib/undercover/simplecov_result_adapter.rb +63 -0
- data/lib/undercover/version.rb +1 -1
- data/lib/undercover.rb +12 -4
- data/undercover.gemspec +2 -0
- metadata +34 -4
- data/docs/codeship.md +0 -19
- data/docs/travis.yml +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 440dce283cf6e85e2f59930af7e1c25f40fa1b2f2d67ba881d03435dcd206787
|
4
|
+
data.tar.gz: 04fc58376332676fb2ba14571510bd55529fa26ca6b5c5377691c0f91032f394
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b59a9e99fd2dea093b43a4cba70f64f2c10490c42c7ccf1fe7ed74a943daba3e4f960cbabff9e6fc6da2f97fb863ea75511d2d2335d9cff8d44f9f4217829017
|
7
|
+
data.tar.gz: 42721ec8490eb12828a2afc31578bc9747a6ae45ed99b90abcefe71bdb652de1331153a0cb24bec5a12cb4615594482052347f6a19547d286ca175fa7fe568e3
|
data/.github/workflows/ruby.yml
CHANGED
@@ -25,18 +25,18 @@ jobs:
|
|
25
25
|
undercover --compare master
|
26
26
|
- uses: actions/upload-artifact@v4
|
27
27
|
with:
|
28
|
-
name: undercover-${{ matrix.ruby }}
|
29
|
-
path: coverage/
|
28
|
+
name: undercover-${{ matrix.ruby }}-coverage
|
29
|
+
path: coverage/undercover_coverage.json
|
30
30
|
coverage:
|
31
31
|
runs-on: ubuntu-latest
|
32
32
|
needs: build
|
33
33
|
steps:
|
34
34
|
- uses: actions/download-artifact@v4
|
35
35
|
with:
|
36
|
-
name: undercover-3.4
|
36
|
+
name: undercover-3.4-coverage
|
37
37
|
- name: Upload coverage
|
38
38
|
run: |
|
39
39
|
ruby -e "$(curl -s https://undercover-ci.com/uploader.rb)" -- \
|
40
40
|
--repo grodowski/undercover \
|
41
41
|
--commit ${{ github.event.pull_request.head.sha || github.sha }} \
|
42
|
-
--
|
42
|
+
--simplecov /home/runner/work/undercover/undercover/undercover_coverage.json
|
data/.tool-versions
CHANGED
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
# [0.7.0] - 2025-07-03
|
10
|
+
|
11
|
+
### Added
|
12
|
+
- New native SimpleCov formatter that generates coverage data directly without requiring LCOV conversion ([#223](https://github.com/grodowski/undercover/pull/223))
|
13
|
+
- `--simplecov -s` CLI option to specify coverage JSON file path as an alternative to LCOV and future default ([#223](https://github.com/grodowski/undercover/pull/223))
|
14
|
+
- Improved path handling for projects running in nested subdirectories or monorepo setups ([#223](https://github.com/grodowski/undercover/pull/223))
|
15
|
+
|
16
|
+
### Fixed
|
17
|
+
- `:nocov:` support to skip coverage analysis for specific code blocks works again after a regression in `0.6+` ([#223](https://github.com/grodowski/undercover/pull/223))
|
18
|
+
|
9
19
|
# [0.6.6] - 2025-07-01
|
10
20
|
|
11
21
|
- Bugfix in `max_warnings_limit` following ([#229](https://github.com/grodowski/undercover/pull/229))
|
@@ -157,7 +167,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
157
167
|
### Added
|
158
168
|
- First release of `undercover` 🎉
|
159
169
|
|
160
|
-
[Unreleased]: https://github.com/grodowski/undercover/compare/v0.
|
170
|
+
[Unreleased]: https://github.com/grodowski/undercover/compare/v0.7.0...HEAD
|
171
|
+
[0.7.0]: https://github.com/grodowski/undercover/compare/v0.6.6...v0.7.0
|
161
172
|
[0.6.6]: https://github.com/grodowski/undercover/compare/v0.6.5...0.6.6
|
162
173
|
[0.6.5]: https://github.com/grodowski/undercover/compare/v0.6.4...0.6.5
|
163
174
|
[0.6.4]: https://github.com/grodowski/undercover/compare/v0.6.3...v0.6.4
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -35,34 +35,58 @@ Or install it yourself as:
|
|
35
35
|
|
36
36
|
$ gem install undercover
|
37
37
|
|
38
|
-
## Setting up
|
38
|
+
## Setting up coverage reporting
|
39
39
|
|
40
|
-
To make your specs or tests compatible with `undercover
|
40
|
+
To make your specs or tests compatible with `undercover`, please add `undercover` to your gemfile to use the undercover formatter the test helper.
|
41
41
|
|
42
42
|
```ruby
|
43
43
|
# Gemfile
|
44
44
|
group :test do
|
45
|
-
gem '
|
46
|
-
gem 'simplecov-lcov'
|
45
|
+
gem 'undercover'
|
47
46
|
end
|
48
47
|
|
49
48
|
# the very top of spec_helper.rb
|
50
49
|
require 'simplecov'
|
51
|
-
require '
|
52
|
-
|
53
|
-
|
50
|
+
require 'undercover/simplecov_formatter'
|
51
|
+
|
52
|
+
# optional, will default to coverage.json
|
53
|
+
SimpleCov::Formatter::Undercover.output_filename = 'my_project_coverage.json'
|
54
|
+
SimpleCov.formatter = SimpleCov::Formatter::Undercover
|
55
|
+
|
54
56
|
SimpleCov.start do
|
55
57
|
add_filter(/^\/spec\//) # For RSpec
|
56
58
|
add_filter(/^\/test\//) # For Minitest
|
57
59
|
enable_coverage(:branch) # Report branch coverage to trigger branch-level undercover warnings
|
58
60
|
end
|
61
|
+
# ...
|
62
|
+
```
|
59
63
|
|
60
|
-
|
64
|
+
Then run your test suite once through to generate the initial coverage file before you can run the `undercover` command.
|
61
65
|
|
62
|
-
|
66
|
+
## Upgrading from pre-0.7.0
|
67
|
+
|
68
|
+
If you're upgrading from an older version of undercover that used LCOV, you can migrate to the new SimpleCov formatter:
|
69
|
+
|
70
|
+
1. Add `gem 'undercover'` to your test group
|
71
|
+
2. Replace the LCOV formatter setup with the new SimpleCov formatter
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
# Gemfile
|
75
|
+
group :test do
|
76
|
+
gem 'simplecov'
|
77
|
+
gem 'simplecov_json_formatter'
|
78
|
+
gem 'undercover'
|
79
|
+
end
|
80
|
+
|
81
|
+
# spec_helper.rb
|
82
|
+
require 'simplecov'
|
83
|
+
require 'undercover/simplecov_formatter'
|
84
|
+
SimpleCov.formatter = SimpleCov::Formatter::Undercover
|
63
85
|
```
|
64
86
|
|
65
|
-
|
87
|
+
3. Update CLI usage: Use `--simplecov` flag instead of `--lcov`, or rely on auto-detection of `coverage/coverage.json`
|
88
|
+
|
89
|
+
Note: LCOV support will be deprecated in a future release, but remains fully functional for existing projects.
|
66
90
|
|
67
91
|
## Usage
|
68
92
|
|
@@ -79,11 +103,10 @@ undercover --compare origin/master
|
|
79
103
|
```
|
80
104
|
|
81
105
|
Check out `docs/` for CI configuration examples:
|
82
|
-
- [
|
106
|
+
- [GitHub Actions](docs/actions.yml)
|
83
107
|
- [CircleCI - simple](docs/circleci_config.yml)
|
84
108
|
- [CircleCI - advanced](docs/circleci_advanced.yml)
|
85
109
|
- [Semaphore](docs/semaphore.yml)
|
86
|
-
- [Codeship](docs/codeship.md)
|
87
110
|
|
88
111
|
Merging coverage results ([sample gist](https://gist.github.com/grodowski/9744ff91034dce8df20c2a8210409fb0)) is required for parallel tests before processing with `undercover`.
|
89
112
|
|
@@ -104,7 +127,8 @@ Options can be passed when running the command from the command line:
|
|
104
127
|
|
105
128
|
```sh
|
106
129
|
Usage: undercover [options]
|
107
|
-
-
|
130
|
+
-s, --simplecov path SimpleCov JSON report file
|
131
|
+
-l, --lcov path LCOV report file path (to be deprecated)
|
108
132
|
-p, --path path Project directory
|
109
133
|
-g, --git-dir dir Override `.git` with a custom directory
|
110
134
|
-c, --compare ref Generate coverage warnings for all changes after `ref`
|
data/docs/actions.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
name: Tests & Undercover
|
2
|
+
on: [push, pull_request]
|
3
|
+
jobs:
|
4
|
+
build:
|
5
|
+
runs-on: ubuntu-latest
|
6
|
+
steps:
|
7
|
+
- uses: actions/checkout@v4
|
8
|
+
- name: Set up Ruby 3.4
|
9
|
+
uses: ruby/setup-ruby@v1
|
10
|
+
with:
|
11
|
+
ruby-version: 3.4
|
12
|
+
- name: Build and test
|
13
|
+
env:
|
14
|
+
RAILS_ENV: test
|
15
|
+
run: |
|
16
|
+
gem install bundler
|
17
|
+
bundle install --jobs 4 --retry 3
|
18
|
+
bundle exec rake test
|
19
|
+
undercover --simplecov coverage/coverage.json --compare origin/master
|
data/docs/circleci_advanced.yml
CHANGED
@@ -20,7 +20,7 @@ jobs:
|
|
20
20
|
bundle exec rspec
|
21
21
|
- run:
|
22
22
|
name: Store coverage report
|
23
|
-
command: mv coverage/
|
23
|
+
command: mv coverage/coverage.json /tmp/coverage/
|
24
24
|
- persist_to_workspace:
|
25
25
|
root: /tmp/coverage
|
26
26
|
paths: .
|
@@ -33,13 +33,13 @@ jobs:
|
|
33
33
|
steps:
|
34
34
|
- checkout
|
35
35
|
- attach_workspace:
|
36
|
-
at: /tmp/coverage # gives access to project's
|
36
|
+
at: /tmp/coverage # gives access to project's coverage report
|
37
37
|
- run:
|
38
38
|
name: Check coverage
|
39
39
|
command: |
|
40
40
|
sudo apt-get install cmake
|
41
41
|
gem install undercover
|
42
|
-
undercover --
|
42
|
+
undercover --simplecov /tmp/coverage/coverage.json \
|
43
43
|
--compare origin/master
|
44
44
|
|
45
45
|
workflows:
|
data/docs/circleci_config.yml
CHANGED
data/lib/undercover/changeset.rb
CHANGED
data/lib/undercover/cli.rb
CHANGED
@@ -24,7 +24,7 @@ module Undercover
|
|
24
24
|
def self.run_report(opts)
|
25
25
|
report = Undercover::Report.new(changeset(opts), opts).build
|
26
26
|
|
27
|
-
error = report.validate(opts.lcov)
|
27
|
+
error = report.validate(opts.simplecov_resultset || opts.lcov)
|
28
28
|
if error
|
29
29
|
puts(WARNINGS_TO_S[error])
|
30
30
|
return 0 if error == :no_changes
|
@@ -1,19 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'undercover/root_to_relative_paths'
|
4
|
+
|
3
5
|
module Undercover
|
4
6
|
LcovParseError = Class.new(StandardError)
|
5
7
|
|
6
8
|
class LcovParser
|
9
|
+
include RootToRelativePaths
|
10
|
+
|
7
11
|
attr_reader :io, :source_files
|
8
12
|
|
9
|
-
def initialize(lcov_io)
|
13
|
+
def initialize(lcov_io, opts)
|
10
14
|
@io = lcov_io
|
11
15
|
@source_files = {}
|
16
|
+
@code_dir = opts&.path
|
12
17
|
end
|
13
18
|
|
14
|
-
def self.parse(lcov_report_path)
|
19
|
+
def self.parse(lcov_report_path, opts = nil)
|
15
20
|
lcov_io = File.open(lcov_report_path)
|
16
|
-
new(lcov_io).parse
|
21
|
+
new(lcov_io, opts).parse
|
17
22
|
end
|
18
23
|
|
19
24
|
def parse
|
@@ -24,7 +29,7 @@ module Undercover
|
|
24
29
|
|
25
30
|
def coverage(filepath)
|
26
31
|
_filename, coverage = source_files.find do |relative_path, _|
|
27
|
-
relative_path == filepath
|
32
|
+
relative_path == fix_relative_filepath(filepath)
|
28
33
|
end
|
29
34
|
coverage || []
|
30
35
|
end
|
@@ -47,6 +52,11 @@ module Undercover
|
|
47
52
|
total_f.round(3)
|
48
53
|
end
|
49
54
|
|
55
|
+
def skipped?(_filepath, _line_no)
|
56
|
+
# this is why lcov parser will be deprecated
|
57
|
+
false
|
58
|
+
end
|
59
|
+
|
50
60
|
private
|
51
61
|
|
52
62
|
# rubocop:disable Metrics/MethodLength, Style/SpecialGlobalVars, Metrics/AbcSize
|
data/lib/undercover/options.rb
CHANGED
@@ -34,6 +34,7 @@ module Undercover
|
|
34
34
|
DEFAULT_FILE_EXCLUDE_GLOBS = %w[test/* spec/* db/* config/* *_test.rb *_spec.rb].freeze
|
35
35
|
|
36
36
|
attr_accessor :lcov,
|
37
|
+
:simplecov_resultset,
|
37
38
|
:path,
|
38
39
|
:git_dir,
|
39
40
|
:compare,
|
@@ -68,11 +69,14 @@ module Undercover
|
|
68
69
|
end
|
69
70
|
|
70
71
|
opts.on_tail('--version', 'Show version') do
|
72
|
+
# :nocov:
|
71
73
|
puts VERSION
|
72
74
|
exit
|
75
|
+
# :nocov:
|
73
76
|
end
|
74
77
|
|
75
78
|
lcov_path_option(opts)
|
79
|
+
resultset_path_option(opts)
|
76
80
|
project_path_option(opts)
|
77
81
|
git_dir_option(opts)
|
78
82
|
compare_option(opts)
|
@@ -81,6 +85,7 @@ module Undercover
|
|
81
85
|
file_filters(opts)
|
82
86
|
end.parse(args)
|
83
87
|
|
88
|
+
guess_resultset_path unless simplecov_resultset
|
84
89
|
guess_lcov_path unless lcov
|
85
90
|
self
|
86
91
|
end
|
@@ -112,6 +117,13 @@ module Undercover
|
|
112
117
|
end
|
113
118
|
end
|
114
119
|
|
120
|
+
def resultset_path_option(parser)
|
121
|
+
desc = 'SimpleCov::Formatter::Undercover output file path (alternative to LCOV that will become default)'
|
122
|
+
parser.on('-s', '--simplecov path', desc) do |path|
|
123
|
+
self.simplecov_resultset = path
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
115
127
|
def project_path_option(parser)
|
116
128
|
parser.on('-p', '--path path', 'Project directory') do |path|
|
117
129
|
self.path = path
|
@@ -147,6 +159,12 @@ module Undercover
|
|
147
159
|
end
|
148
160
|
end
|
149
161
|
|
162
|
+
def guess_resultset_path
|
163
|
+
cwd = Pathname.new(File.expand_path(path))
|
164
|
+
try_path = File.join(cwd, 'coverage', 'coverage.json')
|
165
|
+
self.simplecov_resultset = try_path if File.exist?(try_path)
|
166
|
+
end
|
167
|
+
|
150
168
|
def guess_lcov_path
|
151
169
|
cwd = Pathname.new(File.expand_path(path))
|
152
170
|
self.lcov = File.join(cwd, 'coverage', 'lcov', "#{cwd.split.last}.lcov")
|
data/lib/undercover/result.rb
CHANGED
@@ -3,15 +3,18 @@
|
|
3
3
|
require 'forwardable'
|
4
4
|
|
5
5
|
module Undercover
|
6
|
-
class Result
|
6
|
+
class Result # rubocop:disable Metrics/ClassLength
|
7
7
|
extend Forwardable
|
8
8
|
|
9
|
-
attr_reader :node, :coverage, :file_path
|
9
|
+
attr_reader :node, :coverage, :coverage_adapter, :file_path
|
10
10
|
|
11
11
|
def_delegators :node, :first_line, :last_line, :name
|
12
|
+
def_delegators :coverage_adapter, :skipped?
|
12
13
|
|
13
|
-
def initialize(node,
|
14
|
+
def initialize(node, coverage_adapter, file_path) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
|
14
15
|
@node = node
|
16
|
+
@coverage_adapter = coverage_adapter
|
17
|
+
file_cov = coverage_adapter.coverage(file_path)
|
15
18
|
@coverage = file_cov.select do |ln, _|
|
16
19
|
if first_line == last_line
|
17
20
|
ln == first_line
|
@@ -21,6 +24,7 @@ module Undercover
|
|
21
24
|
ln > first_line && ln < last_line
|
22
25
|
end
|
23
26
|
end
|
27
|
+
|
24
28
|
@file_path = file_path
|
25
29
|
@flagged = false
|
26
30
|
end
|
@@ -33,7 +37,8 @@ module Undercover
|
|
33
37
|
@flagged
|
34
38
|
end
|
35
39
|
|
36
|
-
def uncovered?(line_no)
|
40
|
+
def uncovered?(line_no) # rubocop:disable Metrics/AbcSize
|
41
|
+
return false if skipped?(file_path, line_no)
|
37
42
|
return true if coverage.empty?
|
38
43
|
|
39
44
|
# check branch coverage for line_no
|
@@ -55,6 +60,11 @@ module Undercover
|
|
55
60
|
|
56
61
|
lines = {}
|
57
62
|
coverage.each do |ln, block_or_line_cov, _, branch_cov|
|
63
|
+
if skipped?(file_path, ln)
|
64
|
+
lines[ln] = 1
|
65
|
+
next
|
66
|
+
end
|
67
|
+
|
58
68
|
lines[ln] = 1 unless lines.key?(ln)
|
59
69
|
if branch_cov
|
60
70
|
lines[ln] = 0 if branch_cov.zero?
|
@@ -93,6 +103,9 @@ module Undercover
|
|
93
103
|
formatted_line = "#{num.to_s.rjust(pad)}: #{line}"
|
94
104
|
if line.strip.empty?
|
95
105
|
Rainbow(formatted_line).darkgray.dark
|
106
|
+
elsif skipped?(file_path, num)
|
107
|
+
Rainbow(formatted_line).darkgray.dark +
|
108
|
+
Rainbow(' skipped with :nocov:').italic.darkgray.dark
|
96
109
|
elsif covered.nil?
|
97
110
|
Rainbow(formatted_line).darkgray.dark +
|
98
111
|
Rainbow(' hits: n/a').italic.darkgray.dark
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Undercover
|
4
|
+
module RootToRelativePaths
|
5
|
+
# Needed if undercover is running inside nested subdirectories (e.g. in a monorepo app), where
|
6
|
+
# the git paths are rooted deeper than the paths in the coverage report.
|
7
|
+
# If that is the case, trim the git filepath to match the local relative path, assumming undercover is
|
8
|
+
# running in the correct directory (has to be equal to SimpleCov.root for paths to match)
|
9
|
+
# @param filepath[String]
|
10
|
+
# @return String
|
11
|
+
def fix_relative_filepath(filepath)
|
12
|
+
return filepath unless @code_dir
|
13
|
+
|
14
|
+
code_dir_abs = File.expand_path(@code_dir)
|
15
|
+
|
16
|
+
if Pathname.new(Dir.pwd).ascend.any? { |p| p.to_s == code_dir_abs }
|
17
|
+
prefix_to_skip = Pathname.new(Dir.pwd).relative_path_from(code_dir_abs).to_s
|
18
|
+
return filepath.delete_prefix(prefix_to_skip).gsub(/\A\//, '')
|
19
|
+
end
|
20
|
+
|
21
|
+
filepath
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'simplecov_json_formatter'
|
4
|
+
|
5
|
+
# Patch ResultExporter to allow setting a custom export_path
|
6
|
+
module SimpleCovJSONFormatter
|
7
|
+
class ResultExporter
|
8
|
+
def export_path
|
9
|
+
# :nocov:
|
10
|
+
File.join(SimpleCov.coverage_path, SimpleCov::Formatter::Undercover.output_filename || FILENAME)
|
11
|
+
# :nocov:
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module Undercover
|
17
|
+
class ResultHashFormatterWithRoot < SimpleCovJSONFormatter::ResultHashFormatter
|
18
|
+
def format
|
19
|
+
formatted_result[:meta] = {timestamp: @result.created_at.to_i}
|
20
|
+
format_files
|
21
|
+
add_undercover_meta_fields
|
22
|
+
formatted_result
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def add_undercover_meta_fields
|
28
|
+
formatted_result.tap do |result|
|
29
|
+
result[:meta].merge!(simplecov_root: SimpleCov.root)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# format_files uses relative path as keys, as opposed to the superclass method
|
34
|
+
def format_files
|
35
|
+
formatted_result[:coverage] ||= {}
|
36
|
+
@result.files.each do |source_file|
|
37
|
+
path = source_file.project_filename.delete_prefix('/')
|
38
|
+
formatted_result[:coverage][path] = format_source_file(source_file)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class UndercoverSimplecovFormatter < SimpleCov::Formatter::JSONFormatter
|
44
|
+
class << self
|
45
|
+
attr_accessor :output_filename
|
46
|
+
end
|
47
|
+
|
48
|
+
def format_result(result)
|
49
|
+
result_hash_formater = ResultHashFormatterWithRoot.new(result)
|
50
|
+
result_hash_formater.format
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
module SimpleCov
|
56
|
+
module Formatter
|
57
|
+
Undercover = ::Undercover::UndercoverSimplecovFormatter
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'undercover/root_to_relative_paths'
|
4
|
+
|
5
|
+
module Undercover
|
6
|
+
class SimplecovResultAdapter
|
7
|
+
include RootToRelativePaths
|
8
|
+
|
9
|
+
attr_reader :simplecov_result
|
10
|
+
|
11
|
+
# @param file[File] JSON file supplied by SimpleCov::Formatter::Undercover
|
12
|
+
# @return SimplecovResultAdapter
|
13
|
+
def self.parse(file, opts = nil)
|
14
|
+
# :nocov:
|
15
|
+
result_h = JSON.parse(file.read)
|
16
|
+
raise ArgumentError, 'empty SimpleCov' if result_h.empty?
|
17
|
+
|
18
|
+
new(result_h, opts)
|
19
|
+
# :nocov:
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param simplecov_result[SimpleCov::Result]
|
23
|
+
def initialize(simplecov_result, opts)
|
24
|
+
@simplecov_result = simplecov_result
|
25
|
+
@code_dir = opts&.path
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param filepath[String]
|
29
|
+
# @return Array tuples (lines) and quadruples (branches) compatible with LcovParser
|
30
|
+
def coverage(filepath) # rubocop:disable Metrics/MethodLength
|
31
|
+
source_file = find_file(filepath)
|
32
|
+
|
33
|
+
return [] unless source_file
|
34
|
+
|
35
|
+
lines = source_file['lines'].map.with_index do |line_coverage, idx|
|
36
|
+
[idx + 1, line_coverage] if line_coverage
|
37
|
+
end.compact
|
38
|
+
branch_idx = 0
|
39
|
+
branches = source_file['branches'].map do |branch|
|
40
|
+
branch_idx += 1
|
41
|
+
[branch['start_line'], 0, branch_idx, branch['coverage']]
|
42
|
+
end
|
43
|
+
lines + branches
|
44
|
+
end
|
45
|
+
|
46
|
+
def skipped?(filepath, line_no)
|
47
|
+
source_file = find_file(filepath)
|
48
|
+
return false unless source_file
|
49
|
+
|
50
|
+
source_file['lines'][line_no - 1] == 'ignored'
|
51
|
+
end
|
52
|
+
|
53
|
+
# unused for now
|
54
|
+
def total_coverage; end
|
55
|
+
def total_branch_coverage; end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def find_file(filepath)
|
60
|
+
simplecov_result['coverage'][fix_relative_filepath(filepath)]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/undercover/version.rb
CHANGED
data/lib/undercover.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
$LOAD_PATH << 'lib'
|
4
|
+
require 'json'
|
4
5
|
require 'imagen'
|
5
6
|
require 'rainbow'
|
6
7
|
require 'bigdecimal'
|
7
8
|
require 'forwardable'
|
9
|
+
require 'simplecov'
|
8
10
|
|
9
11
|
require 'undercover/lcov_parser'
|
10
12
|
require 'undercover/result'
|
@@ -13,6 +15,7 @@ require 'undercover/changeset'
|
|
13
15
|
require 'undercover/formatter'
|
14
16
|
require 'undercover/options'
|
15
17
|
require 'undercover/filter_set'
|
18
|
+
require 'undercover/simplecov_result_adapter'
|
16
19
|
require 'undercover/version'
|
17
20
|
|
18
21
|
module Undercover
|
@@ -22,6 +25,7 @@ module Undercover
|
|
22
25
|
|
23
26
|
attr_reader :changeset,
|
24
27
|
:lcov,
|
28
|
+
:simplecov_resultset,
|
25
29
|
:results,
|
26
30
|
:code_dir,
|
27
31
|
:filter_set,
|
@@ -32,7 +36,11 @@ module Undercover
|
|
32
36
|
# @param changeset [Undercover::Changeset]
|
33
37
|
# @param opts [Undercover::Options]
|
34
38
|
def initialize(changeset, opts)
|
35
|
-
|
39
|
+
if opts.simplecov_resultset
|
40
|
+
@simplecov_resultset = SimplecovResultAdapter.parse(File.open(opts.simplecov_resultset), opts)
|
41
|
+
end
|
42
|
+
@lcov = LcovParser.parse(File.open(opts.lcov), opts)
|
43
|
+
|
36
44
|
@code_dir = opts.path
|
37
45
|
@changeset = changeset
|
38
46
|
@filter_set = FilterSet.new(opts.glob_allow_filters, opts.glob_reject_filters)
|
@@ -102,9 +110,6 @@ module Undercover
|
|
102
110
|
def load_and_parse_file(filepath)
|
103
111
|
key = filepath.gsub(/^\.\//, '')
|
104
112
|
return if loaded_files[key]
|
105
|
-
|
106
|
-
coverage = lcov.coverage(filepath)
|
107
|
-
|
108
113
|
return unless include_file?(filepath)
|
109
114
|
|
110
115
|
root_ast = Imagen::Node::Root.new.build_from_file(
|
@@ -112,6 +117,9 @@ module Undercover
|
|
112
117
|
)
|
113
118
|
return if root_ast.children.empty?
|
114
119
|
|
120
|
+
# lcov will be deprecated at some point and we'll be able to refactor harder
|
121
|
+
coverage = simplecov_resultset || lcov
|
122
|
+
|
115
123
|
loaded_files[key] = []
|
116
124
|
root_ast.find_all(->(node) { !node.is_a?(Imagen::Node::Root) }).each do |imagen_node|
|
117
125
|
loaded_files[key] << Result.new(imagen_node, coverage, filepath)
|
data/undercover.gemspec
CHANGED
@@ -32,4 +32,6 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.add_dependency 'imagen', '>= 0.2.0'
|
33
33
|
spec.add_dependency 'rainbow', '>= 2.1', '< 4.0'
|
34
34
|
spec.add_dependency 'rugged', '>= 0.27', '< 1.10'
|
35
|
+
spec.add_dependency 'simplecov'
|
36
|
+
spec.add_dependency 'simplecov_json_formatter'
|
35
37
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: undercover
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Grodowski
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-07-
|
10
|
+
date: 2025-07-03 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: base64
|
@@ -91,6 +91,34 @@ dependencies:
|
|
91
91
|
- - "<"
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '1.10'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: simplecov
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
type: :runtime
|
102
|
+
prerelease: false
|
103
|
+
version_requirements: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
- !ruby/object:Gem::Dependency
|
109
|
+
name: simplecov_json_formatter
|
110
|
+
requirement: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
type: :runtime
|
116
|
+
prerelease: false
|
117
|
+
version_requirements: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
94
122
|
email:
|
95
123
|
- jgrodowski@gmail.com
|
96
124
|
executables:
|
@@ -112,13 +140,12 @@ files:
|
|
112
140
|
- README.md
|
113
141
|
- Rakefile
|
114
142
|
- bin/undercover
|
143
|
+
- docs/actions.yml
|
115
144
|
- docs/circleci_advanced.yml
|
116
145
|
- docs/circleci_config.yml
|
117
|
-
- docs/codeship.md
|
118
146
|
- docs/screenshot_success.png
|
119
147
|
- docs/screenshot_warnings.png
|
120
148
|
- docs/semaphore.yml
|
121
|
-
- docs/travis.yml
|
122
149
|
- lib/undercover.rb
|
123
150
|
- lib/undercover/changeset.rb
|
124
151
|
- lib/undercover/cli.rb
|
@@ -127,6 +154,9 @@ files:
|
|
127
154
|
- lib/undercover/lcov_parser.rb
|
128
155
|
- lib/undercover/options.rb
|
129
156
|
- lib/undercover/result.rb
|
157
|
+
- lib/undercover/root_to_relative_paths.rb
|
158
|
+
- lib/undercover/simplecov_formatter.rb
|
159
|
+
- lib/undercover/simplecov_result_adapter.rb
|
130
160
|
- lib/undercover/version.rb
|
131
161
|
- undercover.gemspec
|
132
162
|
homepage: https://github.com/grodowski/undercover
|
data/docs/codeship.md
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
Sample configuration to run `undercover` in Codeship CI. Edit these fields in **Project Settings**.
|
2
|
-
|
3
|
-
**Setup commands**
|
4
|
-
|
5
|
-
```
|
6
|
-
rvm use 2.5.3 --install
|
7
|
-
bundle install
|
8
|
-
gem install undercover
|
9
|
-
```
|
10
|
-
|
11
|
-
**Test pipeline**
|
12
|
-
|
13
|
-
```
|
14
|
-
bundle exec rspec --format documentation --color
|
15
|
-
# fetch origin/master to have a ref to compare against
|
16
|
-
git remote set-branches --add origin master
|
17
|
-
git fetch
|
18
|
-
undercover -c origin/master
|
19
|
-
```
|
data/docs/travis.yml
DELETED