undercover 0.5.0 → 0.6.3
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/dependabot.yml +4 -0
- data/.github/workflows/ruby.yml +6 -6
- data/.rubocop.yml +6 -0
- data/.tool-versions +1 -1
- data/CHANGELOG.md +18 -1
- data/README.md +4 -2
- data/lib/undercover/changeset.rb +3 -1
- data/lib/undercover/options.rb +27 -5
- data/lib/undercover/result.rb +16 -9
- data/lib/undercover/version.rb +1 -1
- data/lib/undercover.rb +16 -4
- data/undercover.gemspec +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6858f42ada692894674f818d7713d20e8239051d06547f72e721f6122dda53be
|
4
|
+
data.tar.gz: ef323b826f66d68a5ad0a5a7c14f5d37d3a85344f0efe82ac457181745000fb9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 365149055a1553d4bc6dfde0475cd4b1bc6a3a82c7a0cb5c5fbcf7604c078e320bafcd85b783d495bc4667bff58c0ebffeb5ec76a982c61bcb366e8a9a8edc18
|
7
|
+
data.tar.gz: d5d7ec83fd50f1504f38bdd9961be84d365d5f3882045a1028f3daf45cd309a5ded497941e723cf3f3ce0eb335dfba34310f69b3d5efb91b0013fc5f69cc77a8
|
data/.github/dependabot.yml
CHANGED
data/.github/workflows/ruby.yml
CHANGED
@@ -7,7 +7,7 @@ jobs:
|
|
7
7
|
matrix:
|
8
8
|
ruby: ['3.3', '3.0']
|
9
9
|
steps:
|
10
|
-
- uses: actions/checkout@
|
10
|
+
- uses: actions/checkout@v4
|
11
11
|
with:
|
12
12
|
fetch-depth: 0 # fetch all since test fixtures depend on history
|
13
13
|
- name: Set up Ruby ${{ matrix.ruby }}
|
@@ -23,20 +23,20 @@ jobs:
|
|
23
23
|
run: |
|
24
24
|
git fetch --update-head-ok origin master:master
|
25
25
|
undercover --compare master
|
26
|
-
- uses: actions/upload-artifact@
|
26
|
+
- uses: actions/upload-artifact@v4
|
27
27
|
with:
|
28
|
-
name: undercover.lcov
|
28
|
+
name: undercover-${{ matrix.ruby }}.lcov
|
29
29
|
path: coverage/lcov/undercover.lcov
|
30
30
|
coverage:
|
31
31
|
runs-on: ubuntu-latest
|
32
32
|
needs: build
|
33
33
|
steps:
|
34
|
-
- uses: actions/download-artifact@
|
34
|
+
- uses: actions/download-artifact@v4
|
35
35
|
with:
|
36
|
-
name: undercover.lcov
|
36
|
+
name: undercover-3.3.lcov
|
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
|
-
--commit $
|
41
|
+
--commit ${{ github.event.pull_request.head.sha || github.sha }} \
|
42
42
|
--lcov /home/runner/work/undercover/undercover/undercover.lcov
|
data/.rubocop.yml
CHANGED
data/.tool-versions
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby 3.3.
|
1
|
+
ruby 3.3.3
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,21 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
# [0.6.3] - 2024-12-23
|
10
|
+
|
11
|
+
### Fixed
|
12
|
+
- Fix false positives with empty blocks/methods on a single line ([#216](https://github.com/grodowski/undercover/issues/216)) by [@splattael](https://github.com/splattael).
|
13
|
+
- Updated list of default excluded directories (added `db/` and `config/`)
|
14
|
+
|
15
|
+
# [0.6.0] - 2024-12-12
|
16
|
+
### Added
|
17
|
+
- Add support for including and exluding files by glob patterns, supplied through CLI args and the configuration file (#146)
|
18
|
+
|
19
|
+
### Fixed
|
20
|
+
- Files that were changed but don't appear in the coverage report at all will now be reported as uncovered, as expected.
|
21
|
+
- Fixed an issue where top-level methods were not being considered [#135](https://github.com/grodowski/undercover/issues/135). This was caused by a bug in the tree traversal logic.
|
22
|
+
- Fixed a bug where `--compare` didn't work with grafted commits as there was no merge base available ([#175](https://github.com/grodowski/undercover/issues/175)). Now it's possible to pass a graft commit as `--compare` which enables `undercover` to work with shallow clones.
|
23
|
+
|
9
24
|
# [0.5.0] - 2024-01-09
|
10
25
|
### Changed
|
11
26
|
- Drop ruby 2.x support, require ruby 3.x in gemspec
|
@@ -128,7 +143,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
128
143
|
### Added
|
129
144
|
- First release of `undercover` 🎉
|
130
145
|
|
131
|
-
[Unreleased]: https://github.com/grodowski/undercover/compare/v0.
|
146
|
+
[Unreleased]: https://github.com/grodowski/undercover/compare/v0.6.3...HEAD
|
147
|
+
[0.6.3]:https://github.com/grodowski/undercover/compare/v0.6.3...v0.6.0
|
148
|
+
[0.6.0]: https://github.com/grodowski/undercover/compare/v0.6.0...v0.5.0
|
132
149
|
[0.5.0]: https://github.com/grodowski/undercover/compare/v0.4.7...v0.5.0
|
133
150
|
[0.4.7]: https://github.com/grodowski/undercover/compare/v0.4.6...v0.4.7
|
134
151
|
[0.4.6]: https://github.com/grodowski/undercover/compare/v0.4.5...v0.4.6
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|

|
2
2
|
|
3
|
-
`undercover` warns about methods, classes and blocks that **were changed without tests**, to help you easily find untested code and reduce the number of bugs. It does so by analysing data from git diffs, code structure and SimpleCov coverage reports.
|
3
|
+
`undercover` warns about methods, classes and blocks that **were changed without tests**, to help you easily find untested code and reduce the number of bugs. It does so by analysing data from git diffs, code structure and SimpleCov coverage reports.
|
4
4
|
|
5
5
|
Works with any Ruby CI pipeline as well as locally as a CLI.
|
6
6
|
|
@@ -104,12 +104,14 @@ A few options exist to provide automated comments from `undercover` in Pull Requ
|
|
104
104
|
Options can be passed when running the command from the command line:
|
105
105
|
|
106
106
|
```sh
|
107
|
-
undercover -h
|
108
107
|
Usage: undercover [options]
|
109
108
|
-l, --lcov path LCOV report file path
|
110
109
|
-p, --path path Project directory
|
111
110
|
-g, --git-dir dir Override `.git` with a custom directory
|
112
111
|
-c, --compare ref Generate coverage warnings for all changes after `ref`
|
112
|
+
-r, --ruby-syntax ver Ruby syntax version, one of: current, ruby18, ruby19, ruby20, ruby21, ruby22, ruby23, ruby24, ruby25, ruby26, ruby30, ruby31, ruby32, ruby33
|
113
|
+
-f, --include-files globs Include files matching specified glob patterns (comma separated). Defaults to '*.rb,*.rake,*.ru,Rakefile'
|
114
|
+
-x, --exclude-files globs Skip files matching specified glob patterns (comma separated). Empty by default.
|
113
115
|
-h, --help Prints this help
|
114
116
|
--version Show version
|
115
117
|
```
|
data/lib/undercover/changeset.rb
CHANGED
@@ -74,7 +74,9 @@ module Undercover
|
|
74
74
|
def compare_base_obj
|
75
75
|
return nil unless compare_base
|
76
76
|
|
77
|
-
repo.
|
77
|
+
merge_base = repo.merge_base(compare_base.to_s, head)
|
78
|
+
# merge_base may be nil with --depth 1, compare two refs directly
|
79
|
+
merge_base ? repo.lookup(merge_base) : repo.rev_parse(compare_base)
|
78
80
|
end
|
79
81
|
|
80
82
|
def head
|
data/lib/undercover/options.rb
CHANGED
@@ -4,7 +4,7 @@ require 'optparse'
|
|
4
4
|
require 'pathname'
|
5
5
|
|
6
6
|
module Undercover
|
7
|
-
class Options
|
7
|
+
class Options # rubocop:disable Metrics/ClassLength
|
8
8
|
RUN_MODE = [
|
9
9
|
RUN_MODE_DIFF_STRICT = :diff_strict, # warn for changed lines
|
10
10
|
# RUN_MODE_DIFF_FILES = :diff_files, # warn for changed whole files
|
@@ -17,7 +17,16 @@ module Undercover
|
|
17
17
|
# OUTPUT_CIRCLEMATOR = :circlemator # posts warnings as review comments
|
18
18
|
].freeze
|
19
19
|
|
20
|
-
|
20
|
+
DEFAULT_FILE_INCLUDE_GLOBS = %w[*.rb *.rake *.ru Rakefile].freeze
|
21
|
+
DEFAULT_FILE_EXCLUDE_GLOBS = %w[test/* spec/* db/* config/* *_test.rb *_spec.rb].freeze
|
22
|
+
|
23
|
+
attr_accessor :lcov,
|
24
|
+
:path,
|
25
|
+
:git_dir,
|
26
|
+
:compare,
|
27
|
+
:syntax_version,
|
28
|
+
:glob_allow_filters,
|
29
|
+
:glob_reject_filters
|
21
30
|
|
22
31
|
def initialize
|
23
32
|
# TODO: use run modes
|
@@ -27,6 +36,8 @@ module Undercover
|
|
27
36
|
# set defaults
|
28
37
|
self.path = '.'
|
29
38
|
self.git_dir = '.git'
|
39
|
+
self.glob_allow_filters = DEFAULT_FILE_INCLUDE_GLOBS
|
40
|
+
self.glob_reject_filters = DEFAULT_FILE_EXCLUDE_GLOBS
|
30
41
|
end
|
31
42
|
|
32
43
|
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
@@ -51,9 +62,7 @@ module Undercover
|
|
51
62
|
git_dir_option(opts)
|
52
63
|
compare_option(opts)
|
53
64
|
ruby_syntax_option(opts)
|
54
|
-
|
55
|
-
# --quiet (skip progress bar)
|
56
|
-
# --exit-status (do not print report, just exit)
|
65
|
+
file_filters(opts)
|
57
66
|
end.parse(args)
|
58
67
|
|
59
68
|
guess_lcov_path unless lcov
|
@@ -119,5 +128,18 @@ module Undercover
|
|
119
128
|
cwd = Pathname.new(File.expand_path(path))
|
120
129
|
self.lcov = File.join(cwd, 'coverage', 'lcov', "#{cwd.split.last}.lcov")
|
121
130
|
end
|
131
|
+
|
132
|
+
def file_filters(parser)
|
133
|
+
desc = 'Include files matching specified glob patterns (comma separated). ' \
|
134
|
+
"Defaults to '#{DEFAULT_FILE_INCLUDE_GLOBS.join(',')}'"
|
135
|
+
parser.on('-f', '--include-files globs', desc) do |comma_separated_globs|
|
136
|
+
self.glob_allow_filters = comma_separated_globs.strip.split(',')
|
137
|
+
end
|
138
|
+
|
139
|
+
desc = 'Skip files matching specified glob patterns (comma separated). Empty by default.'
|
140
|
+
parser.on('-x', '--exclude-files globs', desc) do |comma_separated_globs|
|
141
|
+
self.glob_reject_filters = comma_separated_globs.strip.split(',')
|
142
|
+
end
|
143
|
+
end
|
122
144
|
end
|
123
145
|
end
|
data/lib/undercover/result.rb
CHANGED
@@ -10,10 +10,16 @@ module Undercover
|
|
10
10
|
|
11
11
|
def_delegators :node, :first_line, :last_line, :name
|
12
12
|
|
13
|
-
def initialize(node, file_cov, file_path)
|
13
|
+
def initialize(node, file_cov, file_path) # rubocop:disable Metrics/MethodLength
|
14
14
|
@node = node
|
15
15
|
@coverage = file_cov.select do |ln, _|
|
16
|
-
first_line == last_line
|
16
|
+
if first_line == last_line
|
17
|
+
ln == first_line
|
18
|
+
elsif node.empty_def?
|
19
|
+
ln >= first_line
|
20
|
+
else
|
21
|
+
ln > first_line && ln < last_line
|
22
|
+
end
|
17
23
|
end
|
18
24
|
@file_path = file_path
|
19
25
|
@flagged = false
|
@@ -27,8 +33,9 @@ module Undercover
|
|
27
33
|
@flagged
|
28
34
|
end
|
29
35
|
|
30
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
31
36
|
def uncovered?(line_no)
|
37
|
+
return true if coverage.empty?
|
38
|
+
|
32
39
|
# check branch coverage for line_no
|
33
40
|
coverage.each do |ln, _block, _branch, cov|
|
34
41
|
return true if ln == line_no && cov && cov.zero?
|
@@ -38,13 +45,14 @@ module Undercover
|
|
38
45
|
line_cov = coverage.select { |cov| cov.size == 2 }.find { |ln, _cov| ln == line_no }
|
39
46
|
line_cov && line_cov[1].zero?
|
40
47
|
end
|
41
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
42
48
|
|
43
49
|
# Method `coverage_f` returns the total coverage of this Undercover::Result
|
44
50
|
# as a % value, taking into account missing branches. Line coverage will be counted
|
45
51
|
# as 0 if any branch is untested.
|
46
52
|
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
47
53
|
def coverage_f
|
54
|
+
return 0.0 if coverage.empty?
|
55
|
+
|
48
56
|
lines = {}
|
49
57
|
coverage.each do |ln, block_or_line_cov, _, branch_cov|
|
50
58
|
lines[ln] = 1 unless lines.key?(ln)
|
@@ -54,7 +62,6 @@ module Undercover
|
|
54
62
|
lines[ln] = 0
|
55
63
|
end
|
56
64
|
end
|
57
|
-
return 1.0 if lines.keys.empty?
|
58
65
|
|
59
66
|
(lines.values.sum.to_f / lines.keys.size).round(4)
|
60
67
|
end
|
@@ -87,14 +94,14 @@ module Undercover
|
|
87
94
|
if line.strip.empty?
|
88
95
|
Rainbow(formatted_line).darkgray.dark
|
89
96
|
elsif covered.nil?
|
90
|
-
Rainbow(formatted_line).darkgray.dark +
|
97
|
+
Rainbow(formatted_line).darkgray.dark +
|
91
98
|
Rainbow(' hits: n/a').italic.darkgray.dark
|
92
99
|
elsif covered.positive?
|
93
|
-
Rainbow(formatted_line).green +
|
100
|
+
Rainbow(formatted_line).green +
|
94
101
|
Rainbow(" hits: #{covered}").italic.darkgray.dark + \
|
95
102
|
count_covered_branches(num)
|
96
103
|
elsif covered.zero?
|
97
|
-
Rainbow(formatted_line).red +
|
104
|
+
Rainbow(formatted_line).red +
|
98
105
|
Rainbow(" hits: #{covered}").italic.darkgray.dark + \
|
99
106
|
count_covered_branches(num)
|
100
107
|
end
|
@@ -122,7 +129,7 @@ module Undercover
|
|
122
129
|
return '' if branches.empty?
|
123
130
|
|
124
131
|
if count_covered < branches.size
|
125
|
-
Rainbow(' branches: ').italic.darkgray.dark +
|
132
|
+
Rainbow(' branches: ').italic.darkgray.dark +
|
126
133
|
Rainbow("#{count_covered}/#{branches.size}").italic.red
|
127
134
|
else
|
128
135
|
Rainbow(" branches: #{count_covered}/#{branches.size}").italic.darkgray.dark
|
data/lib/undercover/version.rb
CHANGED
data/lib/undercover.rb
CHANGED
@@ -22,7 +22,8 @@ module Undercover
|
|
22
22
|
attr_reader :changeset,
|
23
23
|
:lcov,
|
24
24
|
:results,
|
25
|
-
:code_dir
|
25
|
+
:code_dir,
|
26
|
+
:glob_filters
|
26
27
|
|
27
28
|
# Initializes a new Undercover::Report
|
28
29
|
#
|
@@ -32,11 +33,15 @@ module Undercover
|
|
32
33
|
@lcov = LcovParser.parse(File.open(opts.lcov))
|
33
34
|
@code_dir = opts.path
|
34
35
|
@changeset = changeset.update
|
36
|
+
@glob_filters = {
|
37
|
+
allow: opts.glob_allow_filters,
|
38
|
+
reject: opts.glob_reject_filters
|
39
|
+
}
|
35
40
|
@loaded_files = {}
|
36
41
|
@results = {}
|
37
42
|
end
|
38
43
|
|
39
|
-
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
44
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
40
45
|
def build
|
41
46
|
changeset.each_changed_line do |filepath, line_no|
|
42
47
|
dist_from_line_no = lambda do |res|
|
@@ -50,6 +55,7 @@ module Undercover
|
|
50
55
|
dist_from_line_no_sorter = lambda do |res1, res2|
|
51
56
|
dist_from_line_no[res1] <=> dist_from_line_no[res2]
|
52
57
|
end
|
58
|
+
|
53
59
|
load_and_parse_file(filepath)
|
54
60
|
|
55
61
|
next unless loaded_files[filepath]
|
@@ -61,7 +67,7 @@ module Undercover
|
|
61
67
|
end
|
62
68
|
self
|
63
69
|
end
|
64
|
-
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
70
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
65
71
|
|
66
72
|
def build_warnings
|
67
73
|
warn('Undercover::Report#build_warnings is deprecated! ' \
|
@@ -92,7 +98,8 @@ module Undercover
|
|
92
98
|
return if loaded_files[key]
|
93
99
|
|
94
100
|
coverage = lcov.coverage(filepath)
|
95
|
-
|
101
|
+
|
102
|
+
return unless include_file?(filepath)
|
96
103
|
|
97
104
|
root_ast = Imagen::Node::Root.new.build_from_file(
|
98
105
|
File.join(code_dir, filepath)
|
@@ -106,5 +113,10 @@ module Undercover
|
|
106
113
|
end
|
107
114
|
end
|
108
115
|
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
116
|
+
|
117
|
+
def include_file?(filepath)
|
118
|
+
fnmatch = proc { |glob| File.fnmatch(glob, filepath) }
|
119
|
+
glob_filters[:allow].any?(fnmatch) && glob_filters[:reject].none?(fnmatch)
|
120
|
+
end
|
109
121
|
end
|
110
122
|
end
|
data/undercover.gemspec
CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.required_ruby_version = '>= 3.0.0'
|
29
29
|
|
30
30
|
spec.add_dependency 'bigdecimal'
|
31
|
-
spec.add_dependency 'imagen', '>= 0.
|
31
|
+
spec.add_dependency 'imagen', '>= 0.2.0'
|
32
32
|
spec.add_dependency 'rainbow', '>= 2.1', '< 4.0'
|
33
33
|
spec.add_dependency 'rugged', '>= 0.27', '< 1.8'
|
34
34
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: undercover
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Grodowski
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bigdecimal
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 0.2.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.
|
40
|
+
version: 0.2.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rainbow
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
136
136
|
- !ruby/object:Gem::Version
|
137
137
|
version: '0'
|
138
138
|
requirements: []
|
139
|
-
rubygems_version: 3.5.
|
139
|
+
rubygems_version: 3.5.11
|
140
140
|
signing_key:
|
141
141
|
specification_version: 4
|
142
142
|
summary: Actionable code coverage - detects untested code blocks in recent changes
|