Skip to content

Commit

Permalink
Add file filtering with glob patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
grodowski committed Dec 3, 2024
1 parent e01d298 commit 036dd0a
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 14 deletions.
15 changes: 14 additions & 1 deletion lib/undercover.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ class Report
attr_reader :changeset,
:lcov,
:results,
:code_dir
:code_dir,
:glob_filters

# Initializes a new Undercover::Report
#
Expand All @@ -32,6 +33,10 @@ def initialize(changeset, opts)
@lcov = LcovParser.parse(File.open(opts.lcov))
@code_dir = opts.path
@changeset = changeset.update
@glob_filters = {
allow: opts.glob_allow_filters,
reject: opts.glob_reject_filters
}
@loaded_files = {}
@results = {}
end
Expand All @@ -50,6 +55,7 @@ def build
dist_from_line_no_sorter = lambda do |res1, res2|
dist_from_line_no[res1] <=> dist_from_line_no[res2]
end

load_and_parse_file(filepath)

next unless loaded_files[filepath]
Expand Down Expand Up @@ -93,6 +99,8 @@ def load_and_parse_file(filepath)

coverage = lcov.coverage(filepath)

return unless include_file?(filepath)

root_ast = Imagen::Node::Root.new.build_from_file(
File.join(code_dir, filepath)
)
Expand All @@ -105,5 +113,10 @@ def load_and_parse_file(filepath)
end
end
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize

def include_file?(filepath)
fnmatch = proc { |glob| File.fnmatch(glob, filepath) }
glob_filters[:allow].any?(fnmatch) && glob_filters[:reject].none?(fnmatch)
end
end
end
30 changes: 25 additions & 5 deletions lib/undercover/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
require 'pathname'

module Undercover
class Options
class Options # rubocop:disable Metrics/ClassLength
RUN_MODE = [
RUN_MODE_DIFF_STRICT = :diff_strict, # warn for changed lines
# RUN_MODE_DIFF_FILES = :diff_files, # warn for changed whole files
Expand All @@ -17,7 +17,15 @@ class Options
# OUTPUT_CIRCLEMATOR = :circlemator # posts warnings as review comments
].freeze

attr_accessor :lcov, :path, :git_dir, :compare, :syntax_version
DEFAULT_FILE_INCLUDE_GLOBS = %w[*.rb *.rake *.ru Rakefile].freeze

attr_accessor :lcov,
:path,
:git_dir,
:compare,
:syntax_version,
:glob_allow_filters,
:glob_reject_filters

def initialize
# TODO: use run modes
Expand All @@ -27,6 +35,8 @@ def initialize
# set defaults
self.path = '.'
self.git_dir = '.git'
self.glob_allow_filters = DEFAULT_FILE_INCLUDE_GLOBS
self.glob_reject_filters = []
end

# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
Expand All @@ -51,9 +61,7 @@ def parse(args)
git_dir_option(opts)
compare_option(opts)
ruby_syntax_option(opts)
# TODO: parse dem other options and assign to self
# --quiet (skip progress bar)
# --exit-status (do not print report, just exit)
file_filters(opts)
end.parse(args)

guess_lcov_path unless lcov
Expand Down Expand Up @@ -119,5 +127,17 @@ def guess_lcov_path
cwd = Pathname.new(File.expand_path(path))
self.lcov = File.join(cwd, 'coverage', 'lcov', "#{cwd.split.last}.lcov")
end

def file_filters(parser)
desc = 'Include files matching specified glob patterns (comma separated)'
parser.on('-f', '--include-files comma_separated_globs', desc) do |comma_separated_globs|
self.glob_allow_filters = comma_separated_globs.strip.split(',')
end

desc = 'Skip files matching specified glob patterns (comma separated)'
parser.on('-x', '--exclude-files comma_separated_globs', desc) do |comma_separated_globs|
self.glob_reject_filters = comma_separated_globs.strip.split(',')
end
end
end
end
7 changes: 2 additions & 5 deletions lib/undercover/result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Result
def initialize(node, file_cov, file_path)
@node = node
@coverage = file_cov.select do |ln, _|
first_line == last_line ? ln == first_line : ln > first_line && ln < last_line
(node.empty_def? ? ln >= first_line : ln > first_line) && ln < last_line
end
@file_path = file_path
@flagged = false
Expand Down Expand Up @@ -45,9 +45,7 @@ def uncovered?(line_no)
# as 0 if any branch is untested.
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
def coverage_f
if coverage.empty?
return node.children.empty? ? 1.0 : 0.0
end
return 0.0 if coverage.empty?

