deep-cover 0.6.4 → 0.7.0
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/.deep_cover.rb +5 -0
- data/.gitignore +7 -4
- data/.rubocop.yml +7 -0
- data/CHANGELOG.md +27 -0
- data/Gemfile +5 -1
- data/README.md +47 -53
- data/Rakefile +20 -15
- data/deep_cover.gemspec +2 -3
- data/exe/deep-cover +2 -4
- data/lib/deep_cover/cli.rb +85 -0
- data/lib/deep_cover/cli/commands/clear.rb +10 -0
- data/lib/deep_cover/cli/commands/clone.rb +22 -0
- data/lib/deep_cover/cli/commands/exec.rb +37 -0
- data/lib/deep_cover/cli/commands/gather.rb +36 -0
- data/lib/deep_cover/cli/commands/help.rb +34 -0
- data/lib/deep_cover/cli/commands/merge.rb +10 -0
- data/lib/deep_cover/cli/commands/report.rb +14 -0
- data/lib/deep_cover/cli/commands/run_expression.rb +13 -0
- data/lib/deep_cover/cli/commands/short_help.rb +26 -0
- data/lib/deep_cover/cli/commands/version.rb +15 -0
- data/lib/deep_cover/cli/tools.rb +18 -0
- data/lib/deep_cover/cover_cloned_tree.rb +58 -0
- data/lib/deep_cover/expression_debugger.rb +122 -0
- data/lib/deep_cover/instrumented_clone_reporter.rb +127 -0
- metadata +22 -33
- data/bin/console +0 -14
- data/bin/cov +0 -43
- data/bin/setup +0 -8
- data/bin/test_gems +0 -54
- data/bin/testall +0 -88
- data/future_read_me.md +0 -108
- data/lib/deep_cover/cli/debugger.rb +0 -127
- data/lib/deep_cover/cli/exec.rb +0 -27
- data/lib/deep_cover/cli/instrumented_clone_reporter.rb +0 -197
- data/lib/deep_cover/cli/runner.rb +0 -126
- data/lib/deep_cover/dump_covered_code.rb +0 -36
- data/lib/deep_cover_entry.rb +0 -3
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tmpdir'
|
4
|
+
|
5
|
+
module DeepCover
|
6
|
+
class CLI
|
7
|
+
desc 'clone [OPTIONS] [COMMAND TO RUN]', 'Gets the coverage using clone mode'
|
8
|
+
option '--output', desc: 'output folder', type: :string, default: DeepCover.config.output, aliases: '-o'
|
9
|
+
option '--reporter', desc: 'reporter to use', type: :string, default: DeepCover.config.reporter
|
10
|
+
option '--open', desc: 'open the output coverage', type: :boolean, default: CLI_DEFAULTS[:open]
|
11
|
+
|
12
|
+
def clone(*command_parts)
|
13
|
+
if command_parts.empty?
|
14
|
+
command_parts = CLI_DEFAULTS[:command]
|
15
|
+
puts "No command specified, using default of: #{command_parts.join(' ')}"
|
16
|
+
end
|
17
|
+
|
18
|
+
require_relative '../../instrumented_clone_reporter'
|
19
|
+
InstrumentedCloneReporter.new(**processed_options.merge(command: command_parts)).run
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DeepCover
|
4
|
+
class CLI
|
5
|
+
# Stop parsing and treat everything as positional argument if
|
6
|
+
# we encounter an unknown option or a positional argument.
|
7
|
+
# `check_unknown_options!` (defined in cli.rb) happens first,
|
8
|
+
# so we just stop on a positional argument.
|
9
|
+
stop_on_unknown_option! :exec
|
10
|
+
|
11
|
+
desc 'exec [OPTIONS] [COMMAND TO RUN]', 'Execute the command with coverage activated'
|
12
|
+
option '--output', desc: 'output folder', type: :string, default: DeepCover.config.output, aliases: '-o'
|
13
|
+
option '--reporter', desc: 'reporter to use', type: :string, default: DeepCover.config.reporter
|
14
|
+
option '--open', desc: 'open the output coverage', type: :boolean, default: CLI_DEFAULTS[:open]
|
15
|
+
|
16
|
+
def exec(*command_parts)
|
17
|
+
if command_parts.empty?
|
18
|
+
command_parts = CLI_DEFAULTS[:command]
|
19
|
+
puts "No command specified, using default of: #{command_parts.join(' ')}"
|
20
|
+
end
|
21
|
+
|
22
|
+
DeepCover.config.set(**processed_options.slice(*DEFAULTS.keys))
|
23
|
+
|
24
|
+
require 'yaml'
|
25
|
+
env_var = {'DEEP_COVER' => 'gather',
|
26
|
+
'DEEP_COVER_OPTIONS' => YAML.dump(DeepCover.config.to_hash_for_serialize),
|
27
|
+
}
|
28
|
+
|
29
|
+
DeepCover.delete_trackers
|
30
|
+
system(env_var, *command_parts)
|
31
|
+
exit_code = $?.exitstatus
|
32
|
+
coverage = Coverage.load
|
33
|
+
puts coverage.report(**processed_options)
|
34
|
+
exit(exit_code)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DeepCover
|
4
|
+
class CLI
|
5
|
+
# Stop parsing and treat everything as positional argument if
|
6
|
+
# we encounter an unknown option or a positional argument.
|
7
|
+
# `check_unknown_options!` (defined in cli.rb) happens first,
|
8
|
+
# so we just stop on a positional argument.
|
9
|
+
stop_on_unknown_option! :gather
|
10
|
+
|
11
|
+
desc 'gather [OPTIONS] COMMAND TO RUN', 'Execute the command and gather the coverage data'
|
12
|
+
def gather(*command_parts)
|
13
|
+
if command_parts.empty?
|
14
|
+
warn set_color('`gather` needs a command to run', :red)
|
15
|
+
exit(1)
|
16
|
+
end
|
17
|
+
|
18
|
+
require 'yaml'
|
19
|
+
env_var = {'DEEP_COVER' => 'gather',
|
20
|
+
'DEEP_COVER_OPTIONS' => YAML.dump(processed_options.slice(*DEFAULTS.keys)),
|
21
|
+
}
|
22
|
+
|
23
|
+
# Clear inspiration from Bundler's kernel_exec
|
24
|
+
# https://github.com/bundler/bundler/blob/d44d803357506895555ff97f73e60d593820a0de/lib/bundler/cli/exec.rb#L50
|
25
|
+
begin
|
26
|
+
Kernel.exec(env_var, *command_parts)
|
27
|
+
rescue Errno::EACCES, Errno::ENOEXEC
|
28
|
+
warn set_color("not executable: #{command_parts.first}", :red)
|
29
|
+
exit 126 # Default exit code for that
|
30
|
+
rescue Errno::ENOENT
|
31
|
+
warn set_color("command not found: #{command_parts.first}", :red)
|
32
|
+
exit 127 # Default exit code for that
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DeepCover
|
4
|
+
class CLI
|
5
|
+
# Thor comes with a built-in help command. When displaying full help, it calls the class' help
|
6
|
+
# We override it to make it more to our taste.
|
7
|
+
|
8
|
+
# Copied from Thor's default one, then customized
|
9
|
+
def self.help(shell, subcommand = false)
|
10
|
+
list = printable_commands(true, subcommand)
|
11
|
+
Thor::Util.thor_classes_in(self).each do |klass|
|
12
|
+
list += klass.printable_commands(false)
|
13
|
+
end
|
14
|
+
list.sort! { |a, b| a[0] <=> b[0] }
|
15
|
+
|
16
|
+
main_commands, list = Tools.extract_commands_for_help(list, :exec, :clone)
|
17
|
+
|
18
|
+
shell.say 'Main commands:'
|
19
|
+
shell.print_table(main_commands, indent: 2, truncate: true)
|
20
|
+
|
21
|
+
lower_level_commands, list = Tools.extract_commands_for_help(list, :gather, :report, :clear, :merge)
|
22
|
+
shell.say
|
23
|
+
shell.say 'Lower-level commands:'
|
24
|
+
shell.print_table(lower_level_commands, indent: 2, truncate: true)
|
25
|
+
|
26
|
+
shell.say
|
27
|
+
shell.say 'Misc commands:'
|
28
|
+
shell.print_table(list, indent: 2, truncate: true)
|
29
|
+
|
30
|
+
shell.say
|
31
|
+
class_options_help(shell)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DeepCover
|
4
|
+
class CLI
|
5
|
+
desc 'report [OPTIONS]', 'Generates report from coverage data that was gathered by previous commands'
|
6
|
+
option '--output', desc: 'output folder', type: :string, default: DeepCover.config.output, aliases: '-o'
|
7
|
+
option '--reporter', desc: 'reporter to use', type: :string, default: DeepCover.config.reporter
|
8
|
+
option '--open', desc: 'open the output coverage', type: :boolean, default: CLI_DEFAULTS[:open]
|
9
|
+
def report
|
10
|
+
coverage = Coverage.load
|
11
|
+
puts coverage.report(**processed_options)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DeepCover
|
4
|
+
class CLI
|
5
|
+
desc "run-expression [OPTIONS] 'ruby code'", 'Show coverage results for the given ruby expression'
|
6
|
+
option '--profile', desc: 'use profiler', type: :boolean if RUBY_PLATFORM != 'java'
|
7
|
+
option '--debug', aliases: '-d', desc: 'opens an interactive console for debugging', type: :boolean
|
8
|
+
def run_expression(expression)
|
9
|
+
require_relative '../expression_debugger'
|
10
|
+
ExpressionDebugger.new(expression, **options.transform_keys(&:to_sym)).show
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DeepCover
|
4
|
+
class CLI
|
5
|
+
desc 'short-help', 'Display a short help. Same as just `deep-cover`'
|
6
|
+
def short_help
|
7
|
+
self.class.short_help(shell)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.short_help(shell)
|
11
|
+
list = printable_commands(true, false)
|
12
|
+
Thor::Util.thor_classes_in(self).each do |klass|
|
13
|
+
list += klass.printable_commands(false)
|
14
|
+
end
|
15
|
+
|
16
|
+
main_commands, _ignored = Tools.extract_commands_for_help(list, :exec, :clone)
|
17
|
+
|
18
|
+
shell.say 'Main command:'
|
19
|
+
shell.print_table(main_commands, indent: 2, truncate: true)
|
20
|
+
|
21
|
+
shell.say
|
22
|
+
shell.say 'Use `deep-cover help` for a full help with a list of lower-level commands'
|
23
|
+
shell.say 'and information on the available options'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DeepCover
|
4
|
+
class CLI
|
5
|
+
# Add some top-level aliases for this command
|
6
|
+
# So it's possible to do `deep-cover -v` or `deep-cover --version`
|
7
|
+
map %w(-v --version) => :version
|
8
|
+
|
9
|
+
desc 'version', "Print deep-cover's version"
|
10
|
+
def version
|
11
|
+
require 'deep_cover/version'
|
12
|
+
puts "deep-cover version #{DeepCover::VERSION}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DeepCover
|
4
|
+
class CLI
|
5
|
+
module Tools
|
6
|
+
# Extracts the commands for the help by name, in same order as the names.
|
7
|
+
# This make handling the output of printable_commands more easily.
|
8
|
+
# Returns the matching and the remaining commands.
|
9
|
+
def self.extract_commands_for_help(commands, *names)
|
10
|
+
matching = names.map do |name|
|
11
|
+
commands.detect { |usage, desc| usage.start_with?("deep-cover #{name}") }
|
12
|
+
end
|
13
|
+
remains = commands - matching
|
14
|
+
[matching, remains]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DeepCover
|
4
|
+
Tools.silence_warnings do
|
5
|
+
require 'with_progress'
|
6
|
+
end
|
7
|
+
module Tools::CoverClonedTree
|
8
|
+
def cover_cloned_tree(original_paths, original_root:, clone_root:) # &block
|
9
|
+
# Make sure the directories end with a '/' for safe replacing
|
10
|
+
original_root = File.join(File.expand_path(original_root), '')
|
11
|
+
clone_root = File.join(File.expand_path(clone_root), '')
|
12
|
+
|
13
|
+
paths_with_bad_syntax = []
|
14
|
+
original_paths, paths_not_in_root = original_paths.partition { |path| path.start_with?(original_root) }
|
15
|
+
|
16
|
+
original_paths.each.with_progress(title: 'Rewriting') do |original_path|
|
17
|
+
clone_path = Pathname(original_path.sub(original_root, clone_root))
|
18
|
+
begin
|
19
|
+
source = clone_path.read
|
20
|
+
# We need to use the original_path so that the tracker_paths inserted in the files
|
21
|
+
# during the instrumentation are for the original paths
|
22
|
+
covered_code = DeepCover.coverage.covered_code(original_path, source: source)
|
23
|
+
rescue Parser::SyntaxError
|
24
|
+
paths_with_bad_syntax << original_path
|
25
|
+
next
|
26
|
+
end
|
27
|
+
|
28
|
+
# Allow a passed block to edit the source that will be written
|
29
|
+
covered_source = covered_code.covered_source
|
30
|
+
covered_source = yield covered_source, original_path, clone_path if block_given?
|
31
|
+
|
32
|
+
clone_path.dirname.mkpath
|
33
|
+
clone_path.write(covered_source)
|
34
|
+
end
|
35
|
+
|
36
|
+
unless paths_with_bad_syntax.empty?
|
37
|
+
warn [
|
38
|
+
"#{paths_with_bad_syntax.size} files could not be instrumented because of syntax errors:",
|
39
|
+
*paths_with_bad_syntax.first(3),
|
40
|
+
('...' if paths_with_bad_syntax.size > 3),
|
41
|
+
].compact.join("\n")
|
42
|
+
end
|
43
|
+
|
44
|
+
unless paths_not_in_root.empty?
|
45
|
+
warn [
|
46
|
+
"#{paths_not_in_root.size} files could not be instrumented because they are not within the directory being cloned.",
|
47
|
+
"(Consider configuring DeepCover's paths to to avoid those files being included)",
|
48
|
+
*paths_not_in_root.first(5),
|
49
|
+
('...' if paths_not_in_root.size > 5),
|
50
|
+
].compact.join("\n")
|
51
|
+
end
|
52
|
+
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Tools.extend Tools::CoverClonedTree
|
58
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DeepCover
|
4
|
+
class ExpressionDebugger
|
5
|
+
include Tools
|
6
|
+
|
7
|
+
module ColorAST
|
8
|
+
def fancy_type
|
9
|
+
color = case
|
10
|
+
when !executable?
|
11
|
+
:faint
|
12
|
+
when !was_executed?
|
13
|
+
:red
|
14
|
+
when flow_interrupt_count > 0
|
15
|
+
:yellow
|
16
|
+
else
|
17
|
+
:green
|
18
|
+
end
|
19
|
+
Term::ANSIColor.send(color, super)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :options
|
24
|
+
def initialize(source, filename: '(source)', lineno: 1, debug: false, **options)
|
25
|
+
@source = source
|
26
|
+
@filename = filename
|
27
|
+
@lineno = lineno
|
28
|
+
@debug = debug
|
29
|
+
@options = options
|
30
|
+
end
|
31
|
+
|
32
|
+
def show
|
33
|
+
Tools.profile(options[:profile]) do
|
34
|
+
execute
|
35
|
+
covered_code.freeze # Our output relies on the counts, so better freeze. See [#13]
|
36
|
+
if @debug
|
37
|
+
show_line_coverage
|
38
|
+
show_instrumented_code
|
39
|
+
show_ast
|
40
|
+
end
|
41
|
+
show_char_coverage
|
42
|
+
end
|
43
|
+
pry if @debug
|
44
|
+
finish
|
45
|
+
end
|
46
|
+
|
47
|
+
def show_line_coverage
|
48
|
+
output { "Line Coverage: Builtin | DeepCover | DeepCover Strict:\n" }
|
49
|
+
begin
|
50
|
+
builtin_line_coverage = builtin_coverage(@source, @filename, @lineno)
|
51
|
+
our_line_coverage = our_coverage(@source, @filename, @lineno, **options)
|
52
|
+
our_strict_line_coverage = our_coverage(@source, @filename, @lineno, allow_partial: false, **options)
|
53
|
+
output do
|
54
|
+
lines = format(builtin_line_coverage, our_line_coverage, our_strict_line_coverage, source: @source)
|
55
|
+
number_lines(lines, lineno: @lineno)
|
56
|
+
end
|
57
|
+
rescue Exception => e
|
58
|
+
output { "Can't run coverage: #{e.class}: #{e}\n#{e.backtrace.join("\n")}" }
|
59
|
+
@failed = true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def show_instrumented_code
|
64
|
+
output { "\nInstrumented code:\n" }
|
65
|
+
output { format_generated_code(covered_code) }
|
66
|
+
end
|
67
|
+
|
68
|
+
def show_ast
|
69
|
+
output { "\nParsed code:\n" }
|
70
|
+
Node.prepend ColorAST
|
71
|
+
output { covered_code.covered_ast }
|
72
|
+
end
|
73
|
+
|
74
|
+
def show_char_coverage
|
75
|
+
output { "\nNode coverage:\n" }
|
76
|
+
|
77
|
+
output { format_char_cover(covered_code, show_whitespace: !!ENV['W'], **options) }
|
78
|
+
end
|
79
|
+
|
80
|
+
def pry
|
81
|
+
a = covered_code.covered_ast
|
82
|
+
b = a.children.first
|
83
|
+
::DeepCover.load_pry
|
84
|
+
binding.pry
|
85
|
+
end
|
86
|
+
|
87
|
+
def finish
|
88
|
+
exit(!@failed)
|
89
|
+
end
|
90
|
+
|
91
|
+
def covered_code
|
92
|
+
@covered_code ||= CoveredCode.new(source: @source, path: @filename, lineno: @lineno)
|
93
|
+
end
|
94
|
+
|
95
|
+
def execute
|
96
|
+
execute_sample(covered_code)
|
97
|
+
# output { trace_counts } # Keep for low-level debugging purposes
|
98
|
+
rescue Exception => e
|
99
|
+
output { "Can't `execute_sample`:#{e.class}: #{e}\n#{e.backtrace.join("\n")}" }
|
100
|
+
@failed = true
|
101
|
+
end
|
102
|
+
|
103
|
+
def trace_counts
|
104
|
+
all = []
|
105
|
+
trace = TracePoint.new(:call) do |tr|
|
106
|
+
if %i[flow_entry_count flow_completion_count execution_count].include? tr.method_id
|
107
|
+
node = tr.self
|
108
|
+
str = "#{node.type} #{(node.value if node.respond_to?(:value))} #{tr.method_id}"
|
109
|
+
all << str unless all.last == str
|
110
|
+
end
|
111
|
+
end
|
112
|
+
trace.enable { covered_code.freeze }
|
113
|
+
all
|
114
|
+
end
|
115
|
+
|
116
|
+
def output
|
117
|
+
Tools.dont_profile do
|
118
|
+
puts yield
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tmpdir'
|
4
|
+
|
5
|
+
module DeepCover
|
6
|
+
require_relative 'cover_cloned_tree'
|
7
|
+
|
8
|
+
class InstrumentedCloneReporter
|
9
|
+
include Tools
|
10
|
+
# matches regular files, .files, ..files, but not '.' or '..'
|
11
|
+
GLOB_ALL_CONTENT = '{,.[^.],..?}*'
|
12
|
+
|
13
|
+
def initialize(**options)
|
14
|
+
@options = CLI_DEFAULTS.merge(options)
|
15
|
+
@root_path = @source_path = Pathname.new('.').expand_path
|
16
|
+
if !@root_path.join('Gemfile').exist? && @root_path.dirname.join('Gemfile').exist?
|
17
|
+
# E.g. rails/activesupport
|
18
|
+
@root_path = @root_path.dirname
|
19
|
+
end
|
20
|
+
path = Pathname('~/test_deep_cover').expand_path
|
21
|
+
if path.exist?
|
22
|
+
@dest_root = path.join(@source_path.basename)
|
23
|
+
@dest_root.mkpath
|
24
|
+
else
|
25
|
+
@dest_root = Pathname.new(Dir.mktmpdir('deep_cover_test'))
|
26
|
+
end
|
27
|
+
|
28
|
+
gem_relative_path = @source_path.relative_path_from(@root_path)
|
29
|
+
@main_path = @dest_root.join(gem_relative_path)
|
30
|
+
end
|
31
|
+
|
32
|
+
def clear
|
33
|
+
FileUtils.rm_rf(Dir.glob("#{@dest_root}/#{GLOB_ALL_CONTENT}"))
|
34
|
+
end
|
35
|
+
|
36
|
+
def copy
|
37
|
+
return true if @copied
|
38
|
+
puts 'Cloning...'
|
39
|
+
FileUtils.cp_r(Dir.glob("#{@root_path}/#{GLOB_ALL_CONTENT}"), @dest_root)
|
40
|
+
@copied = true
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_entry_point_file
|
44
|
+
require 'tempfile'
|
45
|
+
file = Tempfile.new(['deep_cover_entry_point', '.rb'])
|
46
|
+
template = File.read(DeepCover::CORE_GEM_LIB_DIRECTORY + '/deep_cover/setup/clone_mode_entry_template.rb')
|
47
|
+
|
48
|
+
cache_directory = DeepCover.config.cache_directory.to_s
|
49
|
+
tracker_global = DeepCover.config.tracker_global
|
50
|
+
|
51
|
+
# Those are the fake global variables that we actually replace as we copy the template over
|
52
|
+
template.gsub!('$_cache_directory', cache_directory.inspect)
|
53
|
+
template.gsub!('$_global_name', tracker_global.inspect)
|
54
|
+
template.gsub!('$_core_gem_lib_directory', DeepCover::CORE_GEM_LIB_DIRECTORY.inspect)
|
55
|
+
|
56
|
+
file.write(template)
|
57
|
+
file.close
|
58
|
+
|
59
|
+
# We dont want the file to be removed, this way it stays as long as the clones directory does.
|
60
|
+
ObjectSpace.undefine_finalizer(file)
|
61
|
+
|
62
|
+
file.path
|
63
|
+
end
|
64
|
+
|
65
|
+
def patch_rubocop
|
66
|
+
path = @dest_root.join('.rubocop.yml')
|
67
|
+
return unless path.exist?
|
68
|
+
puts 'Patching .rubocop.yml'
|
69
|
+
config = YAML.load(path.read)
|
70
|
+
all_cop_excludes = ((config['AllCops'] ||= {})['Exclude'] ||= [])
|
71
|
+
|
72
|
+
# Ensure they end with a '/'
|
73
|
+
original_root = File.join(File.expand_path(@root_path), '')
|
74
|
+
clone_root = File.join(File.expand_path(@dest_root), '')
|
75
|
+
|
76
|
+
paths_to_ignore = DeepCover.all_tracked_file_paths
|
77
|
+
paths_to_ignore.select! { |p| p.start_with?(original_root) }
|
78
|
+
paths_to_ignore.map! { |p| p.sub(original_root, clone_root) }
|
79
|
+
|
80
|
+
all_cop_excludes.concat(paths_to_ignore)
|
81
|
+
path.write("# This file was modified by DeepCover\n" + YAML.dump(config))
|
82
|
+
end
|
83
|
+
|
84
|
+
def patch
|
85
|
+
patch_rubocop
|
86
|
+
end
|
87
|
+
|
88
|
+
def remove_deep_cover_config
|
89
|
+
path = @dest_root.join('.deep_cover.rb')
|
90
|
+
return unless path.exist?
|
91
|
+
File.delete(path)
|
92
|
+
end
|
93
|
+
|
94
|
+
def cover
|
95
|
+
entry_point_path = create_entry_point_file
|
96
|
+
Tools.cover_cloned_tree(DeepCover.all_tracked_file_paths,
|
97
|
+
clone_root: @dest_root,
|
98
|
+
original_root: @root_path) do |source|
|
99
|
+
source.sub(/\A(#.*\n|\s+)*/) do |header|
|
100
|
+
"#{header}require #{entry_point_path.inspect};"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def process
|
106
|
+
DeepCover.delete_trackers
|
107
|
+
system({'DISABLE_SPRING' => 'true', 'DEEP_COVER_OPTIONS' => nil}, *@options[:command], chdir: @main_path)
|
108
|
+
$?.exitstatus
|
109
|
+
end
|
110
|
+
|
111
|
+
def report
|
112
|
+
coverage = Coverage.load
|
113
|
+
puts coverage.report(**@options)
|
114
|
+
end
|
115
|
+
|
116
|
+
def run
|
117
|
+
clear
|
118
|
+
copy
|
119
|
+
cover
|
120
|
+
patch
|
121
|
+
remove_deep_cover_config
|
122
|
+
exit_code = process
|
123
|
+
report
|
124
|
+
exit(exit_code)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|