undercover 0.6.4 → 0.6.6
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/CHANGELOG.md +15 -3
- data/README.md +1 -1
- data/lib/undercover/changeset.rb +15 -27
- data/lib/undercover/cli.rb +2 -1
- data/lib/undercover/filter_set.rb +17 -0
- data/lib/undercover/options.rb +11 -1
- data/lib/undercover/version.rb +1 -1
- data/lib/undercover.rb +14 -9
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d4fbea540abf1922afa393179a770aa7468bb030085495c4be1daad89bafaaa
|
4
|
+
data.tar.gz: a815eb262c6b848fe21420d1626ba4e1b43dadf025e095380acb7b0fb6fe5e07
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 625346ca6e5b042b1658e58e82be45e4c5a5528843f4a7112b079fd244b99282965e96f47f67ff54cd341e2ce7e8d2d16c559bfbbda9d5483ed44a6ed847c814
|
7
|
+
data.tar.gz: 307d626ae101ae1d7136f2fa6247f317b9a3bd072c7f0da936f32dc0d7910ada7b9c9f8b04fe66ae2cc79fe0387cc0575f303af06bf67e729fd6e9174f3aacd4
|
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.6] - 2025-07-01
|
10
|
+
|
11
|
+
- Bugfix in `max_warnings_limit` following ([#229](https://github.com/grodowski/undercover/pull/229))
|
12
|
+
|
13
|
+
# [0.6.5] - 2025-07-01
|
14
|
+
|
15
|
+
### Fixed
|
16
|
+
- Improved performance for large PRs with lazy diff enumeration ([#229](https://github.com/grodowski/undercover/pull/229))
|
17
|
+
|
9
18
|
# [0.6.4] - 2025-03-29
|
10
19
|
|
11
20
|
### Fixed
|
@@ -148,9 +157,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
148
157
|
### Added
|
149
158
|
- First release of `undercover` 🎉
|
150
159
|
|
151
|
-
[Unreleased]: https://github.com/grodowski/undercover/compare/v0.6.
|
152
|
-
[0.6.
|
153
|
-
[0.6.
|
160
|
+
[Unreleased]: https://github.com/grodowski/undercover/compare/v0.6.6...HEAD
|
161
|
+
[0.6.6]: https://github.com/grodowski/undercover/compare/v0.6.5...0.6.6
|
162
|
+
[0.6.5]: https://github.com/grodowski/undercover/compare/v0.6.4...0.6.5
|
163
|
+
[0.6.4]: https://github.com/grodowski/undercover/compare/v0.6.3...v0.6.4
|
164
|
+
[0.6.3]: https://github.com/grodowski/undercover/compare/v0.6.0...v0.6.3
|
165
|
+
[0.6.0]: https://github.com/grodowski/undercover/compare/v0.5.0...v0.6.0
|
154
166
|
[0.5.0]: https://github.com/grodowski/undercover/compare/v0.4.7...v0.5.0
|
155
167
|
[0.4.7]: https://github.com/grodowski/undercover/compare/v0.4.6...v0.4.7
|
156
168
|
[0.4.6]: https://github.com/grodowski/undercover/compare/v0.4.5...v0.4.6
|
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:
|
@@ -110,6 +109,7 @@ Usage: undercover [options]
|
|
110
109
|
-g, --git-dir dir Override `.git` with a custom directory
|
111
110
|
-c, --compare ref Generate coverage warnings for all changes after `ref`
|
112
111
|
-r, --ruby-syntax ver Ruby syntax version, one of: current, ruby18, ruby19, ruby20, ruby21, ruby22, ruby23, ruby24, ruby25, ruby26, ruby30, ruby31, ruby32, ruby33
|
112
|
+
-w, --max-warnings limit Maximum number of warnings to generate before stopping analysis. Useful as a performance improvement for large diffs.
|
113
113
|
-f, --include-files globs Include files matching specified glob patterns (comma separated). Defaults to '*.rb,*.rake,*.ru,Rakefile'
|
114
114
|
-x, --exclude-files globs Skip files matching specified glob patterns (comma separated). Empty by default.
|
115
115
|
-h, --help Prints this help
|
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,25 @@ 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
46
|
# TODO: refactor to a standalone validator (depending on changeset AND lcov)
|
59
47
|
def validate(lcov_report_path)
|
60
|
-
return :no_changes if
|
48
|
+
return :no_changes if full_diff.deltas.empty?
|
61
49
|
|
62
50
|
:stale_coverage if last_modified > File.mtime(lcov_report_path)
|
63
51
|
end
|
@@ -68,7 +56,7 @@ module Undercover
|
|
68
56
|
# as it makes sense to run Undercover with the most recent file versions
|
69
57
|
def full_diff
|
70
58
|
base = compare_base_obj || head
|
71
|
-
base.diff(repo.index).merge!(repo.diff_workdir(head))
|
59
|
+
@full_diff ||= base.diff(repo.index).merge!(repo.diff_workdir(head))
|
72
60
|
end
|
73
61
|
|
74
62
|
def compare_base_obj
|
@@ -83,6 +71,6 @@ module Undercover
|
|
83
71
|
repo.head.target
|
84
72
|
end
|
85
73
|
|
86
|
-
attr_reader :repo, :compare_base
|
74
|
+
attr_reader :repo, :compare_base, :filter_set
|
87
75
|
end
|
88
76
|
end
|
data/lib/undercover/cli.rb
CHANGED
@@ -43,7 +43,8 @@ module Undercover
|
|
43
43
|
|
44
44
|
def self.changeset(opts)
|
45
45
|
git_dir = File.join(opts.path, opts.git_dir)
|
46
|
-
Undercover::
|
46
|
+
filter_set = Undercover::FilterSet.new(opts.glob_allow_filters, opts.glob_reject_filters)
|
47
|
+
Undercover::Changeset.new(git_dir, opts.compare, filter_set)
|
47
48
|
end
|
48
49
|
end
|
49
50
|
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) }
|
14
|
+
allow_filters.any?(fnmatch) && reject_filters.none?(fnmatch)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/undercover/options.rb
CHANGED
@@ -41,7 +41,8 @@ module Undercover
|
|
41
41
|
:run_mode,
|
42
42
|
:file_scope,
|
43
43
|
:glob_allow_filters,
|
44
|
-
:glob_reject_filters
|
44
|
+
:glob_reject_filters,
|
45
|
+
:max_warnings_limit
|
45
46
|
|
46
47
|
def initialize
|
47
48
|
@run_mode = DIFF_TRIGGER_LINE
|
@@ -51,6 +52,7 @@ module Undercover
|
|
51
52
|
self.git_dir = '.git'
|
52
53
|
self.glob_allow_filters = DEFAULT_FILE_INCLUDE_GLOBS
|
53
54
|
self.glob_reject_filters = DEFAULT_FILE_EXCLUDE_GLOBS
|
55
|
+
self.max_warnings_limit = nil
|
54
56
|
end
|
55
57
|
|
56
58
|
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
@@ -75,6 +77,7 @@ module Undercover
|
|
75
77
|
git_dir_option(opts)
|
76
78
|
compare_option(opts)
|
77
79
|
ruby_syntax_option(opts)
|
80
|
+
max_warnings_limit_option(opts)
|
78
81
|
file_filters(opts)
|
79
82
|
end.parse(args)
|
80
83
|
|
@@ -137,6 +140,13 @@ module Undercover
|
|
137
140
|
end
|
138
141
|
end
|
139
142
|
|
143
|
+
def max_warnings_limit_option(parser)
|
144
|
+
desc = 'Maximum number of warnings to generate before stopping analysis'
|
145
|
+
parser.on('-w', '--max-warnings limit', Integer, desc) do |limit|
|
146
|
+
self.max_warnings_limit = limit
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
140
150
|
def guess_lcov_path
|
141
151
|
cwd = Pathname.new(File.expand_path(path))
|
142
152
|
self.lcov = File.join(cwd, 'coverage', 'lcov', "#{cwd.split.last}.lcov")
|
data/lib/undercover/version.rb
CHANGED
data/lib/undercover.rb
CHANGED
@@ -12,6 +12,7 @@ require 'undercover/cli'
|
|
12
12
|
require 'undercover/changeset'
|
13
13
|
require 'undercover/formatter'
|
14
14
|
require 'undercover/options'
|
15
|
+
require 'undercover/filter_set'
|
15
16
|
require 'undercover/version'
|
16
17
|
|
17
18
|
module Undercover
|
@@ -23,7 +24,8 @@ module Undercover
|
|
23
24
|
:lcov,
|
24
25
|
:results,
|
25
26
|
:code_dir,
|
26
|
-
:
|
27
|
+
:filter_set,
|
28
|
+
:max_warnings_limit
|
27
29
|
|
28
30
|
# Initializes a new Undercover::Report
|
29
31
|
#
|
@@ -32,18 +34,19 @@ module Undercover
|
|
32
34
|
def initialize(changeset, opts)
|
33
35
|
@lcov = LcovParser.parse(File.open(opts.lcov))
|
34
36
|
@code_dir = opts.path
|
35
|
-
@changeset = changeset
|
36
|
-
@
|
37
|
-
|
38
|
-
reject: opts.glob_reject_filters
|
39
|
-
}
|
37
|
+
@changeset = changeset
|
38
|
+
@filter_set = FilterSet.new(opts.glob_allow_filters, opts.glob_reject_filters)
|
39
|
+
@max_warnings_limit = opts.max_warnings_limit
|
40
40
|
@loaded_files = {}
|
41
41
|
@results = {}
|
42
42
|
end
|
43
43
|
|
44
44
|
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
45
45
|
def build
|
46
|
+
flag_count = 0
|
46
47
|
changeset.each_changed_line do |filepath, line_no|
|
48
|
+
break if max_warnings_limit && flag_count >= max_warnings_limit
|
49
|
+
|
47
50
|
dist_from_line_no = lambda do |res|
|
48
51
|
return BigDecimal::INFINITY if line_no < res.first_line
|
49
52
|
|
@@ -61,7 +64,10 @@ module Undercover
|
|
61
64
|
next unless loaded_files[filepath]
|
62
65
|
|
63
66
|
res = loaded_files[filepath].min(&dist_from_line_no_sorter)
|
64
|
-
|
67
|
+
if res.uncovered?(line_no) && !res.flagged?
|
68
|
+
res.flag
|
69
|
+
flag_count += 1
|
70
|
+
end
|
65
71
|
results[filepath] ||= Set.new
|
66
72
|
results[filepath] << res
|
67
73
|
end
|
@@ -114,8 +120,7 @@ module Undercover
|
|
114
120
|
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
115
121
|
|
116
122
|
def include_file?(filepath)
|
117
|
-
|
118
|
-
glob_filters[:allow].any?(fnmatch) && glob_filters[:reject].none?(fnmatch)
|
123
|
+
filter_set.include?(filepath)
|
119
124
|
end
|
120
125
|
end
|
121
126
|
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.6.
|
4
|
+
version: 0.6.6
|
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-01 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: base64
|
@@ -122,6 +122,7 @@ files:
|
|
122
122
|
- lib/undercover.rb
|
123
123
|
- lib/undercover/changeset.rb
|
124
124
|
- lib/undercover/cli.rb
|
125
|
+
- lib/undercover/filter_set.rb
|
125
126
|
- lib/undercover/formatter.rb
|
126
127
|
- lib/undercover/lcov_parser.rb
|
127
128
|
- lib/undercover/options.rb
|