lines = {}
coverage.each do |ln, block_or_line_cov, _, branch_cov|
Expand All @@ -58,7 +56,6 @@ def coverage_f
lines[ln] = 0
end
end
return 1.0 if lines.keys.empty?

(lines.values.sum.to_f / lines.keys.size).round(4)
end
Expand Down
7 changes: 7 additions & 0 deletions lib/untested.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class Foo
def initialize
@super = 1
end
end
20 changes: 20 additions & 0 deletions spec/cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,26 @@
subject.run(%w[-cHEAD~1])
end

it 'sets file globs from options' do
stub_stdout
stub_build
expect(Undercover::Report)
.to receive(:new)
.with(
instance_of(Undercover::Changeset),
undercover_options(
lcov: a_string_matching(/coverage\/lcov\/\w+\.lcov/),
path: '.',
git_dir: '.git',
compare: nil,
glob_allow_filters: ['*.rb', '*.rake'],
glob_reject_filters: ['Rakefile']
)
)
.and_call_original
subject.run(%w[-f *.rb,*.rake -x Rakefile])
end

it 'returns 0 exit code on success' do
stub_stdout

Expand Down
15 changes: 15 additions & 0 deletions spec/fixtures/Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

require 'bundler/gem_tasks'
require 'rspec/core/rake_task'
require 'rubocop/rake_task'

def rakefile # TODO: fix known issue of not parsing top-level expressions!
desc 'Run RuboCop'
RuboCop::RakeTask.new(:rubocop)

desc 'Run Tests'
RSpec::Core::RakeTask.new(:spec)

task default: %i[rubocop spec]
end
Binary file modified spec/fixtures/test.git/index
Binary file not shown.
13 changes: 11 additions & 2 deletions spec/report_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,13 @@
.to receive(:each_changed_line)
.and_yield('test_two_patches.rb', 6)
.and_yield('test_two_patches.rb', 21)
.and_yield('Rakefile', 1)
.and_yield('.undercover_config', 1) # unparsable, won't appear in the report
mock_changeset
end

it 'flags 2 two results' do
it 'flags 2 two results when Rakefile is ignored' do
options.glob_reject_filters = ['Rakefile']
options.lcov = 'spec/fixtures/test_two_patches.lcov'
report.build
flagged = report.flagged_results
Expand All @@ -99,6 +102,7 @@
end

it 'deprecated build_warnings still works' do
options.glob_allow_filters = ['*.rb']
options.lcov = 'spec/fixtures/test_two_patches.lcov'
report.build
warnings = report.build_warnings.to_a
Expand All @@ -113,12 +117,17 @@
options.lcov = 'spec/fixtures/test_empty.lcov'
report.build
warnings = report.build_warnings.to_a
expect(warnings.size).to eq(2)
expect(warnings.size).to eq(3)

expect(warnings[0].file_path).to eq('test_two_patches.rb')
expect(warnings[0].first_line).to eq(3)
expect(warnings[1].file_path).to eq('test_two_patches.rb')
expect(warnings[1].first_line).to eq(15)
expect(warnings[2].file_path).to eq('Rakefile')
expect(warnings[2].first_line).to eq(7)

expect(warnings[0].coverage_f).to eq(0.0)
expect(warnings[1].coverage_f).to eq(0.0)
end
end
end
2 changes: 1 addition & 1 deletion undercover.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
spec.required_ruby_version = '>= 3.0.0'

spec.add_dependency 'bigdecimal'
spec.add_dependency 'imagen', '>= 0.1.8'
spec.add_dependency 'imagen', '>= 0.2.0'
spec.add_dependency 'rainbow', '>= 2.1', '< 4.0'
spec.add_dependency 'rugged', '>= 0.27', '< 1.8'
end

0 comments on commit 036dd0a

Please sign in to comment.