undercover 0.3.4 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +1 -1
- data/.rubocop.yml +2 -1
- data/CHANGELOG.md +9 -0
- data/README.md +12 -3
- data/lib/undercover.rb +2 -2
- data/lib/undercover/changeset.rb +2 -1
- data/lib/undercover/lcov_parser.rb +10 -2
- data/lib/undercover/options.rb +1 -1
- data/lib/undercover/result.rb +44 -20
- data/lib/undercover/version.rb +1 -1
- data/undercover.gemspec +5 -3
- metadata +12 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5104b390e6cc5e103274e4621c3ec1f01a75091703e2a3549ad7a629b0edd9e1
|
4
|
+
data.tar.gz: d7346137e3b284a8815e3b0c55c22ee154fbb2e781576204eef898e3f221218d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a7cda81269eb9f3e5cb1e752c83e5b203dc01b64409765ba69c2e9fb9ef8a456d324a631f7eb5341938a3781328a688556292c552d13b8ef431490e7304875b
|
7
|
+
data.tar.gz: 980ecc847bee0a649ed9953e07118b22df8ed691ea5e72711511cd5759ad1ec507f56fdbc190f9824197f82f8d244fcb8a7f9545b75fda24d68cb5abb9311097
|
data/.github/workflows/ruby.yml
CHANGED
data/.rubocop.yml
CHANGED
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.4.0] - 2021-02-06
|
10
|
+
### Added
|
11
|
+
- [Minimal implementation of branch coverage in LCOV parser](https://github.com/grodowski/undercover/pull/112) by [@magneland](https://github.com/magneland)
|
12
|
+
- Branch coverage output support in Undercover::Formatter
|
13
|
+
### Changed
|
14
|
+
- Min Ruby requirement bumped to 2.5.0
|
15
|
+
- Dependency updates: Rubocop 1.0 and Rugged 1.1.0
|
16
|
+
|
17
|
+
|
9
18
|
## [0.3.4] - 2020-04-05
|
10
19
|
### Changed
|
11
20
|
- Updated parsing performance by scoping `all_results` to git diff
|
data/README.md
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
# undercover 👮♂️
|
2
2
|
|
3
|
-
**Like RuboCop but for code coverage
|
3
|
+
**Like RuboCop but for code coverage**. Inspects files in a git diff and warns on changed methods, classes and blocks which need to be tested. Use it locally or as part of an automated build to shorten your code coverage feedback loop!
|
4
4
|
|
5
|
-
**
|
5
|
+
- Visit **[https://undercover-ci.com](https://undercover-ci.com)** to set up actionable GitHub code review checks, or use one of the [integrations](#code-review-integrations)
|
6
|
+
- Learn how to find untested code changes locally with the [CLI](#usage)
|
6
7
|
|
7
8
|
A sample output of `undercover` ran before a commit may look like this:
|
8
9
|
|
@@ -14,7 +15,6 @@ And like this, given that specs were added:
|
|
14
15
|
|
15
16
|
[![Build Status](https://action-badges.now.sh/grodowski/undercover)](https://github.com/grodowski/undercover/actions)
|
16
17
|
[![Maintainability](https://api.codeclimate.com/v1/badges/b403feed68a18c072ec5/maintainability)](https://codeclimate.com/github/grodowski/undercover/maintainability)
|
17
|
-
[![codebeat badge](https://codebeat.co/badges/be548247-2421-4448-bdab-896d13eb02e9)](https://codebeat.co/projects/github-com-grodowski-undercover-master)
|
18
18
|
|
19
19
|
## Installation
|
20
20
|
|
@@ -83,6 +83,15 @@ Check out `docs/` for CI configuration examples:
|
|
83
83
|
|
84
84
|
Merging coverage results ([sample gist](https://gist.github.com/grodowski/9744ff91034dce8df20c2a8210409fb0)) is required for parallel tests before processing with `undercover`.
|
85
85
|
|
86
|
+
## Code review integrations
|
87
|
+
|
88
|
+
A few options exist to provide automated comments from `undercover` in Pull Request reviews, which is the most streamlined way to add Undercover to your development workflow.
|
89
|
+
|
90
|
+
- [UndercoverCI](https://undercover-ci.com) - `undercover` Pull Request feedback delivered natively with GitHub Checks
|
91
|
+
- [pronto-undercover](https://github.com/grodowski/pronto-undercover)
|
92
|
+
- [danger-undercover](https://github.com/nimblehq/danger-undercover)
|
93
|
+
- [undercover-checkstyle](https://github.com/aki77/undercover-checkstyle)
|
94
|
+
|
86
95
|
## Configuration
|
87
96
|
|
88
97
|
### CLI Options
|
data/lib/undercover.rb
CHANGED
@@ -36,7 +36,7 @@ module Undercover
|
|
36
36
|
@results = {}
|
37
37
|
end
|
38
38
|
|
39
|
-
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
39
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
|
40
40
|
def build
|
41
41
|
changeset.each_changed_line do |filepath, line_no|
|
42
42
|
dist_from_line_no = lambda do |res|
|
@@ -61,7 +61,7 @@ module Undercover
|
|
61
61
|
end
|
62
62
|
self
|
63
63
|
end
|
64
|
-
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
64
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
|
65
65
|
|
66
66
|
def build_warnings
|
67
67
|
warn('Undercover::Report#build_warnings is deprecated! ' \
|
data/lib/undercover/changeset.rb
CHANGED
@@ -31,7 +31,7 @@ module Undercover
|
|
31
31
|
|
32
32
|
private
|
33
33
|
|
34
|
-
# rubocop:disable Metrics/MethodLength, Style/SpecialGlobalVars
|
34
|
+
# rubocop:disable Metrics/MethodLength, Style/SpecialGlobalVars, Metrics/AbcSize
|
35
35
|
def parse_line(line)
|
36
36
|
case line
|
37
37
|
when /^SF:(.+)/
|
@@ -41,12 +41,20 @@ module Undercover
|
|
41
41
|
line_no = $~[1]
|
42
42
|
covered = $~[2]
|
43
43
|
source_files[@current_filename] << [line_no.to_i, covered.to_i]
|
44
|
+
when /^(BRF|BRH):(\d+)/
|
45
|
+
# branches found/hit; no-op
|
46
|
+
when /^BRDA:(\d+),(\d+),(\d+),(-|\d+)/
|
47
|
+
line_no = $~[1]
|
48
|
+
block_no = $~[2]
|
49
|
+
branch_no = $~[3]
|
50
|
+
covered = ($~[4] == '-' ? '0' : $~[4])
|
51
|
+
source_files[@current_filename] << [line_no.to_i, block_no.to_i, branch_no.to_i, covered.to_i]
|
44
52
|
when /^end_of_record$/, /^$/
|
45
53
|
@current_filename = nil
|
46
54
|
else
|
47
55
|
raise LcovParseError, "could not recognise '#{line}' as valid LCOV"
|
48
56
|
end
|
49
57
|
end
|
50
|
-
# rubocop:enable Metrics/MethodLength, Style/SpecialGlobalVars
|
58
|
+
# rubocop:enable Metrics/MethodLength, Style/SpecialGlobalVars, Metrics/AbcSize
|
51
59
|
end
|
52
60
|
end
|
data/lib/undercover/options.rb
CHANGED
data/lib/undercover/result.rb
CHANGED
@@ -27,28 +27,32 @@ module Undercover
|
|
27
27
|
@flagged
|
28
28
|
end
|
29
29
|
|
30
|
-
# TODO: make DRY
|
31
|
-
def non_code?(line_no)
|
32
|
-
line_cov = coverage.find { |ln, _cov| ln == line_no }
|
33
|
-
!line_cov
|
34
|
-
end
|
35
|
-
|
36
|
-
def covered?(line_no)
|
37
|
-
line_cov = coverage.find { |ln, _cov| ln == line_no }
|
38
|
-
line_cov && line_cov[1].positive?
|
39
|
-
end
|
40
|
-
|
41
30
|
def uncovered?(line_no)
|
31
|
+
coverage.each do |ln, _block, _branch, cov|
|
32
|
+
return true if ln == line_no && cov && cov.zero?
|
33
|
+
end
|
34
|
+
|
42
35
|
line_cov = coverage.find { |ln, _cov| ln == line_no }
|
43
36
|
line_cov && line_cov[1].zero?
|
44
37
|
end
|
45
38
|
|
39
|
+
# Method `coverage_f` returns the total coverage of this Undercover::Result
|
40
|
+
# as a % value, taking into account missing branches. Line coverage will be counted
|
41
|
+
# as 0 if any branch is untested.
|
42
|
+
# rubocop:disable Metrics/AbcSize
|
46
43
|
def coverage_f
|
47
|
-
|
48
|
-
|
44
|
+
lines = {}
|
45
|
+
coverage.each do |ln, block_or_line_cov, _, branch_cov|
|
46
|
+
lines[ln] = 1 unless lines.key?(ln)
|
47
|
+
if branch_cov
|
48
|
+
lines[ln] = 0 if branch_cov.zero?
|
49
|
+
elsif block_or_line_cov.zero?
|
50
|
+
lines[ln] = 0
|
51
|
+
end
|
49
52
|
end
|
50
|
-
(
|
53
|
+
(lines.values.sum.to_f / lines.keys.size).round(4)
|
51
54
|
end
|
55
|
+
# rubocop:enable Metrics/AbcSize
|
52
56
|
|
53
57
|
# TODO: create a formatter interface instead and add some tests.
|
54
58
|
# TODO: re-enable rubocops
|
@@ -60,10 +64,10 @@ module Undercover
|
|
60
64
|
cov_enum = coverage.each
|
61
65
|
cov_source_lines = (node.first_line..node.last_line).map do |line_no|
|
62
66
|
cov_line_no = begin
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
+
cov_enum.peek[0]
|
68
|
+
rescue StopIteration
|
69
|
+
-1
|
70
|
+
end
|
67
71
|
cov_enum.next[1] if cov_line_no == line_no
|
68
72
|
end
|
69
73
|
cov_source_lines.zip(node.source_lines_with_numbers)
|
@@ -81,10 +85,12 @@ module Undercover
|
|
81
85
|
Rainbow(' hits: n/a').italic.darkgray.dark
|
82
86
|
elsif covered.positive?
|
83
87
|
Rainbow(formatted_line).green + \
|
84
|
-
Rainbow(" hits: #{covered}").italic.darkgray.dark
|
88
|
+
Rainbow(" hits: #{covered}").italic.darkgray.dark + \
|
89
|
+
count_covered_branches(num)
|
85
90
|
elsif covered.zero?
|
86
91
|
Rainbow(formatted_line).red + \
|
87
|
-
Rainbow(" hits: #{covered}").italic.darkgray.dark
|
92
|
+
Rainbow(" hits: #{covered}").italic.darkgray.dark + \
|
93
|
+
count_covered_branches(num)
|
88
94
|
end
|
89
95
|
end.join("\n")
|
90
96
|
end
|
@@ -99,5 +105,23 @@ module Undercover
|
|
99
105
|
" name: #{node.name}, coverage: #{coverage_f}>"
|
100
106
|
end
|
101
107
|
alias to_s inspect
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
# rubocop:disable Metrics/AbcSize
|
112
|
+
def count_covered_branches(line_number)
|
113
|
+
branches = coverage.select { |cov| cov.size == 4 && cov[0] == line_number }
|
114
|
+
count_covered = branches.count { |cov| cov[3].positive? }
|
115
|
+
|
116
|
+
return '' if branches.size.zero?
|
117
|
+
|
118
|
+
if count_covered < branches.size
|
119
|
+
Rainbow(' branches: ').italic.darkgray.dark + \
|
120
|
+
Rainbow("#{count_covered}/#{branches.size}").italic.red
|
121
|
+
else
|
122
|
+
Rainbow(" branches: #{count_covered}/#{branches.size}").italic.darkgray.dark
|
123
|
+
end
|
124
|
+
end
|
125
|
+
# rubocop:enable Metrics/AbcSize
|
102
126
|
end
|
103
127
|
end
|
data/lib/undercover/version.rb
CHANGED
data/undercover.gemspec
CHANGED
@@ -23,18 +23,20 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
|
24
24
|
spec.require_paths = ['lib']
|
25
25
|
|
26
|
+
spec.required_ruby_version = '>= 2.5.0'
|
27
|
+
|
26
28
|
spec.add_dependency 'imagen', '>= 0.1.8'
|
27
29
|
spec.add_dependency 'rainbow', '>= 2.1', '< 4.0'
|
28
|
-
spec.add_dependency 'rugged', '>= 0.27', '< 1.
|
30
|
+
spec.add_dependency 'rugged', '>= 0.27', '< 1.2'
|
29
31
|
|
30
32
|
spec.add_development_dependency 'bundler'
|
31
33
|
spec.add_development_dependency 'pry'
|
32
34
|
spec.add_development_dependency 'rake', '~> 13.0'
|
33
35
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
34
|
-
spec.add_development_dependency 'rubocop', '~>
|
36
|
+
spec.add_development_dependency 'rubocop', '~> 1.9.1'
|
35
37
|
spec.add_development_dependency 'simplecov'
|
36
38
|
spec.add_development_dependency 'simplecov-html'
|
37
|
-
spec.add_development_dependency 'simplecov-lcov'
|
39
|
+
spec.add_development_dependency 'simplecov-lcov', '~> 0.8'
|
38
40
|
spec.add_development_dependency 'timecop'
|
39
41
|
end
|
40
42
|
# rubocop:enable Metrics/BlockLength
|
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.4.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:
|
11
|
+
date: 2021-02-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: imagen
|
@@ -53,7 +53,7 @@ dependencies:
|
|
53
53
|
version: '0.27'
|
54
54
|
- - "<"
|
55
55
|
- !ruby/object:Gem::Version
|
56
|
-
version: '1.
|
56
|
+
version: '1.2'
|
57
57
|
type: :runtime
|
58
58
|
prerelease: false
|
59
59
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -63,7 +63,7 @@ dependencies:
|
|
63
63
|
version: '0.27'
|
64
64
|
- - "<"
|
65
65
|
- !ruby/object:Gem::Version
|
66
|
-
version: '1.
|
66
|
+
version: '1.2'
|
67
67
|
- !ruby/object:Gem::Dependency
|
68
68
|
name: bundler
|
69
69
|
requirement: !ruby/object:Gem::Requirement
|
@@ -126,14 +126,14 @@ dependencies:
|
|
126
126
|
requirements:
|
127
127
|
- - "~>"
|
128
128
|
- !ruby/object:Gem::Version
|
129
|
-
version:
|
129
|
+
version: 1.9.1
|
130
130
|
type: :development
|
131
131
|
prerelease: false
|
132
132
|
version_requirements: !ruby/object:Gem::Requirement
|
133
133
|
requirements:
|
134
134
|
- - "~>"
|
135
135
|
- !ruby/object:Gem::Version
|
136
|
-
version:
|
136
|
+
version: 1.9.1
|
137
137
|
- !ruby/object:Gem::Dependency
|
138
138
|
name: simplecov
|
139
139
|
requirement: !ruby/object:Gem::Requirement
|
@@ -166,16 +166,16 @@ dependencies:
|
|
166
166
|
name: simplecov-lcov
|
167
167
|
requirement: !ruby/object:Gem::Requirement
|
168
168
|
requirements:
|
169
|
-
- - "
|
169
|
+
- - "~>"
|
170
170
|
- !ruby/object:Gem::Version
|
171
|
-
version: '0'
|
171
|
+
version: '0.8'
|
172
172
|
type: :development
|
173
173
|
prerelease: false
|
174
174
|
version_requirements: !ruby/object:Gem::Requirement
|
175
175
|
requirements:
|
176
|
-
- - "
|
176
|
+
- - "~>"
|
177
177
|
- !ruby/object:Gem::Version
|
178
|
-
version: '0'
|
178
|
+
version: '0.8'
|
179
179
|
- !ruby/object:Gem::Dependency
|
180
180
|
name: timecop
|
181
181
|
requirement: !ruby/object:Gem::Requirement
|
@@ -238,14 +238,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
238
238
|
requirements:
|
239
239
|
- - ">="
|
240
240
|
- !ruby/object:Gem::Version
|
241
|
-
version:
|
241
|
+
version: 2.5.0
|
242
242
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
243
243
|
requirements:
|
244
244
|
- - ">="
|
245
245
|
- !ruby/object:Gem::Version
|
246
246
|
version: '0'
|
247
247
|
requirements: []
|
248
|
-
rubygems_version: 3.
|
248
|
+
rubygems_version: 3.2.3
|
249
249
|
signing_key:
|
250
250
|
specification_version: 4
|
251
251
|
summary: Actionable code coverage - detects untested code blocks in recent changes
|