undercover 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +11 -1
- data/README.md +4 -2
- data/lib/undercover/changeset.rb +3 -1
- data/lib/undercover/options.rb +26 -5
- data/lib/undercover/result.rb +9 -8
- 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: c860e600589d92698fa5df94b1b8fe9283cbb00cdc595410b9c3a413d74b3095
|
4
|
+
data.tar.gz: e2c26b709c691201f473846e0cb6a7fa6844c5d1dc73169ca533d95482182f6c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ace70eb4f75d2d57bda9d906925a7b5525c5a67520380ba0327a5344ed6718b79ea2587a5a0fb4d2a09d430d09b30eb2d1ac63c503be17197ff9c6455ab12b00
|
7
|
+
data.tar.gz: a2ec9a3b4d27cb9eaa7b4595f71ff9b12108e939864a6f5279aece22cd728e358dd50b16e63d0537780154e3ffd20e0712bce8322a8591e4f08f70d9d6818145
|
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,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
# [0.6.0] - 2024-12-12
|
10
|
+
### Added
|
11
|
+
- Add support for including and exluding files by glob patterns, supplied through CLI args and the configuration file (#146)
|
12
|
+
|
13
|
+
### Fixed
|
14
|
+
- Files that were changed but don't appear in the coverage report at all will now be reported as uncovered, as expected.
|
15
|
+
- 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.
|
16
|
+
- 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.
|
17
|
+
|
9
18
|
# [0.5.0] - 2024-01-09
|
10
19
|
### Changed
|
11
20
|
- Drop ruby 2.x support, require ruby 3.x in gemspec
|
@@ -128,7 +137,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
128
137
|
### Added
|
129
138
|
- First release of `undercover` 🎉
|
130
139
|
|
131
|
-
[Unreleased]: https://github.com/grodowski/undercover/compare/v0.
|
140
|
+
[Unreleased]: https://github.com/grodowski/undercover/compare/v0.6.0...HEAD
|
141
|
+
[0.6.0]: https://github.com/grodowski/undercover/compare/v0.6.0...v0.5.0
|
132
142
|
[0.5.0]: https://github.com/grodowski/undercover/compare/v0.4.7...v0.5.0
|
133
143
|
[0.4.7]: https://github.com/grodowski/undercover/compare/v0.4.6...v0.4.7
|
134
144
|
[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
|
![logo](https://github.com/grodowski/undercover/assets/4991698/c4bf038b-4472-4406-8f1f-5ddc812908d6)
|
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,15 @@ 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
|
+
|
22
|
+
attr_accessor :lcov,
|
23
|
+
:path,
|
24
|
+
:git_dir,
|
25
|
+
:compare,
|
26
|
+
:syntax_version,
|
27
|
+
:glob_allow_filters,
|
28
|
+
:glob_reject_filters
|
21
29
|
|
22
30
|
def initialize
|
23
31
|
# TODO: use run modes
|
@@ -27,6 +35,8 @@ module Undercover
|
|
27
35
|
# set defaults
|
28
36
|
self.path = '.'
|
29
37
|
self.git_dir = '.git'
|
38
|
+
self.glob_allow_filters = DEFAULT_FILE_INCLUDE_GLOBS
|
39
|
+
self.glob_reject_filters = []
|
30
40
|
end
|
31
41
|
|
32
42
|
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
@@ -51,9 +61,7 @@ module Undercover
|
|
51
61
|
git_dir_option(opts)
|
52
62
|
compare_option(opts)
|
53
63
|
ruby_syntax_option(opts)
|
54
|
-
|
55
|
-
# --quiet (skip progress bar)
|
56
|
-
# --exit-status (do not print report, just exit)
|
64
|
+
file_filters(opts)
|
57
65
|
end.parse(args)
|
58
66
|
|
59
67
|
guess_lcov_path unless lcov
|
@@ -119,5 +127,18 @@ module Undercover
|
|
119
127
|
cwd = Pathname.new(File.expand_path(path))
|
120
128
|
self.lcov = File.join(cwd, 'coverage', 'lcov', "#{cwd.split.last}.lcov")
|
121
129
|
end
|
130
|
+
|
131
|
+
def file_filters(parser)
|
132
|
+
desc = 'Include files matching specified glob patterns (comma separated). ' \
|
133
|
+
"Defaults to '#{DEFAULT_FILE_INCLUDE_GLOBS.join(',')}'"
|
134
|
+
parser.on('-f', '--include-files globs', desc) do |comma_separated_globs|
|
135
|
+
self.glob_allow_filters = comma_separated_globs.strip.split(',')
|
136
|
+
end
|
137
|
+
|
138
|
+
desc = 'Skip files matching specified glob patterns (comma separated). Empty by default.'
|
139
|
+
parser.on('-x', '--exclude-files globs', desc) do |comma_separated_globs|
|
140
|
+
self.glob_reject_filters = comma_separated_globs.strip.split(',')
|
141
|
+
end
|
142
|
+
end
|
122
143
|
end
|
123
144
|
end
|
data/lib/undercover/result.rb
CHANGED
@@ -13,7 +13,7 @@ module Undercover
|
|
13
13
|
def initialize(node, file_cov, file_path)
|
14
14
|
@node = node
|
15
15
|
@coverage = file_cov.select do |ln, _|
|
16
|
-
|
16
|
+
(node.empty_def? ? ln >= first_line : ln > first_line) && ln < last_line
|
17
17
|
end
|
18
18
|
@file_path = file_path
|
19
19
|
@flagged = false
|
@@ -27,8 +27,9 @@ module Undercover
|
|
27
27
|
@flagged
|
28
28
|
end
|
29
29
|
|
30
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
31
30
|
def uncovered?(line_no)
|
31
|
+
return true if coverage.empty?
|
32
|
+
|
32
33
|
# check branch coverage for line_no
|
33
34
|
coverage.each do |ln, _block, _branch, cov|
|
34
35
|
return true if ln == line_no && cov && cov.zero?
|
@@ -38,13 +39,14 @@ module Undercover
|
|
38
39
|
line_cov = coverage.select { |cov| cov.size == 2 }.find { |ln, _cov| ln == line_no }
|
39
40
|
line_cov && line_cov[1].zero?
|
40
41
|
end
|
41
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
42
42
|
|
43
43
|
# Method `coverage_f` returns the total coverage of this Undercover::Result
|
44
44
|
# as a % value, taking into account missing branches. Line coverage will be counted
|
45
45
|
# as 0 if any branch is untested.
|
46
46
|
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
47
47
|
def coverage_f
|
48
|
+
return 0.0 if coverage.empty?
|
49
|
+
|
48
50
|
lines = {}
|
49
51
|
coverage.each do |ln, block_or_line_cov, _, branch_cov|
|
50
52
|
lines[ln] = 1 unless lines.key?(ln)
|
@@ -54,7 +56,6 @@ module Undercover
|
|
54
56
|
lines[ln] = 0
|
55
57
|
end
|
56
58
|
end
|
57
|
-
return 1.0 if lines.keys.empty?
|
58
59
|
|
59
60
|
(lines.values.sum.to_f / lines.keys.size).round(4)
|
60
61
|
end
|
@@ -87,14 +88,14 @@ module Undercover
|
|
87
88
|
if line.strip.empty?
|
88
89
|
Rainbow(formatted_line).darkgray.dark
|
89
90
|
elsif covered.nil?
|
90
|
-
Rainbow(formatted_line).darkgray.dark +
|
91
|
+
Rainbow(formatted_line).darkgray.dark +
|
91
92
|
Rainbow(' hits: n/a').italic.darkgray.dark
|
92
93
|
elsif covered.positive?
|
93
|
-
Rainbow(formatted_line).green +
|
94
|
+
Rainbow(formatted_line).green +
|
94
95
|
Rainbow(" hits: #{covered}").italic.darkgray.dark + \
|
95
96
|
count_covered_branches(num)
|
96
97
|
elsif covered.zero?
|
97
|
-
Rainbow(formatted_line).red +
|
98
|
+
Rainbow(formatted_line).red +
|
98
99
|
Rainbow(" hits: #{covered}").italic.darkgray.dark + \
|
99
100
|
count_covered_branches(num)
|
100
101
|
end
|
@@ -122,7 +123,7 @@ module Undercover
|
|
122
123
|
return '' if branches.empty?
|
123
124
|
|
124
125
|
if count_covered < branches.size
|
125
|
-
Rainbow(' branches: ').italic.darkgray.dark +
|
126
|
+
Rainbow(' branches: ').italic.darkgray.dark +
|
126
127
|
Rainbow("#{count_covered}/#{branches.size}").italic.red
|
127
128
|
else
|
128
129
|
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.0
|
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-12 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
|