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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba2a988ce8b2ef9451615675538b268f4d663cb141288a646b2604785ea92dc6
4
- data.tar.gz: 6822d32d0b2000e711194c0d595b2f69dcaa3020740db9613be8f6fceea1e4e9
3
+ metadata.gz: c860e600589d92698fa5df94b1b8fe9283cbb00cdc595410b9c3a413d74b3095
4
+ data.tar.gz: e2c26b709c691201f473846e0cb6a7fa6844c5d1dc73169ca533d95482182f6c
5
5
  SHA512:
6
- metadata.gz: 8ada6a585eee4ff30f9a520dde96f0b3b74bd11ab05a9e7857b356da7c00519e81d36dda12ddd4c7afde81b23cb73bc1c88a35f2f559f1cf9a638c42eab48052
7
- data.tar.gz: 6c846695987c6126e7db5c7c363e44756f57aaf34374157bd35c0e723469f705a625244e90818a39b07e5626df8b34f248796405f95a5c9ed884e4760af304f3
6
+ metadata.gz: ace70eb4f75d2d57bda9d906925a7b5525c5a67520380ba0327a5344ed6718b79ea2587a5a0fb4d2a09d430d09b30eb2d1ac63c503be17197ff9c6455ab12b00
7
+ data.tar.gz: a2ec9a3b4d27cb9eaa7b4595f71ff9b12108e939864a6f5279aece22cd728e358dd50b16e63d0537780154e3ffd20e0712bce8322a8591e4f08f70d9d6818145
@@ -14,3 +14,7 @@ updates:
14
14
  - 1.12.1
15
15
  - 1.8.1
16
16
  - 1.9.0
17
+ - package-ecosystem: "github-actions"
18
+ directory: "/"
19
+ schedule:
20
+ interval: "weekly"
@@ -7,7 +7,7 @@ jobs:
7
7
  matrix:
8
8
  ruby: ['3.3', '3.0']
9
9
  steps:
10
- - uses: actions/checkout@v3
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@v3
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@v3
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 $GITHUB_SHA \
41
+ --commit ${{ github.event.pull_request.head.sha || github.sha }} \
42
42
  --lcov /home/runner/work/undercover/undercover/undercover.lcov
data/.rubocop.yml CHANGED
@@ -24,6 +24,12 @@ Metrics/BlockLength:
24
24
  Exclude:
25
25
  - spec/**/*
26
26
 
27
+ Metrics/CyclomaticComplexity:
28
+ Max: 10
29
+
30
+ Metrics/PerceivedComplexity:
31
+ Max: 10
32
+
27
33
  Style/HashEachMethods:
28
34
  Enabled: true
29
35
 
data/.tool-versions CHANGED
@@ -1 +1 @@
1
- ruby 3.3.0
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.5.0...HEAD
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
  ```
@@ -74,7 +74,9 @@ module Undercover
74
74
  def compare_base_obj
75
75
  return nil unless compare_base
76
76
 
77
- repo.lookup(repo.merge_base(compare_base.to_s, head))
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
@@ -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
- attr_accessor :lcov, :path, :git_dir, :compare, :syntax_version
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
- # TODO: parse dem other options and assign to self
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
@@ -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
- first_line == last_line ? ln == first_line : ln > first_line && ln < last_line
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Undercover
4
- VERSION = '0.5.0'
4
+ VERSION = '0.6.0'
5
5
  end
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, Metrics/CyclomaticComplexity
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, Metrics/CyclomaticComplexity
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
- return if coverage.empty?
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.1.8'
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.5.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-01-09 00:00:00.000000000 Z
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.1.8
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.1.8
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.4
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