Module: Kettle::Soup::Cover
- Extended by:
- Loaders
- Includes:
- Constants
- Defined in:
- lib/kettle/soup/cover.rb,
lib/kettle/soup/cover/loaders.rb,
lib/kettle/soup/cover/version.rb,
lib/kettle/soup/cover/constants.rb,
lib/kettle/soup/cover/formatters.rb,
lib/kettle/soup/cover/coverage_thresholds.rb,
lib/kettle/soup/cover/filters/gt_line_filter.rb,
lib/kettle/soup/cover/filters/lt_line_filter.rb
Defined Under Namespace
Modules: Constants, CoverageThresholds, Filters, Loaders, Version
Classes: Error
Constant Summary
collapse
- VAR_HOME_PREFIX =
%r{\A/var/home(?=/|\z)}
- VERSION =
Current gem version exposed at the traditional constant location.
Version::VERSION
Constants included
from Constants
Constants::CI, Constants::CLEAN_RESULTSET, Constants::CLEAN_RESULTSET_DEFAULT, Constants::COMMAND_NAME, Constants::COVERAGE_DIR, Constants::COVERAGE_ROOT_DIR, Constants::DEBUG, Constants::DO_COV, Constants::ENV_GET, Constants::FALSE, Constants::FILTER_DIRS, Constants::FORMATTERS, Constants::FORMATTER_PLUGINS, Constants::IS_CI, Constants::MERGE_TIMEOUT, Constants::MIN_COVERAGE_BRANCH, Constants::MIN_COVERAGE_HARD, Constants::MIN_COVERAGE_HARD_REQUESTED, Constants::MIN_COVERAGE_LINE, Constants::MIN_COVERAGE_STRICT, Constants::MULTI_FORMATTERS, Constants::MULTI_FORMATTERS_DEFAULT, Constants::OPEN_BIN, Constants::PREFIX, Constants::QUIET_COLLATION, Constants::SIMPLECOV_COMMAND_NAME, Constants::TEST_ENV_NUMBER, Constants::TRUE, Constants::TURBO_TESTS, Constants::TURBO_TESTS_DIR, Constants::TURBO_TESTS_WORKER, Constants::USE_MERGING, Constants::VERBOSE, Constants::WASHED_CONSTANTS
Class Method Summary
collapse
-
.clean_resultset! ⇒ Object
Deletes coverage/.resultset.json (if it exists) so that stale entries from prior runs cannot pollute the current run’s coverage report.
-
.clear_coverage_dir!(coverage_dir = Constants::COVERAGE_DIR, project_root: Dir.pwd) ⇒ Object
-
.clear_turbo_tests_coverage_dir!(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd) ⇒ Object
-
.collate_turbo_tests_coverage!(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd) ⇒ Object
-
.configure_formatters! ⇒ Object
-
.coverage_task_env(coverage_dir = Constants::COVERAGE_DIR, project_root: Dir.pwd) ⇒ Object
-
.display_path(path) ⇒ Object
-
.mark_turbo_tests_collated!(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd) ⇒ Object
-
.merge_branch_coverage(left, right) ⇒ Object
-
.merge_branch_entry(left, right) ⇒ Object
-
.merge_coverage_value(left, right) ⇒ Object
-
.merge_json_coverage!(target, source) ⇒ Object
-
.merge_line_coverage(left, right) ⇒ Object
-
.publish_turbo_tests_json_coverage!(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd) ⇒ Object
-
.quiet_collation_formatter_line?(line) ⇒ Boolean
-
.refresh_coverage_data!(coverage_dir = Constants::COVERAGE_DIR, project_root: Dir.pwd, out: $stdout, err: $stderr) ⇒ Object
-
.replay_quiet_collation_output(output, io) ⇒ Object
-
.turbo_tests_collated?(resultsets, coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd) ⇒ Boolean
-
.turbo_tests_collation_marker_path(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd) ⇒ Object
-
.turbo_tests_coverage? ⇒ Boolean
-
.turbo_tests_coverage_dir(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd) ⇒ Object
-
.turbo_tests_json_paths(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd) ⇒ Object
-
.turbo_tests_resultset_paths(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd) ⇒ Object
-
.with_quiet_collation_output ⇒ Object
Methods included from Loaders
install_tasks, load_filters, load_formatters
Class Method Details
.clean_resultset! ⇒ Object
Deletes coverage/.resultset.json (if it exists) so that stale entries
from prior runs cannot pollute the current run’s coverage report.
Called automatically from config.rb when CLEAN_RESULTSET is true.
57
58
59
60
|
# File 'lib/kettle/soup/cover.rb', line 57
def clean_resultset!
resultset_path = SimpleCov::ResultMerger.resultset_path
File.delete(resultset_path) if File.exist?(resultset_path)
end
|
.clear_coverage_dir!(coverage_dir = Constants::COVERAGE_DIR, project_root: Dir.pwd) ⇒ Object
62
63
64
|
# File 'lib/kettle/soup/cover.rb', line 62
def clear_coverage_dir!(coverage_dir = Constants::COVERAGE_DIR, project_root: Dir.pwd)
FileUtils.rm_rf(File.expand_path(coverage_dir, project_root))
end
|
.clear_turbo_tests_coverage_dir!(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd) ⇒ Object
74
75
76
|
# File 'lib/kettle/soup/cover.rb', line 74
def clear_turbo_tests_coverage_dir!(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd)
FileUtils.rm_rf(turbo_tests_coverage_dir(coverage_dir, project_root: project_root))
end
|
.collate_turbo_tests_coverage!(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd) ⇒ Object
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
# File 'lib/kettle/soup/cover.rb', line 90
def collate_turbo_tests_coverage!(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd)
return :disabled unless turbo_tests_coverage?
resultsets = turbo_tests_resultset_paths(coverage_dir, project_root: project_root)
return :empty if resultsets.empty?
return :already_collated if turbo_tests_collated?(resultsets, coverage_dir, project_root: project_root)
require "simplecov"
with_quiet_collation_output do
SimpleCov.collate(resultsets) do
command_name("#{Constants::COMMAND_NAME} (turbo_tests2)")
enable_coverage(:branch)
primary_coverage(:branch)
skip(Constants::FILTER_DIRS)
coverage_dir(File.expand_path(coverage_dir, project_root))
Kettle::Soup::Cover.configure_formatters!
Kettle::Soup::Cover::CoverageThresholds.configure!(self)
end
end
SimpleCov.external_at_exit = true if SimpleCov.respond_to?(:external_at_exit=)
publish_turbo_tests_json_coverage!(coverage_dir, project_root: project_root)
mark_turbo_tests_collated!(coverage_dir, project_root: project_root)
:collated
end
|
.coverage_task_env(coverage_dir = Constants::COVERAGE_DIR, project_root: Dir.pwd) ⇒ Object
.display_path(path) ⇒ Object
48
49
50
51
52
|
# File 'lib/kettle/soup/cover.rb', line 48
def display_path(path)
return path if path.nil?
path.to_s.sub(VAR_HOME_PREFIX, "/home")
end
|
.mark_turbo_tests_collated!(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd) ⇒ Object
128
129
130
131
132
|
# File 'lib/kettle/soup/cover.rb', line 128
def mark_turbo_tests_collated!(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd)
marker_path = turbo_tests_collation_marker_path(coverage_dir, project_root: project_root)
FileUtils.mkdir_p(File.dirname(marker_path))
FileUtils.touch(marker_path)
end
|
.merge_branch_coverage(left, right) ⇒ Object
168
169
170
171
|
# File 'lib/kettle/soup/cover.rb', line 168
def merge_branch_coverage(left, right)
length = [left.length, right.length].max
Array.new(length) { |index| merge_branch_entry(left[index], right[index]) }.compact
end
|
.merge_branch_entry(left, right) ⇒ Object
173
174
175
176
177
178
179
180
181
|
# File 'lib/kettle/soup/cover.rb', line 173
def merge_branch_entry(left, right)
return right unless left
return left unless right
return left unless left.is_a?(Hash) && right.is_a?(Hash)
left.merge(right) do |key, left_value, right_value|
(key == "coverage") ? merge_coverage_value(left_value, right_value) : left_value
end
end
|
.merge_coverage_value(left, right) ⇒ Object
183
184
185
186
187
188
189
190
|
# File 'lib/kettle/soup/cover.rb', line 183
def merge_coverage_value(left, right)
return left + right if left.is_a?(Integer) && right.is_a?(Integer)
return left if left.is_a?(Integer)
return right if right.is_a?(Integer)
return left if left
right
end
|
.merge_json_coverage!(target, source) ⇒ Object
154
155
156
157
158
159
160
161
|
# File 'lib/kettle/soup/cover.rb', line 154
def merge_json_coverage!(target, source)
source.each do |path, coverage|
target[path] ||= {"lines" => [], "branches" => []}
target[path]["lines"] = merge_line_coverage(target[path]["lines"], coverage["lines"] || [])
target[path]["branches"] = merge_branch_coverage(target[path]["branches"] || [], coverage["branches"] || [])
end
target
end
|
.merge_line_coverage(left, right) ⇒ Object
163
164
165
166
|
# File 'lib/kettle/soup/cover.rb', line 163
def merge_line_coverage(left, right)
length = [left.length, right.length].max
Array.new(length) { |index| merge_coverage_value(left[index], right[index]) }
end
|
.publish_turbo_tests_json_coverage!(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd) ⇒ Object
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
# File 'lib/kettle/soup/cover.rb', line 134
def publish_turbo_tests_json_coverage!(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd)
paths = turbo_tests_json_paths(coverage_dir, project_root: project_root)
return :empty if paths.empty?
merged = {
"meta" => {},
"coverage" => {}
}
paths.sort_by { |path| File.basename(File.dirname(path)).to_i }.each do |path|
data = JSON.parse(File.read(path))
merged["meta"].merge!(data["meta"]) if data["meta"].is_a?(Hash)
merge_json_coverage!(merged["coverage"], data["coverage"] || {})
end
output_path = File.expand_path(File.join(coverage_dir, "coverage.json"), project_root)
FileUtils.mkdir_p(File.dirname(output_path))
File.write(output_path, JSON.pretty_generate(merged))
:published
end
|
218
219
220
221
222
223
224
225
|
# File 'lib/kettle/soup/cover.rb', line 218
def quiet_collation_formatter_line?(line)
stripped = line.strip
return true if stripped.empty?
return true if stripped.match?(/coverage report generated/i)
return true if stripped.match?(/\A(?:Line|Branch) coverage:/i)
false
end
|
.refresh_coverage_data!(coverage_dir = Constants::COVERAGE_DIR, project_root: Dir.pwd, out: $stdout, err: $stderr) ⇒ Object
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
|
# File 'lib/kettle/soup/cover.rb', line 241
def refresh_coverage_data!(coverage_dir = Constants::COVERAGE_DIR, project_root: Dir.pwd, out: $stdout, err: $stderr)
clear_coverage_dir!(coverage_dir, project_root: project_root)
coverage_task = File.expand_path("bin/rake", project_root)
success = system(
coverage_task_env(coverage_dir, project_root: project_root),
coverage_task,
"coverage",
chdir: project_root,
out: out,
err: err
)
return if success
raise Error, "Coverage refresh failed: #{coverage_task} coverage"
end
|
.replay_quiet_collation_output(output, io) ⇒ Object
212
213
214
215
216
|
# File 'lib/kettle/soup/cover.rb', line 212
def replay_quiet_collation_output(output, io)
output.each_line do |line|
io.print(line) unless quiet_collation_formatter_line?(line)
end
end
|
.turbo_tests_collated?(resultsets, coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd) ⇒ Boolean
120
121
122
123
124
125
126
|
# File 'lib/kettle/soup/cover.rb', line 120
def turbo_tests_collated?(resultsets, coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd)
marker_path = turbo_tests_collation_marker_path(coverage_dir, project_root: project_root)
return false unless File.file?(marker_path)
marker_mtime = File.mtime(marker_path)
resultsets.all? { |path| File.file?(path) && File.mtime(path) <= marker_mtime }
end
|
.turbo_tests_collation_marker_path(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd) ⇒ Object
86
87
88
|
# File 'lib/kettle/soup/cover.rb', line 86
def turbo_tests_collation_marker_path(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd)
File.expand_path(File.join(coverage_dir, ".turbo_tests_collated"), project_root)
end
|
.turbo_tests_coverage? ⇒ Boolean
.turbo_tests_coverage_dir(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd) ⇒ Object
.turbo_tests_json_paths(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd) ⇒ Object
82
83
84
|
# File 'lib/kettle/soup/cover.rb', line 82
def turbo_tests_json_paths(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd)
Dir[File.join(turbo_tests_coverage_dir(coverage_dir, project_root: project_root), "*", "coverage.json")]
end
|
.turbo_tests_resultset_paths(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd) ⇒ Object
78
79
80
|
# File 'lib/kettle/soup/cover.rb', line 78
def turbo_tests_resultset_paths(coverage_dir = Constants::COVERAGE_ROOT_DIR, project_root: Dir.pwd)
Dir[File.join(turbo_tests_coverage_dir(coverage_dir, project_root: project_root), "*", ".resultset.json")]
end
|
.with_quiet_collation_output ⇒ Object
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|
# File 'lib/kettle/soup/cover.rb', line 192
def with_quiet_collation_output
return yield unless Constants::QUIET_COLLATION && !Constants::VERBOSE
stdout = StringIO.new
stderr = StringIO.new
original_stdout = $stdout
original_stderr = $stderr
begin
$stdout = stdout
$stderr = stderr
yield
ensure
$stdout = original_stdout
$stderr = original_stderr
replay_quiet_collation_output(stdout.string, original_stdout)
replay_quiet_collation_output(stderr.string, original_stderr)
end
end
|