1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'optparse'
require 'fileutils'
require 'uri'
require 'json'
require 'set'
class FailedTests
DEFAULT_OPTIONS = {
previous_tests_report_path: 'test_results/previous/test_reports.json',
output_directory: 'tmp/previous_failed_tests/',
format: :oneline,
rspec_pg_regex: /rspec .+ pg12( .+)?/,
rspec_ee_pg_regex: /rspec-ee .+ pg12( .+)?/
}.freeze
def initialize(options)
@filename = options.delete(:previous_tests_report_path)
@output_directory = options.delete(:output_directory)
@format = options.delete(:format).to_sym
@rspec_pg_regex = options.delete(:rspec_pg_regex)
@rspec_ee_pg_regex = options.delete(:rspec_ee_pg_regex)
end
def output_failed_tests
create_output_dir
failed_cases_for_suite_collection.each do |suite_name, suite_tests|
puts "[FailedTests] Detected #{suite_tests.size} failed tests in suite #{suite_name}..."
suite_tests =
case format
when :oneline
suite_tests.map { |test| test['file'] }.join(' ') # rubocop:disable Rails/Pluck
when :json
JSON.pretty_generate(suite_tests.to_a)
end
output_file = File.join(output_directory, "#{suite_name}_failed_tests.#{output_file_format}")
File.open(output_file, 'w') do |file|
file.write(suite_tests)
end
end
end
def failed_cases_for_suite_collection
suite_map.each_with_object(Hash.new { |h, k| h[k] = Set.new }) do |(suite_name, suite_collection_regex), hash|
failed_suites.each do |suite|
hash[suite_name].merge(failed_cases(suite)) if suite['name'] =~ suite_collection_regex
end
end
end
def suite_map
@suite_map ||= {
rspec: rspec_pg_regex,
rspec_ee: rspec_ee_pg_regex,
jest: /jest/
}
end
private
attr_reader :filename, :output_directory, :format, :rspec_pg_regex, :rspec_ee_pg_regex
def file_contents
@file_contents ||= begin
File.read(filename)
rescue Errno::ENOENT
'{}'
end
end
def file_contents_as_json
@file_contents_as_json ||= begin
JSON.parse(file_contents)
rescue JSON::ParserError
{}
end
end
def output_file_format
case format
when :oneline
'txt'
when :json
'json'
else
raise "[FailedTests] Unsupported format `#{format}` (allowed formats: `oneline` and `json`)!"
end
end
def failed_suites
return [] unless file_contents_as_json['suites']
file_contents_as_json['suites'].select { |suite| suite['failed_count'] > 0 }
end
def failed_cases(suite)
return [] unless suite
suite['test_cases'].filter_map do |failure_hash|
next if failure_hash['status'] != 'failed'
failure_hash['job_url'] = suite['job_url']
failure_hash['file'] = failure_hash['file'].delete_prefix('./')
failure_hash
end
end
def create_output_dir
return if File.directory?(output_directory)
puts '[FailedTests] Creating output directory...'
FileUtils.mkdir_p(output_directory)
end
end
if $PROGRAM_NAME == __FILE__
options = FailedTests::DEFAULT_OPTIONS.dup
OptionParser.new do |opts|
opts.on("-p", "--previous-tests-report-path PREVIOUS_TESTS_REPORT_PATH", String,
"Path of the file listing previous test failures (defaults to " \
"`#{FailedTests::DEFAULT_OPTIONS[:previous_tests_report_path]}`)") do |value|
options[:previous_tests_report_path] = value
end
opts.on("-o", "--output-directory OUTPUT_DIRECTORY", String,
"Output directory for failed test files (defaults to " \
"`#{FailedTests::DEFAULT_OPTIONS[:output_directory]}`)") do |value|
options[:output_directory] = value
end
opts.on("-f", "--format [oneline|json]", String,
"Format of the output files: oneline (with test filenames) or JSON (defaults to " \
"`#{FailedTests::DEFAULT_OPTIONS[:format]}`)") do |value|
options[:format] = value
end
opts.on("--rspec-pg-regex RSPEC_PG_REGEX", Regexp,
"Regex to use when finding matching RSpec jobs (defaults to " \
"`#{FailedTests::DEFAULT_OPTIONS[:rspec_pg_regex]}`)") do |value|
options[:rspec_pg_regex] = value
end
opts.on("--rspec-ee-pg-regex RSPEC_EE_PG_REGEX", Regexp,
"Regex to use when finding matching RSpec EE jobs (defaults to " \
"`#{FailedTests::DEFAULT_OPTIONS[:rspec_ee_pg_regex]}`)") do |value|
options[:rspec_ee_pg_regex] = value
end
opts.on("-h", "--help", "Prints this help") do
puts opts
exit
end
end.parse!
FailedTests.new(options).output_failed_tests
end
|