undercover 0.6.4 → 0.7.4
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 +6 -6
- data/.tool-versions +1 -0
- data/CHANGELOG.md +48 -3
- data/Gemfile +2 -1
- data/README.md +36 -14
- 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 +15 -28
- data/lib/undercover/cli.rb +23 -2
- data/lib/undercover/filter_set.rb +17 -0
- data/lib/undercover/lcov_parser.rb +14 -4
- data/lib/undercover/options.rb +48 -5
- data/lib/undercover/result.rb +18 -5
- 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 +65 -0
- data/lib/undercover/version.rb +1 -1
- data/lib/undercover.rb +26 -13
- data/undercover.gemspec +2 -0
- metadata +35 -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: fb439eb426932d432434081cf9e17cce9b19b90a85c71b6a4c173d20cceb9392
|
4
|
+
data.tar.gz: a2703dd7d19a18f943dd3fdaebc34faf23cc995b1cc94b673756f1b5142cf046
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 034ff6bd2826c4826b06780bd874e28c04c8fbcb0fcde85a5c0a1dd8901e4f5d2ebfe6c149b828c0fcf28fd4064f14ef122f69c763f59170b62d99941281d44b
|
7
|
+
data.tar.gz: 114c9a9873fb75c17a3bfe79612bfe8d2891cd2d2b2dd68f8253d49f3529def86bca607d4774d1f113ade2fd8eb2d6d5d55e53d4b47b4a5464c3a6075eb2da3b
|
data/.github/workflows/ruby.yml
CHANGED
@@ -18,25 +18,25 @@ jobs:
|
|
18
18
|
run: |
|
19
19
|
gem install bundler undercover --no-doc
|
20
20
|
bundle install --jobs 4 --retry 3
|
21
|
-
|
21
|
+
rake
|
22
22
|
- name: undercover (local)
|
23
23
|
run: |
|
24
24
|
git fetch --update-head-ok origin master:master
|
25
|
-
undercover --compare master
|
25
|
+
undercover --simplecov coverage/undercover_coverage.json --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,43 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
# [0.7.4] - 2025-07-13
|
10
|
+
|
11
|
+
### Fixed
|
12
|
+
- Fix `fnmatch` for `FilterSet` to support glob braces (sets) in `--include-files` and `--exclude-files`
|
13
|
+
|
14
|
+
# [0.7.3] - 2025-07-13
|
15
|
+
|
16
|
+
### Fixed
|
17
|
+
- Improve Options#parse with glob braces support, strip quotes properly from .undercover config files
|
18
|
+
- Fix Result#coverage_f to support ignored branches
|
19
|
+
- Fix error parsing JSON coverage with branch coverage disabled ([#231](https://github.com/grodowski/undercover/issues/231))
|
20
|
+
- Fixed NoMethodError and Errno::ENOENT that were occurring when coverage report doesn't exist ([#232](https://github.com/grodowski/undercover/issues/232))
|
21
|
+
|
22
|
+
# [0.7.2] - 2025-07-07
|
23
|
+
|
24
|
+
### Fixed
|
25
|
+
- Resolved errors when .lcov files doesn't exist using `--lcov` CLI flag and `guess_lcov_path`
|
26
|
+
|
27
|
+
# [0.7.0] - 2025-07-03
|
28
|
+
|
29
|
+
### Added
|
30
|
+
- New native SimpleCov formatter that generates coverage data directly without requiring LCOV conversion ([#223](https://github.com/grodowski/undercover/pull/223))
|
31
|
+
- `--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))
|
32
|
+
- Improved path handling for projects running in nested subdirectories or monorepo setups ([#223](https://github.com/grodowski/undercover/pull/223))
|
33
|
+
|
34
|
+
### Fixed
|
35
|
+
- `: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))
|
36
|
+
|
37
|
+
# [0.6.6] - 2025-07-01
|
38
|
+
|
39
|
+
- Bugfix in `max_warnings_limit` following ([#229](https://github.com/grodowski/undercover/pull/229))
|
40
|
+
|
41
|
+
# [0.6.5] - 2025-07-01
|
42
|
+
|
43
|
+
### Fixed
|
44
|
+
- Improved performance for large PRs with lazy diff enumeration ([#229](https://github.com/grodowski/undercover/pull/229))
|
45
|
+
|
9
46
|
# [0.6.4] - 2025-03-29
|
10
47
|
|
11
48
|
### Fixed
|
@@ -148,9 +185,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
148
185
|
### Added
|
149
186
|
- First release of `undercover` 🎉
|
150
187
|
|
151
|
-
[Unreleased]: https://github.com/grodowski/undercover/compare/v0.
|
152
|
-
[0.
|
153
|
-
[0.
|
188
|
+
[Unreleased]: https://github.com/grodowski/undercover/compare/v0.7.4...HEAD
|
189
|
+
[0.7.4]: https://github.com/grodowski/undercover/compare/v0.7.3...v0.7.4
|
190
|
+
[0.7.3]: https://github.com/grodowski/undercover/compare/v0.7.2...v0.7.3
|
191
|
+
[0.7.2]: https://github.com/grodowski/undercover/compare/v0.7.1...v0.7.2
|
192
|
+
[0.7.1]: https://github.com/grodowski/undercover/compare/v0.7.0...v0.7.1
|
193
|
+
[0.7.0]: https://github.com/grodowski/undercover/compare/v0.6.6...v0.7.0
|
194
|
+
[0.6.6]: https://github.com/grodowski/undercover/compare/v0.6.5...0.6.6
|
195
|
+
[0.6.5]: https://github.com/grodowski/undercover/compare/v0.6.4...0.6.5
|
196
|
+
[0.6.4]: https://github.com/grodowski/undercover/compare/v0.6.3...v0.6.4
|
197
|
+
[0.6.3]: https://github.com/grodowski/undercover/compare/v0.6.0...v0.6.3
|
198
|
+
[0.6.0]: https://github.com/grodowski/undercover/compare/v0.5.0...v0.6.0
|
154
199
|
[0.5.0]: https://github.com/grodowski/undercover/compare/v0.4.7...v0.5.0
|
155
200
|
[0.4.7]: https://github.com/grodowski/undercover/compare/v0.4.6...v0.4.7
|
156
201
|
[0.4.6]: https://github.com/grodowski/undercover/compare/v0.4.5...v0.4.6
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -9,7 +9,6 @@ Works with any Ruby CI pipeline as well as locally as a CLI.
|
|
9
9
|
|
10
10
|
|
11
11
|
[](https://github.com/grodowski/undercover/actions)
|
12
|
-
[](https://codeclimate.com/github/grodowski/undercover/maintainability)
|
13
12
|

|
14
13
|
|
15
14
|
A sample output of `undercover` ran before a commit may look like this:
|
@@ -36,34 +35,56 @@ Or install it yourself as:
|
|
36
35
|
|
37
36
|
$ gem install undercover
|
38
37
|
|
39
|
-
## Setting up
|
38
|
+
## Setting up coverage reporting
|
40
39
|
|
41
|
-
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.
|
42
41
|
|
43
42
|
```ruby
|
44
43
|
# Gemfile
|
45
44
|
group :test do
|
46
|
-
gem '
|
47
|
-
gem 'simplecov-lcov'
|
45
|
+
gem 'undercover'
|
48
46
|
end
|
49
47
|
|
50
48
|
# the very top of spec_helper.rb
|
51
49
|
require 'simplecov'
|
52
|
-
require '
|
53
|
-
|
54
|
-
|
50
|
+
require 'undercover/simplecov_formatter'
|
51
|
+
|
52
|
+
# optional, the filename defaults to `coverage.json` and is automatically recognised by the gem
|
53
|
+
# SimpleCov::Formatter::Undercover.output_filename = 'my_project_coverage.json'
|
54
|
+
SimpleCov.formatter = SimpleCov::Formatter::Undercover
|
55
|
+
|
55
56
|
SimpleCov.start do
|
56
57
|
add_filter(/^\/spec\//) # For RSpec
|
57
58
|
add_filter(/^\/test\//) # For Minitest
|
58
59
|
enable_coverage(:branch) # Report branch coverage to trigger branch-level undercover warnings
|
59
60
|
end
|
61
|
+
# ...
|
62
|
+
```
|
60
63
|
|
61
|
-
|
64
|
+
Then run your test suite once through to generate the initial coverage file before you can run the `undercover` command.
|
62
65
|
|
63
|
-
|
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 'undercover'
|
77
|
+
end
|
78
|
+
|
79
|
+
# spec_helper.rb
|
80
|
+
require 'simplecov'
|
81
|
+
require 'undercover/simplecov_formatter'
|
82
|
+
SimpleCov.formatter = SimpleCov::Formatter::Undercover
|
64
83
|
```
|
65
84
|
|
66
|
-
|
85
|
+
3. Update CLI usage: Use `--simplecov` flag instead of `--lcov`, or rely on auto-detection of `coverage/coverage.json`
|
86
|
+
|
87
|
+
Note: LCOV support will be deprecated in a future release, but remains fully functional for existing projects.
|
67
88
|
|
68
89
|
## Usage
|
69
90
|
|
@@ -80,11 +101,10 @@ undercover --compare origin/master
|
|
80
101
|
```
|
81
102
|
|
82
103
|
Check out `docs/` for CI configuration examples:
|
83
|
-
- [
|
104
|
+
- [GitHub Actions](docs/actions.yml)
|
84
105
|
- [CircleCI - simple](docs/circleci_config.yml)
|
85
106
|
- [CircleCI - advanced](docs/circleci_advanced.yml)
|
86
107
|
- [Semaphore](docs/semaphore.yml)
|
87
|
-
- [Codeship](docs/codeship.md)
|
88
108
|
|
89
109
|
Merging coverage results ([sample gist](https://gist.github.com/grodowski/9744ff91034dce8df20c2a8210409fb0)) is required for parallel tests before processing with `undercover`.
|
90
110
|
|
@@ -105,11 +125,13 @@ Options can be passed when running the command from the command line:
|
|
105
125
|
|
106
126
|
```sh
|
107
127
|
Usage: undercover [options]
|
108
|
-
-
|
128
|
+
-s, --simplecov path SimpleCov JSON report file
|
129
|
+
-l, --lcov path LCOV report file path (to be deprecated)
|
109
130
|
-p, --path path Project directory
|
110
131
|
-g, --git-dir dir Override `.git` with a custom directory
|
111
132
|
-c, --compare ref Generate coverage warnings for all changes after `ref`
|
112
133
|
-r, --ruby-syntax ver Ruby syntax version, one of: current, ruby18, ruby19, ruby20, ruby21, ruby22, ruby23, ruby24, ruby25, ruby26, ruby30, ruby31, ruby32, ruby33
|
134
|
+
-w, --max-warnings limit Maximum number of warnings to generate before stopping analysis. Useful as a performance improvement for large diffs.
|
113
135
|
-f, --include-files globs Include files matching specified glob patterns (comma separated). Defaults to '*.rb,*.rake,*.ru,Rakefile'
|
114
136
|
-x, --exclude-files globs Skip files matching specified glob patterns (comma separated). Empty by default.
|
115
137
|
-h, --help Prints this help
|
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
@@ -8,31 +8,12 @@ module Undercover
|
|
8
8
|
class Changeset
|
9
9
|
T_ZERO = Time.strptime('0', '%s').freeze
|
10
10
|
|
11
|
-
|
12
|
-
include Enumerable
|
13
|
-
|
14
|
-
attr_reader :files
|
15
|
-
|
16
|
-
def_delegators :files, :each, :<=>
|
17
|
-
|
18
|
-
def initialize(dir, compare_base = nil)
|
11
|
+
def initialize(dir, compare_base = nil, filter_set = nil)
|
19
12
|
@dir = dir
|
20
13
|
@repo = Rugged::Repository.new(dir)
|
21
14
|
@repo.workdir = Pathname.new(dir).dirname.to_s # TODO: can replace?
|
22
15
|
@compare_base = compare_base
|
23
|
-
@
|
24
|
-
end
|
25
|
-
|
26
|
-
def update
|
27
|
-
full_diff.each_patch do |patch|
|
28
|
-
filepath = patch.delta.new_file[:path]
|
29
|
-
line_nums = patch.each_hunk.map do |hunk|
|
30
|
-
# TODO: optimise this to use line ranges!
|
31
|
-
hunk.lines.select(&:addition?).map(&:new_lineno)
|
32
|
-
end.flatten
|
33
|
-
@files[filepath] = line_nums if line_nums.any?
|
34
|
-
end
|
35
|
-
self
|
16
|
+
@filter_set = filter_set
|
36
17
|
end
|
37
18
|
|
38
19
|
def last_modified
|
@@ -46,18 +27,24 @@ module Undercover
|
|
46
27
|
end
|
47
28
|
|
48
29
|
def file_paths
|
49
|
-
|
30
|
+
full_diff.deltas.map { |d| d.new_file[:path] }.sort
|
50
31
|
end
|
51
32
|
|
52
33
|
def each_changed_line
|
53
|
-
|
54
|
-
|
34
|
+
full_diff.each_patch do |patch|
|
35
|
+
filepath = patch.delta.new_file[:path]
|
36
|
+
next if filter_set && !filter_set.include?(filepath)
|
37
|
+
|
38
|
+
patch.each_hunk do |hunk|
|
39
|
+
hunk.lines.select(&:addition?).each do |line|
|
40
|
+
yield filepath, line.new_lineno
|
41
|
+
end
|
42
|
+
end
|
55
43
|
end
|
56
44
|
end
|
57
45
|
|
58
|
-
# TODO: refactor to a standalone validator (depending on changeset AND lcov)
|
59
46
|
def validate(lcov_report_path)
|
60
|
-
return :no_changes if
|
47
|
+
return :no_changes if full_diff.deltas.empty?
|
61
48
|
|
62
49
|
:stale_coverage if last_modified > File.mtime(lcov_report_path)
|
63
50
|
end
|
@@ -68,7 +55,7 @@ module Undercover
|
|
68
55
|
# as it makes sense to run Undercover with the most recent file versions
|
69
56
|
def full_diff
|
70
57
|
base = compare_base_obj || head
|
71
|
-
base.diff(repo.index).merge!(repo.diff_workdir(head))
|
58
|
+
@full_diff ||= base.diff(repo.index).merge!(repo.diff_workdir(head))
|
72
59
|
end
|
73
60
|
|
74
61
|
def compare_base_obj
|
@@ -83,6 +70,6 @@ module Undercover
|
|
83
70
|
repo.head.target
|
84
71
|
end
|
85
72
|
|
86
|
-
attr_reader :repo, :compare_base
|
73
|
+
attr_reader :repo, :compare_base, :filter_set
|
87
74
|
end
|
88
75
|
end
|
data/lib/undercover/cli.rb
CHANGED
@@ -22,9 +22,29 @@ module Undercover
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def self.run_report(opts)
|
25
|
+
coverage_path = opts.simplecov_resultset || opts.lcov
|
26
|
+
return handle_missing_coverage_path(opts) if coverage_path.nil?
|
27
|
+
return handle_missing_file(coverage_path) unless File.exist?(coverage_path)
|
28
|
+
|
25
29
|
report = Undercover::Report.new(changeset(opts), opts).build
|
30
|
+
handle_report_validation(report, coverage_path)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.handle_missing_coverage_path(opts)
|
34
|
+
puts Rainbow('❌ ERROR: No coverage report found. Checked default paths:').red
|
35
|
+
puts Rainbow(' - ./coverage/coverage.json (SimpleCov)').red
|
36
|
+
puts Rainbow(" - ./coverage/lcov/#{Pathname.new(File.expand_path(opts.path)).split.last}.lcov (LCOV)").red
|
37
|
+
puts Rainbow('Set a custom path with --lcov or --simplecov option').red
|
38
|
+
1
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.handle_missing_file(coverage_path)
|
42
|
+
puts Rainbow("❌ ERROR: Coverage report not found at: #{coverage_path}").red
|
43
|
+
1
|
44
|
+
end
|
26
45
|
|
27
|
-
|
46
|
+
def self.handle_report_validation(report, coverage_path)
|
47
|
+
error = report.validate(coverage_path)
|
28
48
|
if error
|
29
49
|
puts(WARNINGS_TO_S[error])
|
30
50
|
return 0 if error == :no_changes
|
@@ -43,7 +63,8 @@ module Undercover
|
|
43
63
|
|
44
64
|
def self.changeset(opts)
|
45
65
|
git_dir = File.join(opts.path, opts.git_dir)
|
46
|
-
Undercover::
|
66
|
+
filter_set = Undercover::FilterSet.new(opts.glob_allow_filters, opts.glob_reject_filters)
|
67
|
+
Undercover::Changeset.new(git_dir, opts.compare, filter_set)
|
47
68
|
end
|
48
69
|
end
|
49
70
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Undercover
|
4
|
+
class FilterSet
|
5
|
+
attr_reader :allow_filters, :reject_filters
|
6
|
+
|
7
|
+
def initialize(allow_filters, reject_filters)
|
8
|
+
@allow_filters = allow_filters || []
|
9
|
+
@reject_filters = reject_filters || []
|
10
|
+
end
|
11
|
+
|
12
|
+
def include?(filepath)
|
13
|
+
fnmatch = proc { |glob| File.fnmatch(glob, filepath, File::FNM_EXTGLOB) }
|
14
|
+
allow_filters.any?(fnmatch) && reject_filters.none?(fnmatch)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -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
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'optparse'
|
4
4
|
require 'pathname'
|
5
|
+
require 'shellwords'
|
5
6
|
|
6
7
|
module Undercover
|
7
8
|
class Options # rubocop:disable Metrics/ClassLength
|
@@ -34,6 +35,7 @@ module Undercover
|
|
34
35
|
DEFAULT_FILE_EXCLUDE_GLOBS = %w[test/* spec/* db/* config/* *_test.rb *_spec.rb].freeze
|
35
36
|
|
36
37
|
attr_accessor :lcov,
|
38
|
+
:simplecov_resultset,
|
37
39
|
:path,
|
38
40
|
:git_dir,
|
39
41
|
:compare,
|
@@ -41,7 +43,8 @@ module Undercover
|
|
41
43
|
:run_mode,
|
42
44
|
:file_scope,
|
43
45
|
:glob_allow_filters,
|
44
|
-
:glob_reject_filters
|
46
|
+
:glob_reject_filters,
|
47
|
+
:max_warnings_limit
|
45
48
|
|
46
49
|
def initialize
|
47
50
|
@run_mode = DIFF_TRIGGER_LINE
|
@@ -51,6 +54,7 @@ module Undercover
|
|
51
54
|
self.git_dir = '.git'
|
52
55
|
self.glob_allow_filters = DEFAULT_FILE_INCLUDE_GLOBS
|
53
56
|
self.glob_reject_filters = DEFAULT_FILE_EXCLUDE_GLOBS
|
57
|
+
self.max_warnings_limit = nil
|
54
58
|
end
|
55
59
|
|
56
60
|
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
@@ -66,18 +70,23 @@ module Undercover
|
|
66
70
|
end
|
67
71
|
|
68
72
|
opts.on_tail('--version', 'Show version') do
|
73
|
+
# :nocov:
|
69
74
|
puts VERSION
|
70
75
|
exit
|
76
|
+
# :nocov:
|
71
77
|
end
|
72
78
|
|
73
79
|
lcov_path_option(opts)
|
80
|
+
resultset_path_option(opts)
|
74
81
|
project_path_option(opts)
|
75
82
|
git_dir_option(opts)
|
76
83
|
compare_option(opts)
|
77
84
|
ruby_syntax_option(opts)
|
85
|
+
max_warnings_limit_option(opts)
|
78
86
|
file_filters(opts)
|
79
87
|
end.parse(args)
|
80
88
|
|
89
|
+
guess_resultset_path unless simplecov_resultset
|
81
90
|
guess_lcov_path unless lcov
|
82
91
|
self
|
83
92
|
end
|
@@ -96,19 +105,39 @@ module Undercover
|
|
96
105
|
def args_from_options_file(path)
|
97
106
|
return [] unless File.exist?(path)
|
98
107
|
|
99
|
-
File.read(path).split(
|
108
|
+
File.read(path).split("\n").flat_map { parse_line(_1) }
|
100
109
|
end
|
101
110
|
|
102
111
|
def project_options_file
|
103
112
|
'./.undercover'
|
104
113
|
end
|
105
114
|
|
115
|
+
def parse_line(line)
|
116
|
+
line = line.strip
|
117
|
+
return [] if line.empty? || line.start_with?('#')
|
118
|
+
|
119
|
+
Shellwords.split(line)
|
120
|
+
end
|
121
|
+
|
122
|
+
def split_comma_separated_with_braces(input)
|
123
|
+
return [] if input.empty?
|
124
|
+
|
125
|
+
input.split(/,(?![^{]*})/).map(&:strip) # split on commas that are not inside braces
|
126
|
+
end
|
127
|
+
|
106
128
|
def lcov_path_option(parser)
|
107
129
|
parser.on('-l', '--lcov path', 'LCOV report file path') do |path|
|
108
130
|
self.lcov = path
|
109
131
|
end
|
110
132
|
end
|
111
133
|
|
134
|
+
def resultset_path_option(parser)
|
135
|
+
desc = 'SimpleCov::Formatter::Undercover output file path (alternative to LCOV that will become default)'
|
136
|
+
parser.on('-s', '--simplecov path', desc) do |path|
|
137
|
+
self.simplecov_resultset = path
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
112
141
|
def project_path_option(parser)
|
113
142
|
parser.on('-p', '--path path', 'Project directory') do |path|
|
114
143
|
self.path = path
|
@@ -137,21 +166,35 @@ module Undercover
|
|
137
166
|
end
|
138
167
|
end
|
139
168
|
|
169
|
+
def max_warnings_limit_option(parser)
|
170
|
+
desc = 'Maximum number of warnings to generate before stopping analysis'
|
171
|
+
parser.on('-w', '--max-warnings limit', Integer, desc) do |limit|
|
172
|
+
self.max_warnings_limit = limit
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def guess_resultset_path
|
177
|
+
cwd = Pathname.new(File.expand_path(path))
|
178
|
+
try_path = File.join(cwd, 'coverage', 'coverage.json')
|
179
|
+
self.simplecov_resultset = try_path if File.exist?(try_path)
|
180
|
+
end
|
181
|
+
|
140
182
|
def guess_lcov_path
|
141
183
|
cwd = Pathname.new(File.expand_path(path))
|
142
|
-
|
184
|
+
try_path = File.join(cwd, 'coverage', 'lcov', "#{cwd.split.last}.lcov")
|
185
|
+
self.lcov = try_path if File.exist?(try_path)
|
143
186
|
end
|
144
187
|
|
145
188
|
def file_filters(parser)
|
146
189
|
desc = 'Include files matching specified glob patterns (comma separated). ' \
|
147
190
|
"Defaults to '#{DEFAULT_FILE_INCLUDE_GLOBS.join(',')}'"
|
148
191
|
parser.on('-f', '--include-files globs', desc) do |comma_separated_globs|
|
149
|
-
self.glob_allow_filters = comma_separated_globs
|
192
|
+
self.glob_allow_filters = split_comma_separated_with_braces(comma_separated_globs)
|
150
193
|
end
|
151
194
|
|
152
195
|
desc = 'Skip files matching specified glob patterns (comma separated). Empty by default.'
|
153
196
|
parser.on('-x', '--exclude-files globs', desc) do |comma_separated_globs|
|
154
|
-
self.glob_reject_filters = comma_separated_globs
|
197
|
+
self.glob_reject_filters = split_comma_separated_with_braces(comma_separated_globs)
|
155
198
|
end
|
156
199
|
end
|
157
200
|
end
|
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,9 +60,14 @@ 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
|
-
lines[ln] = 0 if branch_cov.zero?
|
70
|
+
lines[ln] = 0 if branch_cov != 'ignored' && branch_cov.zero?
|
61
71
|
elsif block_or_line_cov.zero?
|
62
72
|
lines[ln] = 0
|
63
73
|
end
|
@@ -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,65 @@
|
|
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
|
+
return lines unless source_file['branches']
|
39
|
+
|
40
|
+
branch_idx = 0
|
41
|
+
branches = source_file['branches'].map do |branch|
|
42
|
+
branch_idx += 1
|
43
|
+
[branch['start_line'], 0, branch_idx, branch['coverage']]
|
44
|
+
end
|
45
|
+
lines + branches
|
46
|
+
end
|
47
|
+
|
48
|
+
def skipped?(filepath, line_no)
|
49
|
+
source_file = find_file(filepath)
|
50
|
+
return false unless source_file
|
51
|
+
|
52
|
+
source_file['lines'][line_no - 1] == 'ignored'
|
53
|
+
end
|
54
|
+
|
55
|
+
# unused for now
|
56
|
+
def total_coverage; end
|
57
|
+
def total_branch_coverage; end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def find_file(filepath)
|
62
|
+
simplecov_result['coverage'][fix_relative_filepath(filepath)]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
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'
|
@@ -12,6 +14,8 @@ require 'undercover/cli'
|
|
12
14
|
require 'undercover/changeset'
|
13
15
|
require 'undercover/formatter'
|
14
16
|
require 'undercover/options'
|
17
|
+
require 'undercover/filter_set'
|
18
|
+
require 'undercover/simplecov_result_adapter'
|
15
19
|
require 'undercover/version'
|
16
20
|
|
17
21
|
module Undercover
|
@@ -21,29 +25,36 @@ module Undercover
|
|
21
25
|
|
22
26
|
attr_reader :changeset,
|
23
27
|
:lcov,
|
28
|
+
:simplecov_resultset,
|
24
29
|
:results,
|
25
30
|
:code_dir,
|
26
|
-
:
|
31
|
+
:filter_set,
|
32
|
+
:max_warnings_limit
|
27
33
|
|
28
34
|
# Initializes a new Undercover::Report
|
29
35
|
#
|
30
36
|
# @param changeset [Undercover::Changeset]
|
31
37
|
# @param opts [Undercover::Options]
|
32
38
|
def initialize(changeset, opts)
|
33
|
-
|
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) if opts.lcov
|
43
|
+
|
34
44
|
@code_dir = opts.path
|
35
|
-
@changeset = changeset
|
36
|
-
@
|
37
|
-
|
38
|
-
reject: opts.glob_reject_filters
|
39
|
-
}
|
45
|
+
@changeset = changeset
|
46
|
+
@filter_set = FilterSet.new(opts.glob_allow_filters, opts.glob_reject_filters)
|
47
|
+
@max_warnings_limit = opts.max_warnings_limit
|
40
48
|
@loaded_files = {}
|
41
49
|
@results = {}
|
42
50
|
end
|
43
51
|
|
44
52
|
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
45
53
|
def build
|
54
|
+
flag_count = 0
|
46
55
|
changeset.each_changed_line do |filepath, line_no|
|
56
|
+
break if max_warnings_limit && flag_count >= max_warnings_limit
|
57
|
+
|
47
58
|
dist_from_line_no = lambda do |res|
|
48
59
|
return BigDecimal::INFINITY if line_no < res.first_line
|
49
60
|
|
@@ -61,7 +72,10 @@ module Undercover
|
|
61
72
|
next unless loaded_files[filepath]
|
62
73
|
|
63
74
|
res = loaded_files[filepath].min(&dist_from_line_no_sorter)
|
64
|
-
|
75
|
+
if res.uncovered?(line_no) && !res.flagged?
|
76
|
+
res.flag
|
77
|
+
flag_count += 1
|
78
|
+
end
|
65
79
|
results[filepath] ||= Set.new
|
66
80
|
results[filepath] << res
|
67
81
|
end
|
@@ -96,9 +110,6 @@ module Undercover
|
|
96
110
|
def load_and_parse_file(filepath)
|
97
111
|
key = filepath.gsub(/^\.\//, '')
|
98
112
|
return if loaded_files[key]
|
99
|
-
|
100
|
-
coverage = lcov.coverage(filepath)
|
101
|
-
|
102
113
|
return unless include_file?(filepath)
|
103
114
|
|
104
115
|
root_ast = Imagen::Node::Root.new.build_from_file(
|
@@ -106,6 +117,9 @@ module Undercover
|
|
106
117
|
)
|
107
118
|
return if root_ast.children.empty?
|
108
119
|
|
120
|
+
# lcov will be deprecated at some point and we'll be able to refactor harder
|
121
|
+
coverage = simplecov_resultset || lcov
|
122
|
+
|
109
123
|
loaded_files[key] = []
|
110
124
|
root_ast.find_all(->(node) { !node.is_a?(Imagen::Node::Root) }).each do |imagen_node|
|
111
125
|
loaded_files[key] << Result.new(imagen_node, coverage, filepath)
|
@@ -114,8 +128,7 @@ module Undercover
|
|
114
128
|
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
115
129
|
|
116
130
|
def include_file?(filepath)
|
117
|
-
|
118
|
-
glob_filters[:allow].any?(fnmatch) && glob_filters[:reject].none?(fnmatch)
|
131
|
+
filter_set.include?(filepath)
|
119
132
|
end
|
120
133
|
end
|
121
134
|
end
|
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.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Grodowski
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-07-13 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,20 +140,23 @@ 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
|
152
|
+
- lib/undercover/filter_set.rb
|
125
153
|
- lib/undercover/formatter.rb
|
126
154
|
- lib/undercover/lcov_parser.rb
|
127
155
|
- lib/undercover/options.rb
|
128
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
|
129
160
|
- lib/undercover/version.rb
|
130
161
|
- undercover.gemspec
|
131
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