simplecov 1.1.1 → 1.2.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/README.md +148 -5
- data/exe/simplecov +0 -3
- data/lib/minitest/simplecov_plugin.rb +12 -9
- data/lib/simplecov/atomic_file.rb +16 -19
- data/lib/simplecov/autostart.rb +5 -7
- data/lib/simplecov/baseline/parser.rb +58 -0
- data/lib/simplecov/baseline.rb +170 -0
- data/lib/simplecov/cli/affected/changed_files.rb +57 -0
- data/lib/simplecov/cli/affected/selection.rb +117 -0
- data/lib/simplecov/cli/affected.rb +148 -0
- data/lib/simplecov/cli/badge/svg.rb +70 -0
- data/lib/simplecov/cli/badge.rb +62 -0
- data/lib/simplecov/cli/clean.rb +23 -24
- data/lib/simplecov/cli/command_helpers.rb +55 -19
- data/lib/simplecov/cli/completions/scripts.rb +114 -0
- data/lib/simplecov/cli/completions.rb +83 -0
- data/lib/simplecov/cli/coverage.rb +25 -28
- data/lib/simplecov/cli/coverage_file.rb +58 -14
- data/lib/simplecov/cli/dead_code/output.rb +100 -0
- data/lib/simplecov/cli/dead_code.rb +139 -0
- data/lib/simplecov/cli/diff/output.rb +45 -0
- data/lib/simplecov/cli/diff.rb +35 -67
- data/lib/simplecov/cli/dotfile.rb +83 -38
- data/lib/simplecov/cli/git.rb +41 -0
- data/lib/simplecov/cli/history/output.rb +135 -0
- data/lib/simplecov/cli/history.rb +67 -0
- data/lib/simplecov/cli/merge.rb +34 -39
- data/lib/simplecov/cli/open.rb +12 -15
- data/lib/simplecov/cli/patch/changed_lines.rb +149 -0
- data/lib/simplecov/cli/patch/output.rb +135 -0
- data/lib/simplecov/cli/patch.rb +169 -0
- data/lib/simplecov/cli/ratchet/output.rb +44 -0
- data/lib/simplecov/cli/ratchet.rb +83 -0
- data/lib/simplecov/cli/report.rb +18 -24
- data/lib/simplecov/cli/run.rb +8 -9
- data/lib/simplecov/cli/serve/report_preparer.rb +7 -6
- data/lib/simplecov/cli/serve/static_file_handler.rb +62 -56
- data/lib/simplecov/cli/serve.rb +27 -24
- data/lib/simplecov/cli/show/annotator.rb +87 -0
- data/lib/simplecov/cli/show/sweep.rb +36 -0
- data/lib/simplecov/cli/show.rb +133 -0
- data/lib/simplecov/cli/status/facts.rb +87 -0
- data/lib/simplecov/cli/status.rb +93 -0
- data/lib/simplecov/cli/tests/redundancy.rb +78 -0
- data/lib/simplecov/cli/tests.rb +148 -0
- data/lib/simplecov/cli/uncovered/misses.rb +37 -0
- data/lib/simplecov/cli/uncovered.rb +70 -32
- data/lib/simplecov/cli/usage.rb +152 -0
- data/lib/simplecov/cli/watch/live_report.rb +73 -0
- data/lib/simplecov/cli/watch/narrator.rb +55 -0
- data/lib/simplecov/cli/watch/poller.rb +45 -0
- data/lib/simplecov/cli/watch/session.rb +134 -0
- data/lib/simplecov/cli/watch/test_plan.rb +43 -0
- data/lib/simplecov/cli/watch.rb +85 -0
- data/lib/simplecov/cli.rb +43 -92
- data/lib/simplecov/color.rb +19 -37
- data/lib/simplecov/combine/branches_combiner.rb +7 -31
- data/lib/simplecov/combine/coverage_accumulator.rb +49 -142
- data/lib/simplecov/combine/identity_interner.rb +10 -13
- data/lib/simplecov/combine/interned_counts.rb +7 -9
- data/lib/simplecov/combine/lines_combiner.rb +20 -44
- data/lib/simplecov/combine/methods_combiner.rb +9 -35
- data/lib/simplecov/combine/results_combiner.rb +4 -21
- data/lib/simplecov/combine.rb +0 -6
- data/lib/simplecov/command_guesser.rb +20 -34
- data/lib/simplecov/configuration/baseline.rb +31 -0
- data/lib/simplecov/configuration/coverage.rb +91 -79
- data/lib/simplecov/configuration/coverage_criteria.rb +43 -54
- data/lib/simplecov/configuration/deprecations.rb +21 -0
- data/lib/simplecov/configuration/eval_coverage.rb +6 -10
- data/lib/simplecov/configuration/filters.rb +40 -73
- data/lib/simplecov/configuration/formatting.rb +74 -83
- data/lib/simplecov/configuration/groups.rb +19 -13
- data/lib/simplecov/configuration/history.rb +44 -0
- data/lib/simplecov/configuration/ignored_entries.rb +31 -22
- data/lib/simplecov/configuration/merging.rb +94 -62
- data/lib/simplecov/configuration/missed_caps.rb +51 -0
- data/lib/simplecov/configuration/production.rb +23 -0
- data/lib/simplecov/configuration/test_tracking.rb +48 -0
- data/lib/simplecov/configuration/thresholds.rb +33 -62
- data/lib/simplecov/configuration/view_coverage.rb +38 -0
- data/lib/simplecov/configuration.rb +70 -76
- data/lib/simplecov/configuration_error.rb +5 -0
- data/lib/simplecov/context_map/union.rb +81 -0
- data/lib/simplecov/context_map.rb +187 -0
- data/lib/simplecov/coverage_json.rb +2 -5
- data/lib/simplecov/coverage_statistics.rb +14 -24
- data/lib/simplecov/coverage_violations.rb +157 -64
- data/lib/simplecov/current_run.rb +61 -0
- data/lib/simplecov/defaults.rb +4 -23
- data/lib/simplecov/deprecation.rb +45 -27
- data/lib/simplecov/directive.rb +46 -62
- data/lib/simplecov/exit_codes/baseline_check.rb +46 -0
- data/lib/simplecov/exit_codes/check.rb +17 -11
- data/lib/simplecov/exit_codes/exit_code_handling.rb +21 -8
- data/lib/simplecov/exit_codes/maximum_coverage_drop_check.rb +7 -10
- data/lib/simplecov/exit_codes/maximum_missed_check.rb +26 -0
- data/lib/simplecov/exit_codes/maximum_missed_per_file_check.rb +34 -0
- data/lib/simplecov/exit_codes/maximum_overall_coverage_check.rb +7 -12
- data/lib/simplecov/exit_codes/minimum_coverage_by_file_check.rb +11 -10
- data/lib/simplecov/exit_codes/minimum_coverage_by_group_check.rb +7 -9
- data/lib/simplecov/exit_codes/minimum_overall_coverage_check.rb +16 -17
- data/lib/simplecov/exit_codes.rb +16 -10
- data/lib/simplecov/exit_handling.rb +94 -59
- data/lib/simplecov/file_list.rb +20 -51
- data/lib/simplecov/filter.rb +43 -66
- data/lib/simplecov/formatter/base.rb +37 -55
- data/lib/simplecov/formatter/baseline_formatter.rb +98 -0
- data/lib/simplecov/formatter/coverage_json_writer.rb +29 -31
- data/lib/simplecov/formatter/html_formatter/public/index.html +15 -9
- data/lib/simplecov/formatter/html_formatter/viewer_data_validator.rb +74 -17
- data/lib/simplecov/formatter/html_formatter.rb +24 -41
- data/lib/simplecov/formatter/json_formatter/errors_formatter.rb +50 -16
- data/lib/simplecov/formatter/json_formatter/production_section_formatter.rb +48 -0
- data/lib/simplecov/formatter/json_formatter/result_hash_formatter.rb +43 -29
- data/lib/simplecov/formatter/json_formatter/source_file_formatter.rb +14 -10
- data/lib/simplecov/formatter/json_formatter.rb +7 -13
- data/lib/simplecov/formatter/multi_formatter.rb +5 -11
- data/lib/simplecov/formatter/simple_formatter.rb +2 -8
- data/lib/simplecov/formatter.rb +14 -10
- data/lib/simplecov/group_names.rb +13 -12
- data/lib/simplecov/history.rb +115 -0
- data/lib/simplecov/last_run.rb +6 -9
- data/lib/simplecov/lines_classifier.rb +31 -16
- data/lib/simplecov/load_global_config.rb +7 -7
- data/lib/simplecov/parallel_adapters/base.rb +13 -41
- data/lib/simplecov/parallel_adapters/generic.rb +7 -19
- data/lib/simplecov/parallel_adapters/parallel_tests.rb +21 -42
- data/lib/simplecov/parallel_adapters.rb +24 -55
- data/lib/simplecov/parallel_coordination.rb +39 -49
- data/lib/simplecov/parallel_result_merger/worker_payload.rb +33 -0
- data/lib/simplecov/parallel_result_merger.rb +67 -126
- data/lib/simplecov/process.rb +14 -32
- data/lib/simplecov/production/error.rb +11 -0
- data/lib/simplecov/production/file_sink.rb +130 -0
- data/lib/simplecov/production.rb +249 -0
- data/lib/simplecov/profiles/rails.rb +1 -12
- data/lib/simplecov/profiles/root_filter.rb +0 -4
- data/lib/simplecov/profiles/strict.rb +9 -19
- data/lib/simplecov/profiles.rb +11 -33
- data/lib/simplecov/report_deferral.rb +11 -15
- data/lib/simplecov/report_stamp.rb +6 -9
- data/lib/simplecov/result/filter_config.rb +19 -0
- data/lib/simplecov/result/missing_source_files_reporter.rb +8 -9
- data/lib/simplecov/result/serialization.rb +43 -0
- data/lib/simplecov/result/source_file_builder.rb +7 -12
- data/lib/simplecov/result.rb +68 -117
- data/lib/simplecov/result_adapter.rb +56 -68
- data/lib/simplecov/result_merger/contexts.rb +22 -0
- data/lib/simplecov/result_merger/legacy_format_adapter.rb +4 -8
- data/lib/simplecov/result_merger/resultset_file.rb +20 -27
- data/lib/simplecov/result_merger/resultset_run_identity.rb +23 -25
- data/lib/simplecov/result_merger/resultset_store.rb +23 -14
- data/lib/simplecov/result_merger/unloaded_files.rb +24 -32
- data/lib/simplecov/result_merger.rb +59 -58
- data/lib/simplecov/result_processing.rb +74 -119
- data/lib/simplecov/run_identity.rb +16 -18
- data/lib/simplecov/simulate_coverage.rb +34 -50
- data/lib/simplecov/source_file/branch.rb +8 -33
- data/lib/simplecov/source_file/branch_builder.rb +28 -47
- data/lib/simplecov/source_file/builder_context.rb +6 -13
- data/lib/simplecov/source_file/line.rb +13 -33
- data/lib/simplecov/source_file/line_builder.rb +9 -15
- data/lib/simplecov/source_file/method.rb +3 -7
- data/lib/simplecov/source_file/method_builder.rb +6 -15
- data/lib/simplecov/source_file/ruby_data_parser.rb +59 -66
- data/lib/simplecov/source_file/skip_chunks.rb +19 -28
- data/lib/simplecov/source_file/source_loader.rb +45 -35
- data/lib/simplecov/source_file/statistics.rb +10 -9
- data/lib/simplecov/source_file.rb +21 -51
- data/lib/simplecov/static_coverage_extractor/condition_folding.rb +63 -114
- data/lib/simplecov/static_coverage_extractor/location_conventions.rb +76 -121
- data/lib/simplecov/static_coverage_extractor/method_collector.rb +11 -24
- data/lib/simplecov/static_coverage_extractor/prism_compat.rb +15 -24
- data/lib/simplecov/static_coverage_extractor/value_position.rb +25 -38
- data/lib/simplecov/static_coverage_extractor/visitor.rb +47 -64
- data/lib/simplecov/static_coverage_extractor.rb +46 -62
- data/lib/simplecov/test_tracker/accessors.rb +34 -0
- data/lib/simplecov/test_tracker/constant_watch.rb +49 -0
- data/lib/simplecov/test_tracker/delta.rb +69 -0
- data/lib/simplecov/test_tracker/framework_hooks.rb +130 -0
- data/lib/simplecov/test_tracker.rb +162 -0
- data/lib/simplecov/unloaded_file_injector.rb +18 -31
- data/lib/simplecov/useless_results_remover.rb +7 -6
- data/lib/simplecov/version.rb +1 -1
- data/lib/simplecov/view_coverage/template_compiler.rb +83 -0
- data/lib/simplecov/view_coverage.rb +55 -0
- data/lib/simplecov-html.rb +1 -0
- data/lib/simplecov.rb +57 -113
- data/lib/simplecov_json_formatter.rb +1 -0
- data/man/simplecov.1 +349 -0
- data/sig/simplecov.rbs +523 -595
- metadata +72 -5
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "optparse"
|
|
4
|
+
require_relative "command_helpers"
|
|
5
|
+
require_relative "open"
|
|
6
|
+
require_relative "serve"
|
|
7
|
+
require_relative "affected"
|
|
8
|
+
require_relative "watch/poller"
|
|
9
|
+
require_relative "watch/live_report"
|
|
10
|
+
require_relative "watch/narrator"
|
|
11
|
+
require_relative "watch/test_plan"
|
|
12
|
+
require_relative "watch/session"
|
|
13
|
+
|
|
14
|
+
module SimpleCov
|
|
15
|
+
module CLI
|
|
16
|
+
# `simplecov watch <command...>`: the coverage inner loop. Serves the report
|
|
17
|
+
# the way `serve` does, polls the tracked files for saves, re-runs the given
|
|
18
|
+
# command on change, and pushes a reload to the open tab over server-sent
|
|
19
|
+
# events when the report regenerates. With a `track_tests` recording in the
|
|
20
|
+
# report, a save re-runs only the tests that touch the changed files, by the
|
|
21
|
+
# same selection walk `simplecov affected` uses.
|
|
22
|
+
module Watch
|
|
23
|
+
extend CommandHelpers
|
|
24
|
+
|
|
25
|
+
extend self
|
|
26
|
+
|
|
27
|
+
def run(args, stdout:, stderr:, **)
|
|
28
|
+
opts, command = parse(args)
|
|
29
|
+
return error(stderr, "missing command to run (e.g. `simplecov watch bundle exec rspec`)") if command.empty?
|
|
30
|
+
|
|
31
|
+
Serve.require_socket
|
|
32
|
+
server = bind(opts, stderr)
|
|
33
|
+
return 1 unless server
|
|
34
|
+
|
|
35
|
+
serve_session(server, command, opts, stdout, stderr)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def serve_session(server, command, opts, stdout, stderr)
|
|
39
|
+
launch_browser(server, stderr) if opts.fetch(:open)
|
|
40
|
+
session_for(command, opts, stdout, stderr).run(server)
|
|
41
|
+
ensure
|
|
42
|
+
server.close
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Fire-and-forget through the same platform opener `simplecov open` uses,
|
|
46
|
+
# detached so the session never waits on a browser. A platform with no known
|
|
47
|
+
# opener notes the URL instead of failing the watch.
|
|
48
|
+
def launch_browser(server, stderr)
|
|
49
|
+
url = "http://#{Serve.url_host(server.addr.fetch(3))}:#{server.addr.fetch(1)}/"
|
|
50
|
+
opener = Open.browser_opener
|
|
51
|
+
unless opener
|
|
52
|
+
return stderr.puts("simplecov watch: no known browser opener for this platform, open it yourself: #{url}")
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
Process.detach(spawn(*opener, url, out: File::NULL, err: File::NULL))
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# `order` rather than `parse` stops at the first positional, so the runner
|
|
59
|
+
# command keeps its own flags: `simplecov watch bundle exec rspec --seed 1`
|
|
60
|
+
# passes --seed through untouched.
|
|
61
|
+
def parse(args)
|
|
62
|
+
opts = {port: 0, host: "127.0.0.1", interval: 0.5, open: false} #: Hash[Symbol, untyped]
|
|
63
|
+
rest =
|
|
64
|
+
build_parser do |parser|
|
|
65
|
+
parser.on("--port N", Integer) { |v| opts[:port] = v }
|
|
66
|
+
parser.on("--host HOST") { |v| opts[:host] = v }
|
|
67
|
+
parser.on("--interval SECONDS", Float) { |v| opts[:interval] = v }
|
|
68
|
+
parser.on("--open") { opts[:open] = true }
|
|
69
|
+
end.order(args)
|
|
70
|
+
[opts, rest]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def bind(opts, stderr)
|
|
74
|
+
(_ = TCPServer).new(opts.fetch(:host), opts.fetch(:port)) #: TCPServer
|
|
75
|
+
rescue SystemCallError, SocketError => e
|
|
76
|
+
error_nil(stderr, "cannot bind to #{opts.fetch(:host)}:#{opts.fetch(:port)} (#{e})")
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def session_for(command, opts, stdout, stderr)
|
|
80
|
+
Session.new(command: command, dir: CLI.coverage_dir,
|
|
81
|
+
interval: opts.fetch(:interval), stdout: stdout, stderr: stderr)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
data/lib/simplecov/cli.rb
CHANGED
|
@@ -1,50 +1,67 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "optparse"
|
|
4
|
+
require_relative "version"
|
|
4
5
|
require_relative "color"
|
|
5
6
|
require_relative "cli/dotfile"
|
|
7
|
+
require_relative "cli/badge"
|
|
6
8
|
require_relative "cli/clean"
|
|
9
|
+
require_relative "cli/completions"
|
|
7
10
|
require_relative "cli/coverage_file"
|
|
8
11
|
require_relative "cli/coverage"
|
|
12
|
+
require_relative "cli/dead_code"
|
|
9
13
|
require_relative "cli/diff"
|
|
14
|
+
require_relative "cli/history"
|
|
10
15
|
require_relative "cli/merge"
|
|
11
16
|
require_relative "cli/open"
|
|
17
|
+
require_relative "cli/patch"
|
|
18
|
+
require_relative "cli/ratchet"
|
|
12
19
|
require_relative "cli/report"
|
|
13
20
|
require_relative "cli/run"
|
|
14
21
|
require_relative "cli/serve"
|
|
22
|
+
require_relative "cli/show"
|
|
23
|
+
require_relative "cli/status"
|
|
24
|
+
require_relative "cli/tests"
|
|
25
|
+
require_relative "cli/affected"
|
|
15
26
|
require_relative "cli/uncovered"
|
|
27
|
+
require_relative "cli/usage"
|
|
28
|
+
require_relative "cli/watch"
|
|
16
29
|
|
|
17
30
|
module SimpleCov
|
|
18
|
-
# Lightweight command-line front-end.
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
# which the bundled HTMLFormatter already drops alongside the HTML, so
|
|
24
|
-
# no runtime hooking is needed for those. Default paths follow the
|
|
25
|
-
# project's `.simplecov` `SimpleCov.coverage_dir` setting when one is
|
|
26
|
-
# present, so a project that writes its report somewhere other than
|
|
27
|
-
# `coverage/` doesn't have to pass `--input` / `--report` every
|
|
28
|
-
# invocation.
|
|
31
|
+
# Lightweight command-line front-end. Read-only subcommands consume
|
|
32
|
+
# JSONFormatter output, which the bundled HTMLFormatter already drops
|
|
33
|
+
# alongside the HTML, so no runtime hooking is needed for those. Default
|
|
34
|
+
# paths follow the project's `.simplecov` `coverage_dir` setting when one is
|
|
35
|
+
# present.
|
|
29
36
|
module CLI
|
|
30
37
|
COMMANDS = {
|
|
31
38
|
"coverage" => Coverage,
|
|
39
|
+
"show" => Show,
|
|
32
40
|
"run" => Run,
|
|
33
41
|
"open" => Open,
|
|
34
42
|
"report" => Report,
|
|
43
|
+
"status" => Status,
|
|
44
|
+
"history" => History,
|
|
35
45
|
"uncovered" => Uncovered,
|
|
46
|
+
"tests" => Tests,
|
|
47
|
+
"affected" => Affected,
|
|
36
48
|
"merge" => Merge,
|
|
37
49
|
"diff" => Diff,
|
|
50
|
+
"patch" => Patch,
|
|
51
|
+
"ratchet" => Ratchet,
|
|
52
|
+
"dead-code" => DeadCode,
|
|
38
53
|
"serve" => Serve,
|
|
39
|
-
"
|
|
54
|
+
"watch" => Watch,
|
|
55
|
+
"badge" => Badge,
|
|
56
|
+
"clean" => Clean,
|
|
57
|
+
"completions" => Completions
|
|
40
58
|
}.freeze
|
|
41
59
|
|
|
42
|
-
|
|
60
|
+
extend self
|
|
43
61
|
|
|
44
|
-
# Resolved once per process
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
# or an at_exit hook just because we asked it for a config value.
|
|
62
|
+
# Resolved once per process, by walking up from cwd for a `.simplecov` and
|
|
63
|
+
# loading it with `SimpleCov.start` neutered so it can't trigger tracking
|
|
64
|
+
# just because we asked it for a config value.
|
|
48
65
|
def coverage_dir
|
|
49
66
|
@coverage_dir ||= Dotfile.coverage_dir
|
|
50
67
|
end
|
|
@@ -53,14 +70,10 @@ module SimpleCov
|
|
|
53
70
|
File.join(coverage_dir, "coverage.json")
|
|
54
71
|
end
|
|
55
72
|
|
|
56
|
-
# Resolve "should this subcommand colorize?" once per invocation.
|
|
57
|
-
# `--no-color` (opts[:no_color]) is the per-invocation kill-switch;
|
|
58
|
-
# otherwise we defer to `SimpleCov::Color.enabled?`, which honors
|
|
59
|
-
# `NO_COLOR` / `FORCE_COLOR` and falls back to `stream.tty?`.
|
|
60
73
|
def color_enabled?(opts, stream)
|
|
61
74
|
return false if opts[:no_color]
|
|
62
75
|
|
|
63
|
-
|
|
76
|
+
Color.enabled?(stream)
|
|
64
77
|
end
|
|
65
78
|
|
|
66
79
|
def default_report
|
|
@@ -71,93 +84,31 @@ module SimpleCov
|
|
|
71
84
|
File.join(coverage_dir, ".resultset.json")
|
|
72
85
|
end
|
|
73
86
|
|
|
74
|
-
# Returns a process exit status (0 on success, non-zero on error).
|
|
75
87
|
def run(argv, stdout: $stdout, stderr: $stderr)
|
|
76
88
|
command, *rest = argv
|
|
77
89
|
handler = COMMANDS[command]
|
|
78
90
|
return dispatch(handler, command, rest, stdout: stdout, stderr: stderr) if handler
|
|
79
91
|
return stdout.puts(usage) || 0 if [nil, "help", "--help", "-h"].include?(command)
|
|
92
|
+
return stdout.puts("simplecov #{VERSION}") || 0 if %w[version --version -v].include?(command)
|
|
80
93
|
|
|
81
94
|
stderr.puts("simplecov: unknown command #{command.inspect}", usage)
|
|
82
95
|
1
|
|
83
96
|
end
|
|
84
97
|
|
|
85
|
-
# One rescue covers every subcommand's OptionParser, so a typo'd
|
|
86
|
-
#
|
|
87
|
-
# exit status 1 instead of an unhandled-exception backtrace.
|
|
98
|
+
# One rescue covers every subcommand's OptionParser, so a typo'd flag becomes
|
|
99
|
+
# a one-line error and exit status 1 instead of a backtrace.
|
|
88
100
|
def dispatch(handler, command, rest, stdout:, stderr:)
|
|
89
101
|
handler.run(rest, stdout: stdout, stderr: stderr)
|
|
102
|
+
rescue CommandHelpers::HelpRequested
|
|
103
|
+
stdout.puts(Usage.for(self, command))
|
|
104
|
+
0
|
|
90
105
|
rescue OptionParser::ParseError => e
|
|
91
|
-
stderr.puts("simplecov #{command}: #{e
|
|
106
|
+
stderr.puts("simplecov #{command}: #{e} (run `simplecov help` for usage)")
|
|
92
107
|
1
|
|
93
108
|
end
|
|
94
109
|
|
|
95
110
|
def usage
|
|
96
|
-
|
|
97
|
-
Usage: simplecov <command> [options]
|
|
98
|
-
|
|
99
|
-
Commands:
|
|
100
|
-
run <command...> Execute <command> with simplecov pre-loaded
|
|
101
|
-
(so a coverage report is generated even
|
|
102
|
-
when the project has no test_helper hook)
|
|
103
|
-
coverage <path> Print coverage stats for the given file
|
|
104
|
-
report Print the overall summary and group totals
|
|
105
|
-
uncovered List the lowest-coverage files
|
|
106
|
-
merge <files...> Merge multiple .resultset.json files
|
|
107
|
-
diff <baseline> Show per-file coverage delta vs baseline
|
|
108
|
-
open Open the HTML report in the default browser
|
|
109
|
-
serve Serve the coverage report over HTTP
|
|
110
|
-
clean Remove the coverage report directory
|
|
111
|
-
help Show this message
|
|
112
|
-
|
|
113
|
-
Default paths follow SimpleCov.coverage_dir from a project's
|
|
114
|
-
`.simplecov` when one is present (#{coverage_dir} for this run).
|
|
115
|
-
|
|
116
|
-
coverage / report / uncovered / diff options:
|
|
117
|
-
--input PATH Read from PATH instead of #{default_input}
|
|
118
|
-
--no-color Disable colorized percentages
|
|
119
|
-
(also honors NO_COLOR / FORCE_COLOR env)
|
|
120
|
-
|
|
121
|
-
coverage options:
|
|
122
|
-
--json Print the file's JSON entry verbatim
|
|
123
|
-
|
|
124
|
-
report options:
|
|
125
|
-
--json Emit totals and group sections as JSON
|
|
126
|
-
|
|
127
|
-
uncovered options:
|
|
128
|
-
--threshold N Only show files below N% coverage
|
|
129
|
-
--top N Show at most N files (default: 10)
|
|
130
|
-
--criterion C line, branch, or method (default: line)
|
|
131
|
-
--json Emit results as a JSON array (for CI)
|
|
132
|
-
|
|
133
|
-
merge options:
|
|
134
|
-
--output PATH Write merged resultset to PATH
|
|
135
|
-
(default: #{default_resultset})
|
|
136
|
-
--honor-timeout Drop entries older than merge_timeout
|
|
137
|
-
--dry-run Print what would be written without
|
|
138
|
-
actually writing
|
|
139
|
-
-q, --quiet Suppress the success status line
|
|
140
|
-
|
|
141
|
-
diff options:
|
|
142
|
-
--fail-on-drop Exit non-zero when any file's coverage
|
|
143
|
-
dropped vs the baseline (deleted
|
|
144
|
-
files don't count as drops)
|
|
145
|
-
--json Emit results as a JSON array (for CI)
|
|
146
|
-
--threshold N Only show files whose absolute delta
|
|
147
|
-
in any criterion is at least N%
|
|
148
|
-
|
|
149
|
-
open options:
|
|
150
|
-
--report PATH Open PATH instead of #{default_report}
|
|
151
|
-
|
|
152
|
-
serve options:
|
|
153
|
-
--port N Bind to port N (default: random open port)
|
|
154
|
-
--host HOST Bind to HOST (default: 127.0.0.1)
|
|
155
|
-
|
|
156
|
-
clean options:
|
|
157
|
-
--dry-run Print what would be removed without
|
|
158
|
-
deleting anything
|
|
159
|
-
-q, --quiet Suppress status lines
|
|
160
|
-
USAGE
|
|
111
|
+
Usage.text(self)
|
|
161
112
|
end
|
|
162
113
|
end
|
|
163
114
|
end
|
data/lib/simplecov/color.rb
CHANGED
|
@@ -1,22 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module SimpleCov
|
|
4
|
-
# ANSI colorization for stderr diagnostics. Thresholds mirror the
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# they're reading the terminal output or the HTML report.
|
|
8
|
-
#
|
|
9
|
-
# Color precedence, highest first:
|
|
10
|
-
#
|
|
11
|
-
# - `SimpleCov.color = true` / `false` (programmatic override, wins
|
|
12
|
-
# over everything; default is `:auto` which falls through)
|
|
13
|
-
# - `NO_COLOR` env var (any non-empty value) → off (see no-color.org)
|
|
14
|
-
# - `FORCE_COLOR` env var (any non-empty value) → on
|
|
15
|
-
# - `stream.tty?` fallback
|
|
16
|
-
#
|
|
17
|
-
# `NO_COLOR` wins over `FORCE_COLOR` if both env vars are set.
|
|
4
|
+
# ANSI colorization for stderr diagnostics. Thresholds mirror the HTML
|
|
5
|
+
# formatter so a team's mental model of "what's the cutoff" is the same in
|
|
6
|
+
# the terminal and in the report.
|
|
18
7
|
module Color
|
|
19
|
-
GREEN_THRESHOLD
|
|
8
|
+
GREEN_THRESHOLD = 90
|
|
20
9
|
YELLOW_THRESHOLD = 75
|
|
21
10
|
|
|
22
11
|
ANSI = {
|
|
@@ -26,51 +15,44 @@ module SimpleCov
|
|
|
26
15
|
reset: "\e[0m"
|
|
27
16
|
}.freeze
|
|
28
17
|
|
|
29
|
-
|
|
18
|
+
extend self
|
|
30
19
|
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
20
|
+
# Precedence, highest first: an explicit `SimpleCov.color` true/false (the
|
|
21
|
+
# default `:auto` falls through), then `NO_COLOR`, then `FORCE_COLOR`, then
|
|
22
|
+
# `stream.tty?`. `NO_COLOR` wins over `FORCE_COLOR` when both are set.
|
|
23
|
+
#
|
|
24
|
+
# `stream` is the IO the colorized text is destined for. CLI subcommands
|
|
25
|
+
# that print to stdout should pass `$stdout` so a redirected pipe doesn't
|
|
26
|
+
# get ANSI sequences.
|
|
27
|
+
#
|
|
28
|
+
# `SimpleCov.color` only exists once the full library is loaded, and the
|
|
29
|
+
# standalone CLI loads this file without it, so a missing config reads as
|
|
30
|
+
# its `:auto` default. A parallel runner can also close a worker's stdio
|
|
31
|
+
# before its at_exit hooks run, and a closed stream is not a tty.
|
|
36
32
|
def enabled?(stream = $stderr)
|
|
37
|
-
# `SimpleCov.color` only exists once the full library is loaded.
|
|
38
|
-
# The standalone CLI (`exe/simplecov`) loads `simplecov/color`
|
|
39
|
-
# without `simplecov` itself to stay lightweight, so treat a
|
|
40
|
-
# missing config the same as its `:auto` default: fall through to
|
|
41
|
-
# the env vars and tty check below.
|
|
42
33
|
config = SimpleCov.color if SimpleCov.respond_to?(:color)
|
|
43
34
|
return config if [true, false].include?(config)
|
|
44
35
|
return false if env_set?("NO_COLOR")
|
|
45
|
-
return true
|
|
36
|
+
return true if env_set?("FORCE_COLOR")
|
|
46
37
|
|
|
47
38
|
stream.tty?
|
|
48
39
|
rescue IOError
|
|
49
|
-
# A parallel runner can close a worker's stdio before its at_exit
|
|
50
|
-
# hooks run (rspec-conductor does). A closed stream is not a tty.
|
|
51
40
|
false
|
|
52
41
|
end
|
|
53
42
|
|
|
54
43
|
def for_percent(percent)
|
|
55
|
-
return :green
|
|
44
|
+
return :green if percent >= GREEN_THRESHOLD
|
|
56
45
|
return :yellow if percent >= YELLOW_THRESHOLD
|
|
57
46
|
|
|
58
47
|
:red
|
|
59
48
|
end
|
|
60
49
|
|
|
61
|
-
# Wrap `text` in the ANSI sequence for `color` (a key of ANSI).
|
|
62
|
-
# Returns the bare text if color is disabled. The `enabled:`
|
|
63
|
-
# keyword lets callers (e.g., CLI subcommands honoring `--no-color`)
|
|
64
|
-
# override the auto-detection without touching env vars.
|
|
65
50
|
def colorize(text, color, enabled: enabled?)
|
|
66
51
|
return text unless enabled
|
|
67
52
|
|
|
68
53
|
"#{ANSI.fetch(color)}#{text}#{ANSI.fetch(:reset)}"
|
|
69
54
|
end
|
|
70
55
|
|
|
71
|
-
# Render `percent` as a fixed "NN.NN%" string colored by which
|
|
72
|
-
# threshold band it falls into. Callers that want a different
|
|
73
|
-
# rendering of the number can pass the pre-rendered `text`.
|
|
74
56
|
def colorize_percent(percent, text = nil, enabled: enabled?)
|
|
75
57
|
colorize(text || format("%.2f%%", percent), for_percent(percent), enabled: enabled)
|
|
76
58
|
end
|
|
@@ -6,49 +6,29 @@ require_relative "interned_counts"
|
|
|
6
6
|
|
|
7
7
|
module SimpleCov
|
|
8
8
|
module Combine
|
|
9
|
-
#
|
|
10
|
-
# Combine different branch coverage results on single file.
|
|
11
|
-
#
|
|
12
|
-
# Should be called through `CoverageAccumulator`.
|
|
13
9
|
module BranchesCombiner
|
|
14
|
-
|
|
10
|
+
extend self
|
|
15
11
|
|
|
16
|
-
#
|
|
17
|
-
# Return merged branches or the existed branch if other is missing.
|
|
18
|
-
#
|
|
19
|
-
# Branches inside files are always same if they exist, the difference only in coverage count.
|
|
20
|
-
# Branch coverage report for any conditional case is built from hash, it's key is a condition and
|
|
21
|
-
# it's body is a hash << keys from condition and value is coverage rate >>.
|
|
22
|
-
# ex: branches => { [:if, 3, 8, 6, 8, 36] =>
|
|
23
|
-
# {[:then, 4, 8, 6, 8, 12] => 1, [:else, 5, 8, 6, 8, 36] => 2}, ... }
|
|
24
|
-
# We create copy of result and update it values depending on the combined branches coverage values.
|
|
25
|
-
#
|
|
26
|
-
# @return [Hash]
|
|
27
|
-
#
|
|
28
12
|
def combine(coverage_a, coverage_b)
|
|
29
13
|
merged = absorb({}, coverage_a) #: Hash[untyped, [untyped, Hash[untyped, untyped]]]
|
|
30
14
|
materialize(absorb(merged, coverage_b))
|
|
31
15
|
end
|
|
32
16
|
|
|
33
17
|
# Folds `coverage` into `target`, an interned table keyed by condition
|
|
34
|
-
# identity. Kept interned
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
# @return [Hash] `target`
|
|
18
|
+
# identity. Kept interned rather than turned back into tuple keys per merge,
|
|
19
|
+
# so a fold over N resultsets interns each condition once instead of
|
|
20
|
+
# re-interning the whole accumulated table N times.
|
|
39
21
|
def absorb(target, coverage)
|
|
40
22
|
return target unless coverage
|
|
41
23
|
|
|
42
24
|
coverage.each do |condition, branches_inside|
|
|
43
25
|
entry = target[identities[condition]] ||= new_condition(condition)
|
|
44
|
-
InternedCounts.absorb_counts(entry
|
|
26
|
+
InternedCounts.absorb_counts(entry.fetch(1), branches_inside, identities)
|
|
45
27
|
end
|
|
46
28
|
|
|
47
29
|
target
|
|
48
30
|
end
|
|
49
31
|
|
|
50
|
-
# Split out so the empty arm table has somewhere to carry its type
|
|
51
|
-
# annotation. Only allocated the first time a condition is seen.
|
|
52
32
|
def new_condition(condition)
|
|
53
33
|
arms = {} #: Hash[untyped, untyped]
|
|
54
34
|
[condition, arms]
|
|
@@ -56,20 +36,16 @@ module SimpleCov
|
|
|
56
36
|
|
|
57
37
|
# Turns an interned table back into the tuple-keyed hash the rest of
|
|
58
38
|
# SimpleCov reads. Done once, at the end of a fold.
|
|
59
|
-
#
|
|
60
|
-
# @return [Hash]
|
|
61
39
|
def materialize(target)
|
|
62
40
|
target.values.to_h { |condition, branches| [condition, branches.values.to_h] }
|
|
63
41
|
end
|
|
64
42
|
|
|
65
|
-
# Bounded by the project's branch count, like `RubyDataParser`'s parse
|
|
66
|
-
# cache.
|
|
67
43
|
def identities
|
|
68
44
|
@identities ||= IdentityInterner.build { |tuple| tuple_identity(tuple) }
|
|
69
45
|
end
|
|
70
46
|
|
|
71
|
-
# Branches match on source span, whatever ids the recording processes
|
|
72
|
-
#
|
|
47
|
+
# Branches match on source span, whatever ids the recording processes handed
|
|
48
|
+
# them (#1233).
|
|
73
49
|
def tuple_identity(tuple)
|
|
74
50
|
type, _id, start_line, start_column, end_line, end_column = SourceFile::RubyDataParser.call(tuple)
|
|
75
51
|
[type, start_line, start_column, end_line, end_column].freeze
|