rspec-tracer 0.9.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +27 -2
- data/lib/rspec_tracer/cache.rb +75 -40
- data/lib/rspec_tracer/configuration.rb +16 -9
- data/lib/rspec_tracer/coverage_merger.rb +41 -0
- data/lib/rspec_tracer/coverage_reporter.rb +31 -28
- data/lib/rspec_tracer/coverage_writer.rb +58 -0
- data/lib/rspec_tracer/html_reporter/reporter.rb +7 -6
- data/lib/rspec_tracer/remote_cache/validator.rb +1 -1
- data/lib/rspec_tracer/report_generator.rb +158 -0
- data/lib/rspec_tracer/report_merger.rb +81 -0
- data/lib/rspec_tracer/report_writer.rb +141 -0
- data/lib/rspec_tracer/reporter.rb +4 -158
- data/lib/rspec_tracer/rspec_runner.rb +2 -4
- data/lib/rspec_tracer/runner.rb +2 -112
- data/lib/rspec_tracer/version.rb +1 -1
- data/lib/rspec_tracer.rb +197 -27
- metadata +21 -16
@@ -0,0 +1,158 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RSpecTracer
|
4
|
+
class ReportGenerator
|
5
|
+
def initialize(reporter, cache)
|
6
|
+
@reporter = reporter
|
7
|
+
@cache = cache
|
8
|
+
end
|
9
|
+
|
10
|
+
def reverse_dependency_report
|
11
|
+
reverse_dependency = Hash.new do |examples, file_name|
|
12
|
+
examples[file_name] = {
|
13
|
+
example_count: 0,
|
14
|
+
examples: Hash.new(0)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
@reporter.dependency.each_pair do |example_id, files|
|
19
|
+
next if @reporter.interrupted_examples.include?(example_id)
|
20
|
+
|
21
|
+
example_file = @reporter.all_examples[example_id][:rerun_file_name]
|
22
|
+
|
23
|
+
files.each do |file_name|
|
24
|
+
reverse_dependency[file_name][:example_count] += 1
|
25
|
+
reverse_dependency[file_name][:examples][example_file] += 1
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
reverse_dependency.transform_values! do |data|
|
30
|
+
{
|
31
|
+
example_count: data[:example_count],
|
32
|
+
examples: data[:examples].sort_by { |file_name, count| [-count, file_name] }.to_h
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
reverse_dependency.sort_by { |file_name, data| [-data[:example_count], file_name] }.to_h
|
37
|
+
end
|
38
|
+
|
39
|
+
def generate_report
|
40
|
+
generate_last_run_report
|
41
|
+
generate_examples_status_report
|
42
|
+
|
43
|
+
%i[all_files all_examples dependency examples_coverage reverse_dependency].each do |report_type|
|
44
|
+
starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
45
|
+
|
46
|
+
send("generate_#{report_type}_report")
|
47
|
+
|
48
|
+
ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
49
|
+
elapsed = RSpecTracer::TimeFormatter.format_time(ending - starting)
|
50
|
+
|
51
|
+
puts "RSpec tracer generated #{report_type.to_s.tr('_', ' ')} report (took #{elapsed})" if RSpecTracer.verbose?
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def generate_last_run_report
|
58
|
+
@reporter.last_run = {
|
59
|
+
pid: RSpecTracer.pid,
|
60
|
+
actual_count: RSpec.world.example_count + @reporter.skipped_examples.count,
|
61
|
+
example_count: RSpec.world.example_count,
|
62
|
+
duplicate_examples: @reporter.duplicate_examples.sum { |_, examples| examples.count },
|
63
|
+
interrupted_examples: @reporter.interrupted_examples.count,
|
64
|
+
failed_examples: @reporter.failed_examples.count,
|
65
|
+
skipped_examples: @reporter.skipped_examples.count,
|
66
|
+
pending_examples: @reporter.pending_examples.count,
|
67
|
+
flaky_examples: @reporter.flaky_examples.count
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
def generate_examples_status_report
|
72
|
+
starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
73
|
+
|
74
|
+
generate_flaky_examples_report
|
75
|
+
generate_failed_examples_report
|
76
|
+
generate_pending_examples_report
|
77
|
+
|
78
|
+
ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
79
|
+
elapsed = RSpecTracer::TimeFormatter.format_time(ending - starting)
|
80
|
+
|
81
|
+
puts "RSpec tracer generated flaky, failed, and pending examples report (took #{elapsed})" if RSpecTracer.verbose?
|
82
|
+
end
|
83
|
+
|
84
|
+
def generate_flaky_examples_report
|
85
|
+
@reporter.possibly_flaky_examples.each do |example_id|
|
86
|
+
next if @reporter.example_deleted?(example_id)
|
87
|
+
next unless @cache.flaky_examples.include?(example_id) ||
|
88
|
+
@reporter.example_passed?(example_id)
|
89
|
+
|
90
|
+
@reporter.register_flaky_example(example_id)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def generate_failed_examples_report
|
95
|
+
@cache.failed_examples.each do |example_id|
|
96
|
+
next if @reporter.example_deleted?(example_id) ||
|
97
|
+
@reporter.all_examples.key?(example_id)
|
98
|
+
|
99
|
+
@reporter.register_failed_example(example_id)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def generate_pending_examples_report
|
104
|
+
@cache.pending_examples.each do |example_id|
|
105
|
+
next if @reporter.example_deleted?(example_id) ||
|
106
|
+
@reporter.all_examples.key?(example_id)
|
107
|
+
|
108
|
+
@reporter.register_pending_example(example_id)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def generate_all_files_report
|
113
|
+
@cache.all_files.each_pair do |file_name, data|
|
114
|
+
next if @reporter.all_files.key?(file_name) ||
|
115
|
+
@reporter.file_deleted?(file_name)
|
116
|
+
|
117
|
+
@reporter.all_files[file_name] = data
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def generate_all_examples_report
|
122
|
+
@cache.all_examples.each_pair do |example_id, data|
|
123
|
+
next if @reporter.all_examples.key?(example_id) ||
|
124
|
+
@reporter.example_deleted?(example_id)
|
125
|
+
|
126
|
+
@reporter.all_examples[example_id] = data
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def generate_dependency_report
|
131
|
+
@cache.dependency.each_pair do |example_id, data|
|
132
|
+
next if @reporter.dependency.key?(example_id) ||
|
133
|
+
@reporter.example_deleted?(example_id)
|
134
|
+
|
135
|
+
@reporter.dependency[example_id] = data.reject do |file_name|
|
136
|
+
@reporter.file_deleted?(file_name)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
@reporter.dependency.transform_values!(&:to_a)
|
141
|
+
end
|
142
|
+
|
143
|
+
def generate_examples_coverage_report
|
144
|
+
@cache.cached_examples_coverage.each_pair do |example_id, data|
|
145
|
+
next if @reporter.examples_coverage.key?(example_id) ||
|
146
|
+
@reporter.example_deleted?(example_id)
|
147
|
+
|
148
|
+
@reporter.examples_coverage[example_id] = data.reject do |file_name|
|
149
|
+
@reporter.file_deleted?(file_name)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def generate_reverse_dependency_report
|
155
|
+
@reporter.reverse_dependency = reverse_dependency_report
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RSpecTracer
|
4
|
+
class ReportMerger
|
5
|
+
attr_reader :all_examples, :duplicate_examples, :interrupted_examples,
|
6
|
+
:flaky_examples, :failed_examples, :pending_examples, :skipped_examples,
|
7
|
+
:all_files, :dependency, :reverse_dependency, :examples_coverage, :last_run
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@last_run = {}
|
11
|
+
@all_examples = {}
|
12
|
+
@duplicate_examples = {}
|
13
|
+
@interrupted_examples = Set.new
|
14
|
+
@flaky_examples = Set.new
|
15
|
+
@failed_examples = Set.new
|
16
|
+
@pending_examples = Set.new
|
17
|
+
@skipped_examples = Set.new
|
18
|
+
@all_files = {}
|
19
|
+
@dependency = Hash.new { |hash, key| hash[key] = Set.new }
|
20
|
+
@reverse_dependency = {}
|
21
|
+
@examples_coverage = {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def merge(reports_dir)
|
25
|
+
reports_dir.each do |report_dir|
|
26
|
+
next unless File.directory?(report_dir)
|
27
|
+
|
28
|
+
merge_cache(load_cache(report_dir))
|
29
|
+
merge_last_run_report(File.dirname(report_dir))
|
30
|
+
end
|
31
|
+
|
32
|
+
@dependency.transform_values!(&:to_a)
|
33
|
+
|
34
|
+
@reverse_dependency = RSpecTracer::ReportGenerator.new(self, nil).reverse_dependency_report
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def load_cache(cache_dir)
|
40
|
+
cache = RSpecTracer::Cache.new
|
41
|
+
|
42
|
+
cache.send(:load_all_examples_cache, cache_dir, discard_run_reason: false)
|
43
|
+
cache.send(:load_duplicate_examples_cache, cache_dir)
|
44
|
+
cache.send(:load_interrupted_examples_cache, cache_dir)
|
45
|
+
cache.send(:load_flaky_examples_cache, cache_dir)
|
46
|
+
cache.send(:load_failed_examples_cache, cache_dir)
|
47
|
+
cache.send(:load_pending_examples_cache, cache_dir)
|
48
|
+
cache.send(:load_skipped_examples_cache, cache_dir)
|
49
|
+
cache.send(:load_all_files_cache, cache_dir)
|
50
|
+
cache.send(:load_dependency_cache, cache_dir)
|
51
|
+
cache.send(:load_examples_coverage_cache, cache_dir)
|
52
|
+
|
53
|
+
cache
|
54
|
+
end
|
55
|
+
|
56
|
+
def merge_cache(cache)
|
57
|
+
@all_examples.merge!(cache.all_examples) { |_, v1, v2| v1[:run_reason] ? v1 : v2 }
|
58
|
+
@duplicate_examples.merge!(cache.duplicate_examples) { |_, v1, v2| v1 + v2 }
|
59
|
+
@interrupted_examples.merge(cache.interrupted_examples)
|
60
|
+
@flaky_examples.merge(cache.flaky_examples)
|
61
|
+
@failed_examples.merge(cache.failed_examples)
|
62
|
+
@pending_examples.merge(cache.pending_examples)
|
63
|
+
@skipped_examples.merge(cache.skipped_examples)
|
64
|
+
@all_files.merge!(cache.all_files)
|
65
|
+
@dependency.merge!(cache.dependency) { |_, v1, v2| v1.merge(v2) }
|
66
|
+
@examples_coverage.merge!(cache.examples_coverage) do |_, v1, v2|
|
67
|
+
v1.merge(v2) { |_, v3, v4| v3.merge(v4) { |_, v5, v6| v5 + v6 } }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def merge_last_run_report(cache_dir)
|
72
|
+
file_name = File.join(cache_dir, 'last_run.json')
|
73
|
+
cached_last_run = JSON.parse(File.read(file_name), symbolize_names: true)
|
74
|
+
cached_last_run[:pid] = [cached_last_run[:pid]]
|
75
|
+
|
76
|
+
cached_last_run.delete_if { |key, _| %i[run_id timestamp].include?(key) }
|
77
|
+
|
78
|
+
@last_run.merge!(cached_last_run) { |_, v1, v2| v1 + v2 }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RSpecTracer
|
4
|
+
class ReportWriter
|
5
|
+
def initialize(report_dir, reporter)
|
6
|
+
@report_dir = report_dir
|
7
|
+
@reporter = reporter
|
8
|
+
end
|
9
|
+
|
10
|
+
def write_report
|
11
|
+
starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
12
|
+
|
13
|
+
@run_id = Digest::MD5.hexdigest(@reporter.all_examples.keys.sort.to_json)
|
14
|
+
@cache_dir = File.join(@report_dir, @run_id)
|
15
|
+
|
16
|
+
FileUtils.mkdir_p(@cache_dir)
|
17
|
+
|
18
|
+
write_all_examples_report
|
19
|
+
write_duplicate_examples_report
|
20
|
+
write_interrupted_examples_report
|
21
|
+
write_flaky_examples_report
|
22
|
+
write_failed_examples_report
|
23
|
+
write_pending_examples_report
|
24
|
+
write_skipped_examples_report
|
25
|
+
write_all_files_report
|
26
|
+
write_dependency_report
|
27
|
+
write_reverse_dependency_report
|
28
|
+
write_examples_coverage_report
|
29
|
+
write_last_run_report
|
30
|
+
|
31
|
+
ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
32
|
+
elapsed = RSpecTracer::TimeFormatter.format_time(ending - starting)
|
33
|
+
|
34
|
+
puts "RSpec tracer reports written to #{@cache_dir} (took #{elapsed})"
|
35
|
+
end
|
36
|
+
|
37
|
+
def print_duplicate_examples
|
38
|
+
return if @reporter.duplicate_examples.empty?
|
39
|
+
|
40
|
+
total = @reporter.duplicate_examples.sum { |_, examples| examples.count }
|
41
|
+
|
42
|
+
puts '=' * 80
|
43
|
+
puts ' IMPORTANT NOTICE -- RSPEC TRACER COULD NOT IDENTIFY SOME EXAMPLES UNIQUELY'
|
44
|
+
puts '=' * 80
|
45
|
+
puts "RSpec tracer could not uniquely identify the following #{total} examples:"
|
46
|
+
|
47
|
+
justify = ' ' * 2
|
48
|
+
nested_justify = justify * 3
|
49
|
+
|
50
|
+
@reporter.duplicate_examples.each_pair do |example_id, examples|
|
51
|
+
puts "#{justify}- Example ID: #{example_id} (#{examples.count} examples)"
|
52
|
+
|
53
|
+
examples.each do |example|
|
54
|
+
description = example[:full_description].strip
|
55
|
+
file_name = example[:rerun_file_name].sub(%r{^/}, '')
|
56
|
+
line_number = example[:rerun_line_number]
|
57
|
+
location = "#{file_name}:#{line_number}"
|
58
|
+
|
59
|
+
puts "#{nested_justify}* #{description} (#{location})"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
puts
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def write_all_examples_report
|
69
|
+
file_name = File.join(@cache_dir, 'all_examples.json')
|
70
|
+
|
71
|
+
File.write(file_name, JSON.pretty_generate(@reporter.all_examples))
|
72
|
+
end
|
73
|
+
|
74
|
+
def write_duplicate_examples_report
|
75
|
+
file_name = File.join(@cache_dir, 'duplicate_examples.json')
|
76
|
+
|
77
|
+
File.write(file_name, JSON.pretty_generate(@reporter.duplicate_examples))
|
78
|
+
end
|
79
|
+
|
80
|
+
def write_interrupted_examples_report
|
81
|
+
file_name = File.join(@cache_dir, 'interrupted_examples.json')
|
82
|
+
|
83
|
+
File.write(file_name, JSON.pretty_generate(@reporter.interrupted_examples.sort.to_a))
|
84
|
+
end
|
85
|
+
|
86
|
+
def write_flaky_examples_report
|
87
|
+
file_name = File.join(@cache_dir, 'flaky_examples.json')
|
88
|
+
|
89
|
+
File.write(file_name, JSON.pretty_generate(@reporter.flaky_examples.sort.to_a))
|
90
|
+
end
|
91
|
+
|
92
|
+
def write_failed_examples_report
|
93
|
+
file_name = File.join(@cache_dir, 'failed_examples.json')
|
94
|
+
|
95
|
+
File.write(file_name, JSON.pretty_generate(@reporter.failed_examples.sort.to_a))
|
96
|
+
end
|
97
|
+
|
98
|
+
def write_pending_examples_report
|
99
|
+
file_name = File.join(@cache_dir, 'pending_examples.json')
|
100
|
+
|
101
|
+
File.write(file_name, JSON.pretty_generate(@reporter.pending_examples.sort.to_a))
|
102
|
+
end
|
103
|
+
|
104
|
+
def write_skipped_examples_report
|
105
|
+
file_name = File.join(@cache_dir, 'skipped_examples.json')
|
106
|
+
|
107
|
+
File.write(file_name, JSON.pretty_generate(@reporter.skipped_examples.sort.to_a))
|
108
|
+
end
|
109
|
+
|
110
|
+
def write_all_files_report
|
111
|
+
file_name = File.join(@cache_dir, 'all_files.json')
|
112
|
+
|
113
|
+
File.write(file_name, JSON.pretty_generate(@reporter.all_files))
|
114
|
+
end
|
115
|
+
|
116
|
+
def write_dependency_report
|
117
|
+
file_name = File.join(@cache_dir, 'dependency.json')
|
118
|
+
|
119
|
+
File.write(file_name, JSON.pretty_generate(@reporter.dependency))
|
120
|
+
end
|
121
|
+
|
122
|
+
def write_reverse_dependency_report
|
123
|
+
file_name = File.join(@cache_dir, 'reverse_dependency.json')
|
124
|
+
|
125
|
+
File.write(file_name, JSON.pretty_generate(@reporter.reverse_dependency))
|
126
|
+
end
|
127
|
+
|
128
|
+
def write_examples_coverage_report
|
129
|
+
file_name = File.join(@cache_dir, 'examples_coverage.json')
|
130
|
+
|
131
|
+
File.write(file_name, JSON.pretty_generate(@reporter.examples_coverage))
|
132
|
+
end
|
133
|
+
|
134
|
+
def write_last_run_report
|
135
|
+
file_name = File.join(@report_dir, 'last_run.json')
|
136
|
+
last_run_data = @reporter.last_run.merge(run_id: @run_id, timestamp: Time.now.utc)
|
137
|
+
|
138
|
+
File.write(file_name, JSON.pretty_generate(last_run_data))
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -4,8 +4,10 @@ module RSpecTracer
|
|
4
4
|
class Reporter
|
5
5
|
attr_reader :all_examples, :interrupted_examples, :duplicate_examples,
|
6
6
|
:possibly_flaky_examples, :flaky_examples, :pending_examples,
|
7
|
-
:
|
8
|
-
:
|
7
|
+
:skipped_examples, :failed_examples, :all_files, :modified_files,
|
8
|
+
:deleted_files, :dependency, :examples_coverage
|
9
|
+
|
10
|
+
attr_accessor :reverse_dependency, :last_run
|
9
11
|
|
10
12
|
def initialize
|
11
13
|
initialize_examples
|
@@ -151,92 +153,6 @@ module RSpecTracer
|
|
151
153
|
@examples_coverage = examples_coverage
|
152
154
|
end
|
153
155
|
|
154
|
-
def generate_reverse_dependency_report
|
155
|
-
@dependency.each_pair do |example_id, files|
|
156
|
-
next if @interrupted_examples.include?(example_id)
|
157
|
-
|
158
|
-
example_file = @all_examples[example_id][:rerun_file_name]
|
159
|
-
|
160
|
-
files.each do |file_name|
|
161
|
-
@reverse_dependency[file_name][:example_count] += 1
|
162
|
-
@reverse_dependency[file_name][:examples][example_file] += 1
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
format_reverse_dependency_report
|
167
|
-
end
|
168
|
-
|
169
|
-
def generate_last_run_report
|
170
|
-
@last_run = {
|
171
|
-
pid: RSpecTracer.pid,
|
172
|
-
actual_count: RSpec.world.example_count + @skipped_examples.count,
|
173
|
-
example_count: RSpec.world.example_count,
|
174
|
-
duplicate_examples: @duplicate_examples.sum { |_, examples| examples.count },
|
175
|
-
interrupted_examples: @interrupted_examples.count,
|
176
|
-
failed_examples: @failed_examples.count,
|
177
|
-
skipped_examples: @skipped_examples.count,
|
178
|
-
pending_examples: @pending_examples.count,
|
179
|
-
flaky_examples: @flaky_examples.count
|
180
|
-
}
|
181
|
-
end
|
182
|
-
|
183
|
-
def write_reports
|
184
|
-
starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
185
|
-
|
186
|
-
@run_id = Digest::MD5.hexdigest(@all_examples.keys.sort.to_json)
|
187
|
-
@cache_dir = File.join(RSpecTracer.cache_path, @run_id)
|
188
|
-
|
189
|
-
FileUtils.mkdir_p(@cache_dir)
|
190
|
-
|
191
|
-
%i[
|
192
|
-
all_examples
|
193
|
-
flaky_examples
|
194
|
-
failed_examples
|
195
|
-
pending_examples
|
196
|
-
all_files
|
197
|
-
dependency
|
198
|
-
reverse_dependency
|
199
|
-
examples_coverage
|
200
|
-
last_run
|
201
|
-
].each { |report_type| send("write_#{report_type}_report") }
|
202
|
-
|
203
|
-
ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
204
|
-
elpased = RSpecTracer::TimeFormatter.format_time(ending - starting)
|
205
|
-
|
206
|
-
puts "RSpec tracer reports written to #{@cache_dir} (took #{elpased})"
|
207
|
-
end
|
208
|
-
|
209
|
-
# rubocop:disable Metrics/AbcSize
|
210
|
-
def print_duplicate_examples
|
211
|
-
return if @duplicate_examples.empty?
|
212
|
-
|
213
|
-
total = @duplicate_examples.sum { |_, examples| examples.count }
|
214
|
-
|
215
|
-
puts '=' * 80
|
216
|
-
puts ' IMPORTANT NOTICE -- RSPEC TRACER COULD NOT IDENTIFY SOME EXAMPLES UNIQUELY'
|
217
|
-
puts '=' * 80
|
218
|
-
puts "RSpec tracer could not uniquely identify the following #{total} examples:"
|
219
|
-
|
220
|
-
justify = ' ' * 2
|
221
|
-
nested_justify = justify * 3
|
222
|
-
|
223
|
-
@duplicate_examples.each_pair do |example_id, examples|
|
224
|
-
puts "#{justify}- Example ID: #{example_id} (#{examples.count} examples)"
|
225
|
-
|
226
|
-
examples.each do |example|
|
227
|
-
description = example[:full_description].strip
|
228
|
-
file_name = example[:rerun_file_name].sub(%r{^/}, '')
|
229
|
-
line_number = example[:rerun_line_number]
|
230
|
-
location = "#{file_name}:#{line_number}"
|
231
|
-
|
232
|
-
puts "#{nested_justify}* #{description} (#{location})"
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
puts
|
237
|
-
end
|
238
|
-
# rubocop:enable Metrics/AbcSize
|
239
|
-
|
240
156
|
private
|
241
157
|
|
242
158
|
def initialize_examples
|
@@ -284,75 +200,5 @@ module RSpecTracer
|
|
284
200
|
status: result.status.to_s
|
285
201
|
}
|
286
202
|
end
|
287
|
-
|
288
|
-
def format_reverse_dependency_report
|
289
|
-
@reverse_dependency.transform_values! do |data|
|
290
|
-
{
|
291
|
-
example_count: data[:example_count],
|
292
|
-
examples: data[:examples].sort_by { |file_name, count| [-count, file_name] }.to_h
|
293
|
-
}
|
294
|
-
end
|
295
|
-
|
296
|
-
report = @reverse_dependency.sort_by do |file_name, data|
|
297
|
-
[-data[:example_count], file_name]
|
298
|
-
end
|
299
|
-
|
300
|
-
@reverse_dependency = report.to_h
|
301
|
-
end
|
302
|
-
|
303
|
-
def write_all_examples_report
|
304
|
-
file_name = File.join(@cache_dir, 'all_examples.json')
|
305
|
-
|
306
|
-
File.write(file_name, JSON.pretty_generate(@all_examples))
|
307
|
-
end
|
308
|
-
|
309
|
-
def write_flaky_examples_report
|
310
|
-
file_name = File.join(@cache_dir, 'flaky_examples.json')
|
311
|
-
|
312
|
-
File.write(file_name, JSON.pretty_generate(@flaky_examples.to_a))
|
313
|
-
end
|
314
|
-
|
315
|
-
def write_failed_examples_report
|
316
|
-
file_name = File.join(@cache_dir, 'failed_examples.json')
|
317
|
-
|
318
|
-
File.write(file_name, JSON.pretty_generate(@failed_examples.to_a))
|
319
|
-
end
|
320
|
-
|
321
|
-
def write_pending_examples_report
|
322
|
-
file_name = File.join(@cache_dir, 'pending_examples.json')
|
323
|
-
|
324
|
-
File.write(file_name, JSON.pretty_generate(@pending_examples.to_a))
|
325
|
-
end
|
326
|
-
|
327
|
-
def write_all_files_report
|
328
|
-
file_name = File.join(@cache_dir, 'all_files.json')
|
329
|
-
|
330
|
-
File.write(file_name, JSON.pretty_generate(@all_files))
|
331
|
-
end
|
332
|
-
|
333
|
-
def write_dependency_report
|
334
|
-
file_name = File.join(@cache_dir, 'dependency.json')
|
335
|
-
|
336
|
-
File.write(file_name, JSON.pretty_generate(@dependency))
|
337
|
-
end
|
338
|
-
|
339
|
-
def write_reverse_dependency_report
|
340
|
-
file_name = File.join(@cache_dir, 'reverse_dependency.json')
|
341
|
-
|
342
|
-
File.write(file_name, JSON.pretty_generate(@reverse_dependency))
|
343
|
-
end
|
344
|
-
|
345
|
-
def write_examples_coverage_report
|
346
|
-
file_name = File.join(@cache_dir, 'examples_coverage.json')
|
347
|
-
|
348
|
-
File.write(file_name, JSON.pretty_generate(@examples_coverage))
|
349
|
-
end
|
350
|
-
|
351
|
-
def write_last_run_report
|
352
|
-
file_name = File.join(RSpecTracer.cache_path, 'last_run.json')
|
353
|
-
last_run_data = @last_run.merge(run_id: @run_id, timestamp: Time.now.utc)
|
354
|
-
|
355
|
-
File.write(file_name, JSON.pretty_generate(last_run_data))
|
356
|
-
end
|
357
203
|
end
|
358
204
|
end
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
module RSpecTracer
|
4
4
|
module RSpecRunner
|
5
|
-
# rubocop:disable Metrics/AbcSize
|
6
5
|
def run_specs(example_groups)
|
7
6
|
actual_count = RSpec.world.example_count
|
8
7
|
RSpecTracer.no_examples = actual_count.zero?
|
@@ -23,18 +22,17 @@ module RSpecTracer
|
|
23
22
|
|
24
23
|
current_count = RSpec.world.example_count
|
25
24
|
ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
26
|
-
|
25
|
+
elapsed = RSpecTracer::TimeFormatter.format_time(ending - starting)
|
27
26
|
|
28
27
|
puts
|
29
28
|
puts <<-EXAMPLES.strip.gsub(/\s+/, ' ')
|
30
29
|
RSpec tracer is running #{current_count} examples (actual: #{actual_count},
|
31
|
-
skipped: #{actual_count - current_count}) (took #{
|
30
|
+
skipped: #{actual_count - current_count}) (took #{elapsed})
|
32
31
|
EXAMPLES
|
33
32
|
|
34
33
|
RSpecTracer.running = true
|
35
34
|
|
36
35
|
super(filtered_example_groups)
|
37
36
|
end
|
38
|
-
# rubocop:enable Metrics/AbcSize
|
39
37
|
end
|
40
38
|
end
|