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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 876068f41c32798bbc3e6d2e37980021c5afebf2d7316700671741b64e4959ae
4
- data.tar.gz: 55fea89d18b7e6feeac2821f97a008999c2442aac83b53239c353fb05d6875f2
3
+ metadata.gz: 5104b390e6cc5e103274e4621c3ec1f01a75091703e2a3549ad7a629b0edd9e1
4
+ data.tar.gz: d7346137e3b284a8815e3b0c55c22ee154fbb2e781576204eef898e3f221218d
5
5
  SHA512:
6
- metadata.gz: 1210f2973aee4c7bea1484c9eef36dce6bf8582eec0f9f95a94585bdc03cce9df7e5f8d750f33d2838f0329fd466e636fba7f05d2080c998717048a09520172f
7
- data.tar.gz: 0cc9be1fa5e3fe60009b71a9b2212c24f2f3c7f20a8df674821dcbd2c2ca5e1157dc04ece674b221d8bbbcaab3f4cfb6084846241474d664e98b644484e77e08
6
+ metadata.gz: 5a7cda81269eb9f3e5cb1e752c83e5b203dc01b64409765ba69c2e9fb9ef8a456d324a631f7eb5341938a3781328a688556292c552d13b8ef431490e7304875b
7
+ data.tar.gz: 980ecc847bee0a649ed9953e07118b22df8ed691ea5e72711511cd5759ad1ec507f56fdbc190f9824197f82f8d244fcb8a7f9545b75fda24d68cb5abb9311097
@@ -5,7 +5,7 @@ jobs:
5
5
  runs-on: ubuntu-latest
6
6
  strategy:
7
7
  matrix:
8
- ruby: ['2.7.x', '2.6.x', '2.5.x']
8
+ ruby: ['3.0.x', '2.7.x', '2.6.x', '2.5.x']
9
9
  steps:
10
10
  - uses: actions/checkout@v1
11
11
  - name: Set up Ruby ${{ matrix.ruby }}
data/.rubocop.yml CHANGED
@@ -1,5 +1,6 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.7.0
2
+ NewCops: enable
3
+ TargetRubyVersion: 2.5.0
3
4
  Exclude:
4
5
  - spec/fixtures/**/*
5
6
 
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
- **Inspects files in a git diff and warns on methods, classes and blocks which need test coverage.** Use it locally or as part of an automated build to shorten your code coverage feedback loop!
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! ' \
@@ -12,7 +12,8 @@ module Undercover
12
12
  include Enumerable
13
13
 
14
14
  attr_reader :files
15
- def_delegators :files, :each, :'<=>'
15
+
16
+ def_delegators :files, :each, :<=>
16
17
 
17
18
  def initialize(dir, compare_base = nil)
18
19
  @dir = dir
@@ -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
@@ -74,7 +74,7 @@ module Undercover
74
74
  def args_from_options_file(path)
75
75
  return [] unless File.exist?(path)
76
76
 
77
- File.read(path).split('\n').flat_map { |line| line.split(' ') }
77
+ File.read(path).split('\n').flat_map(&:split)
78
78
  end
79
79
 
80
80
  def project_options_file
@@ -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
- covered = coverage.reduce(0) do |sum, (_, cov)|
48
- sum + [[0, cov].max, 1].min
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
- (covered.to_f / coverage.size).round(4)
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
- cov_enum.peek[0]
64
- rescue StopIteration
65
- -1
66
- end
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Undercover
4
- VERSION = '0.3.4'
4
+ VERSION = '0.4.0'
5
5
  end
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.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', '~> 0.81.0'
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.3.4
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: 2020-04-05 00:00:00.000000000 Z
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.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.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: 0.81.0
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: 0.81.0
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: '0'
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.1.2
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