fast_ci 0.1.2 → 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/.github/workflows/main.yml +26 -0
- data/.rubocop.yml +3 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +154 -43
- data/LICENSE.txt +1 -1
- data/README.md +5 -1
- data/bin/fastci_brakeman +9 -0
- data/bin/fastci_bundle_audit +55 -0
- data/bin/fastci_rubycritic +10 -0
- data/fast_ci.gemspec +8 -5
- data/lib/fast_ci/brakeman/commandline.rb +12 -0
- data/lib/fast_ci/brakeman.rb +30 -0
- data/lib/fast_ci/configuration.rb +20 -5
- data/lib/fast_ci/dryrun_runner_prepend.rb +28 -0
- data/lib/fast_ci/extract_definitions.rb +44 -0
- data/lib/fast_ci/rspec_dryrun_formatter.rb +117 -0
- data/lib/fast_ci/rspec_formatter.rb +274 -0
- data/lib/fast_ci/rspec_run_formatter.rb +247 -0
- data/lib/fast_ci/ruby_critic/cli/application.rb +51 -0
- data/lib/fast_ci/runner_prepend.rb +107 -0
- data/lib/fast_ci/simple_cov/reporting.rb +39 -0
- data/lib/fast_ci/simple_cov.rb +68 -0
- data/lib/fast_ci/version.rb +1 -1
- data/lib/fast_ci.rb +112 -26
- data/lib/minitest/reporters/fastci_reporter.rb +287 -0
- data/lib/minitest/rubyci_plugin.rb +9 -0
- metadata +86 -9
@@ -0,0 +1,287 @@
|
|
1
|
+
module Minitest
|
2
|
+
module Reporters
|
3
|
+
class Suite
|
4
|
+
attr_reader :name
|
5
|
+
def initialize(name)
|
6
|
+
@name = name
|
7
|
+
end
|
8
|
+
|
9
|
+
def ==(other)
|
10
|
+
name == other.name
|
11
|
+
end
|
12
|
+
|
13
|
+
def eql?(other)
|
14
|
+
self == other
|
15
|
+
end
|
16
|
+
|
17
|
+
def hash
|
18
|
+
name.hash
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
name.to_s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class FastCIReporter
|
27
|
+
attr_accessor :tests, :test_results, :ids
|
28
|
+
|
29
|
+
def initialize
|
30
|
+
@tests = {}
|
31
|
+
@test_results = {}
|
32
|
+
@ids = {}
|
33
|
+
@events = []
|
34
|
+
|
35
|
+
$stdout = StringIO.new()
|
36
|
+
|
37
|
+
if ENV['RBCI_REMOTE_TESTS'] != 'true'
|
38
|
+
FastCI.minitest_ws.on(:enq_request) do
|
39
|
+
tests
|
40
|
+
end
|
41
|
+
|
42
|
+
FastCI.minitest_ws.on(:deq) do |api_tests|
|
43
|
+
test_results
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def start
|
49
|
+
test_count = Runnable.runnables.sum { |s| s.runnable_methods.count }
|
50
|
+
msg('start', { test_count: test_count })
|
51
|
+
@events << ['run_minitest'.upcase, { started_at: Time.current }]
|
52
|
+
send_events if ENV['RBCI_REMOTE_TESTS'] == 'true'
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_output
|
56
|
+
return if $stdout.pos == 0
|
57
|
+
$stdout.rewind
|
58
|
+
res = $stdout.read
|
59
|
+
$stdout.flush
|
60
|
+
$stdout.rewind
|
61
|
+
return unless res
|
62
|
+
res.strip.chomp if res.strip.chomp != ""
|
63
|
+
end
|
64
|
+
|
65
|
+
def before_test(test)
|
66
|
+
$stdout = StringIO.new()
|
67
|
+
end
|
68
|
+
|
69
|
+
def prerecord(klass, name)
|
70
|
+
description = test_description(name)
|
71
|
+
path = test_path(klass.name)
|
72
|
+
|
73
|
+
test_results[path] ||= { run_time: 0.0, file_status: 'pending', test_count: 0, test_counters: { failed: 0, passed: 0, pending: 0 }, '1' => { description: klass.name } }
|
74
|
+
test_results[path][:test_count] += 1
|
75
|
+
|
76
|
+
id = (test_results[path]['1'].keys.size + 1).to_s
|
77
|
+
ids[description] = id
|
78
|
+
|
79
|
+
test_results[path]['1'][id] ||= { status: 'pending', description: description }
|
80
|
+
test_results[path]['1'][id][:start] = Minitest.clock_time
|
81
|
+
|
82
|
+
tests[path] ||= { run_time: 0.0, file_status: 'pending', test_count: 0, test_counters: { failed: 0, passed: 0, pending: 0 }, '1' => {} }
|
83
|
+
tests[path][:test_count] += 1
|
84
|
+
tests[path]['1'][id] ||= { status: 'pending' }
|
85
|
+
end
|
86
|
+
|
87
|
+
def record(result)
|
88
|
+
test_finished(result)
|
89
|
+
description = test_description(result.name)
|
90
|
+
id = ids[description]
|
91
|
+
path = test_path(result.klass)
|
92
|
+
|
93
|
+
test_results[path]['1'][id][:end] = Minitest.clock_time
|
94
|
+
test_results[path]['1'][id][:run_time] = test_results[path]['1'][id][:end] - test_results[path]['1'][id][:start]
|
95
|
+
test_results[path]['1'][id][:status] = result_status(result).to_s
|
96
|
+
test_results[path][:test_counters][result_status(result)] += 1
|
97
|
+
test_results[path][:run_time] += test_results[path]['1'][id][:run_time]
|
98
|
+
end
|
99
|
+
|
100
|
+
def report
|
101
|
+
test_results.each do |path, file_results|
|
102
|
+
file_status = 'pending'
|
103
|
+
file_results['1'].each do |id, test_result|
|
104
|
+
next if id == :description
|
105
|
+
if (test_result[:status] == 'passed') && (file_status != 'failed')
|
106
|
+
file_status = 'passed'
|
107
|
+
elsif file_status == 'failed'
|
108
|
+
file_status = 'failed'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
test_results[path][:file_status] = file_status
|
112
|
+
end
|
113
|
+
|
114
|
+
if ENV['RBCI_REMOTE_TESTS'] == 'true'
|
115
|
+
send_events
|
116
|
+
else
|
117
|
+
FastCI.minitest_await
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def passed?
|
122
|
+
results = []
|
123
|
+
test_results.map do |path, file_results|
|
124
|
+
file_results['1'].each do |id, test_result|
|
125
|
+
next if id == :description
|
126
|
+
if test_result[:status] == 'failed'
|
127
|
+
results << false
|
128
|
+
else
|
129
|
+
results << true
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
pass = results.any? {|reult| !result }
|
135
|
+
|
136
|
+
if pass
|
137
|
+
@events << ['run_minitest'.upcase, { succeed_after: 1 }]
|
138
|
+
else
|
139
|
+
@events << ['run_minitest'.upcase, { failed_after: 1 }]
|
140
|
+
end
|
141
|
+
send_events if ENV['RBCI_REMOTE_TESTS'] == 'true'
|
142
|
+
|
143
|
+
return pass
|
144
|
+
end
|
145
|
+
|
146
|
+
def method_missing(method, *args)
|
147
|
+
return
|
148
|
+
end
|
149
|
+
|
150
|
+
protected
|
151
|
+
|
152
|
+
def before_suite(suite)
|
153
|
+
end
|
154
|
+
|
155
|
+
def after_suite(_suite)
|
156
|
+
end
|
157
|
+
|
158
|
+
def record_print_status(test)
|
159
|
+
test_name = test.name.gsub(/^test_: /, "test:")
|
160
|
+
print pad_test(test_name)
|
161
|
+
print_colored_status(test)
|
162
|
+
print(" (%.2fs)" % test.time) unless test.time.nil?
|
163
|
+
puts
|
164
|
+
end
|
165
|
+
|
166
|
+
def record_print_failures_if_any(test)
|
167
|
+
if !test.skipped? && test.failure
|
168
|
+
print_info(test.failure, test.error?)
|
169
|
+
puts
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def screenshots_base64(output)
|
174
|
+
return unless output
|
175
|
+
img_path = output&.scan(/\\[Screenshot Image\\]: (.*)$/)&.flatten&.first&.strip&.chomp ||
|
176
|
+
output&.scan(/\\[Screenshot\\]: (.*)$/)&.flatten&.first&.strip&.chomp
|
177
|
+
|
178
|
+
if img_path && File.exist?(img_path)
|
179
|
+
STDOUT.puts "SCREENSHOT!"
|
180
|
+
Base64.strict_encode64(File.read(img_path))
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_finished(test)
|
185
|
+
output = get_output
|
186
|
+
|
187
|
+
location = if !test.source_location.join(":").start_with?(::Rails.root.join('vendor').to_s)
|
188
|
+
test.source_location.join(":")
|
189
|
+
else
|
190
|
+
if (file = `cat #{::Rails.root.join('vendor', 'bundle', 'minitest_cache_file').to_s} | grep "#{test.klass} => "`.split(" => ").last&.chomp)
|
191
|
+
file + ":"
|
192
|
+
else
|
193
|
+
file = `grep -rw "#{::Rails.root.to_s}" -e "#{test.klass} "`.split(":").first
|
194
|
+
`echo "#{test.klass} => #{file}" >> #{::Rails.root.join('vendor', 'bundle', 'minitest_cache_file').to_s}`
|
195
|
+
file + ":"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
fully_formatted = if test.failure
|
200
|
+
fully_formatted = "\n" + test.failure.message.split("\n").first
|
201
|
+
|
202
|
+
test.failure.backtrace.each do |l|
|
203
|
+
if !l["/cache/"]
|
204
|
+
fully_formatted << "\n " + cyan + l + "\033[0m"
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
fully_formatted
|
209
|
+
end
|
210
|
+
|
211
|
+
output_inside = output&.split("\n")&.select do |line|
|
212
|
+
!line["Screenshot"]
|
213
|
+
end&.join("\n")
|
214
|
+
event_data = {
|
215
|
+
test_class: Suite.new(test.klass),
|
216
|
+
test_name: test.name.gsub(/^test_\\d*/, "").gsub(/^test_: /, "test:").gsub(/^_/, "").strip,
|
217
|
+
assertions_count: test.assertions,
|
218
|
+
location: location,
|
219
|
+
status: status(test),
|
220
|
+
run_time: test.time,
|
221
|
+
fully_formatted: fully_formatted,
|
222
|
+
output_inside: output_inside,
|
223
|
+
screenshots_base64: [screenshots_base64(output)]
|
224
|
+
}
|
225
|
+
|
226
|
+
msg('test_finished', event_data)
|
227
|
+
if ENV['RBCI_REMOTE_TESTS'] == 'true'
|
228
|
+
send_events if @events.length >= 10
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def status(test)
|
233
|
+
if test.passed?
|
234
|
+
"passed"
|
235
|
+
elsif test.error?
|
236
|
+
"error"
|
237
|
+
elsif test.skipped?
|
238
|
+
"skipped"
|
239
|
+
elsif test.failure
|
240
|
+
"failed"
|
241
|
+
else
|
242
|
+
raise("Status not found")
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
private
|
247
|
+
|
248
|
+
def msg(event, data)
|
249
|
+
@events << ["minitest_#{event}".upcase, data]
|
250
|
+
end
|
251
|
+
|
252
|
+
def send_events
|
253
|
+
return unless @events.length > 0
|
254
|
+
|
255
|
+
json_events = {
|
256
|
+
build_id: FastCI.configuration.orig_build_id,
|
257
|
+
compressed_data: Base64.strict_encode64(Zlib::Deflate.deflate(JSON.fast_generate(@events), 9)),
|
258
|
+
}
|
259
|
+
|
260
|
+
FastCI.send_events(json_events)
|
261
|
+
|
262
|
+
@events = []
|
263
|
+
end
|
264
|
+
|
265
|
+
def test_description(name)
|
266
|
+
test_name = name.split('test_').last
|
267
|
+
test_name = test_name[2..-1] if test_name.starts_with?(': ')
|
268
|
+
|
269
|
+
return test_name.strip
|
270
|
+
end
|
271
|
+
|
272
|
+
def test_path(klass)
|
273
|
+
return "./#{Object.const_source_location(klass)[0].gsub(Regexp.new("^#{::Rails.root}/"), '')}"
|
274
|
+
end
|
275
|
+
|
276
|
+
def result_status(result)
|
277
|
+
if result.passed?
|
278
|
+
:passed
|
279
|
+
elsif result.skipped?
|
280
|
+
:skipped
|
281
|
+
else
|
282
|
+
:failed
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
metadata
CHANGED
@@ -1,29 +1,85 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fast_ci
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Nesha Zoric
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-10-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: console
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 1.10.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 1.10.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: async-websocket
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "<="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.20.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "<="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.20.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubycritic
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 4.1.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 4.1.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: brakeman
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 5.4.1
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 5.4.1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: minitest-rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '5.1'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '5.1'
|
27
83
|
- !ruby/object:Gem::Dependency
|
28
84
|
name: pry
|
29
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -40,26 +96,47 @@ dependencies:
|
|
40
96
|
version: '0'
|
41
97
|
description: Ruby wrapper for creating FastCI integrations
|
42
98
|
email:
|
43
|
-
-
|
44
|
-
executables:
|
99
|
+
- no-reply@ruby.ci
|
100
|
+
executables:
|
101
|
+
- fastci_rubycritic
|
102
|
+
- fastci_brakeman
|
103
|
+
- fastci_bundle_audit
|
45
104
|
extensions: []
|
46
105
|
extra_rdoc_files: []
|
47
106
|
files:
|
107
|
+
- ".github/workflows/main.yml"
|
48
108
|
- ".gitignore"
|
49
109
|
- ".rspec"
|
50
110
|
- ".rubocop.yml"
|
111
|
+
- CODE_OF_CONDUCT.md
|
51
112
|
- Gemfile
|
52
113
|
- Gemfile.lock
|
53
114
|
- LICENSE.txt
|
54
115
|
- README.md
|
55
116
|
- Rakefile
|
56
117
|
- bin/console
|
118
|
+
- bin/fastci_brakeman
|
119
|
+
- bin/fastci_bundle_audit
|
120
|
+
- bin/fastci_rubycritic
|
57
121
|
- bin/setup
|
58
122
|
- fast_ci.gemspec
|
59
123
|
- lib/fast_ci.rb
|
124
|
+
- lib/fast_ci/brakeman.rb
|
125
|
+
- lib/fast_ci/brakeman/commandline.rb
|
60
126
|
- lib/fast_ci/configuration.rb
|
127
|
+
- lib/fast_ci/dryrun_runner_prepend.rb
|
61
128
|
- lib/fast_ci/exceptions.rb
|
129
|
+
- lib/fast_ci/extract_definitions.rb
|
130
|
+
- lib/fast_ci/rspec_dryrun_formatter.rb
|
131
|
+
- lib/fast_ci/rspec_formatter.rb
|
132
|
+
- lib/fast_ci/rspec_run_formatter.rb
|
133
|
+
- lib/fast_ci/ruby_critic/cli/application.rb
|
134
|
+
- lib/fast_ci/runner_prepend.rb
|
135
|
+
- lib/fast_ci/simple_cov.rb
|
136
|
+
- lib/fast_ci/simple_cov/reporting.rb
|
62
137
|
- lib/fast_ci/version.rb
|
138
|
+
- lib/minitest/reporters/fastci_reporter.rb
|
139
|
+
- lib/minitest/rubyci_plugin.rb
|
63
140
|
homepage: https://github.com/RubyCI/fast_ci_gem
|
64
141
|
licenses:
|
65
142
|
- MIT
|