ruby_ci 0.2.5 → 0.2.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: deccb17205a9125cad4257da4d460cdcc1a254b38259a434813437f17e5ba1e8
4
- data.tar.gz: 96457b78c8cdc5573e998ae65260c850dc2d1385fe21ae6f70592076d6efe728
3
+ metadata.gz: 2441626a4b8a03996716c6932e0914bb851eebd62a39b8ce2c8e5282f3abe906
4
+ data.tar.gz: 2942c029042f0a38d533b8410e280e0fc94cf18b9a8871012f3a5d5328a0f44d
5
5
  SHA512:
6
- metadata.gz: 54b2a36f99862e51470b1ca379da26fb993ea13308418417407bb52210230d18467b9873ba6965c9343422c22811794ed3873186ab496f8fbbbc75941f78c420
7
- data.tar.gz: c28f203e0a2d7756544aa4085c10823ce290d43bee1b73923997f8aae53a8a62c200282f7ea66ef016698ffd60949c0ddb3a4107d7a924322b05248dbcbe5084
6
+ metadata.gz: b2bb8f6a266af27120f648ed3a3225d117a4abea4e0ac1ca5f9453a18389ce388f292aa71bbc2349c7252253d732a07855b37a9751fe28475913973f4a63e5ea
7
+ data.tar.gz: b1a433532873916bfe8b0beef1f5e953a77bc69ed143a6bac1e5c018d1c26724f6aa5eed42b39d9334806ab9eeddcd0532210629577ed461022afa865c9d8c6e
@@ -1,5 +1,28 @@
1
1
  module Minitest
2
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
+
3
26
  class RubyciReporter
4
27
  attr_accessor :tests, :test_results, :ids
5
28
 
@@ -7,16 +30,40 @@ module Minitest
7
30
  @tests = {}
8
31
  @test_results = {}
9
32
  @ids = {}
33
+ @events = []
10
34
 
11
- RubyCI.minitest_ws.on(:enq_request) do
12
- tests
13
- end
35
+ $stdout = StringIO.new()
14
36
 
15
- RubyCI.minitest_ws.on(:deq) do |api_tests|
16
- test_results
37
+ if ENV['RBCI_REMOTE_TESTS'] != 'true'
38
+ RubyCI.minitest_ws.on(:enq_request) do
39
+ tests
40
+ end
41
+
42
+ RubyCI.minitest_ws.on(:deq) do |api_tests|
43
+ test_results
44
+ end
17
45
  end
18
46
  end
19
47
 
48
+ def start
49
+ test_count = Runnable.runnables.sum { |s| s.runnable_methods.count }
50
+ msg('start', { test_count: test_count })
51
+ end
52
+
53
+ def get_output
54
+ return if $stdout.pos == 0
55
+ $stdout.rewind
56
+ res = $stdout.read
57
+ $stdout.flush
58
+ $stdout.rewind
59
+ return unless res
60
+ res.strip.chomp if res.strip.chomp != ""
61
+ end
62
+
63
+ def before_test(test)
64
+ $stdout = StringIO.new()
65
+ end
66
+
20
67
  def prerecord(klass, name)
21
68
  description = test_description(name)
22
69
  path = test_path(klass.name)
@@ -36,6 +83,7 @@ module Minitest
36
83
  end
37
84
 
38
85
  def record(result)
86
+ test_finished(result)
39
87
  description = test_description(result.name)
40
88
  id = ids[description]
41
89
  path = test_path(result.klass)
@@ -61,15 +109,133 @@ module Minitest
61
109
  test_results[path][:file_status] = file_status
62
110
  end
63
111
 
64
- RubyCI.minitest_await
112
+
113
+ if ENV['RBCI_REMOTE_TESTS'] == 'true'
114
+ send_events
115
+ else
116
+ RubyCI.minitest_await
117
+ end
65
118
  end
66
119
 
67
120
  def method_missing(method, *args)
68
121
  return
69
122
  end
123
+
124
+ protected
125
+
126
+ def before_suite(suite)
127
+ end
128
+
129
+ def after_suite(_suite)
130
+ end
131
+
132
+ def record_print_status(test)
133
+ test_name = test.name.gsub(/^test_: /, "test:")
134
+ print pad_test(test_name)
135
+ print_colored_status(test)
136
+ print(" (%.2fs)" % test.time) unless test.time.nil?
137
+ puts
138
+ end
139
+
140
+ def record_print_failures_if_any(test)
141
+ if !test.skipped? && test.failure
142
+ print_info(test.failure, test.error?)
143
+ puts
144
+ end
145
+ end
146
+
147
+ def screenshots_base64(output)
148
+ return unless output
149
+ img_path = output&.scan(/\\[Screenshot Image\\]: (.*)$/)&.flatten&.first&.strip&.chomp ||
150
+ output&.scan(/\\[Screenshot\\]: (.*)$/)&.flatten&.first&.strip&.chomp
151
+
152
+ if img_path && File.exist?(img_path)
153
+ STDOUT.puts "SCREENSHOT!"
154
+ Base64.strict_encode64(File.read(img_path))
155
+ end
156
+ end
157
+
158
+ def test_finished(test)
159
+ output = get_output
160
+
161
+ location = if !test.source_location.join(":").start_with?(::Rails.root.join('vendor').to_s)
162
+ test.source_location.join(":")
163
+ else
164
+ if (file = `cat #{::Rails.root.join('vendor', 'bundle', 'minitest_cache_file').to_s} | grep "#{test.klass} => "`.split(" => ").last&.chomp)
165
+ file + ":"
166
+ else
167
+ file = `grep -rw "#{::Rails.root.to_s}" -e "#{test.klass} "`.split(":").first
168
+ `echo "#{test.klass} => #{file}" >> #{::Rails.root.join('vendor', 'bundle', 'minitest_cache_file').to_s}`
169
+ file + ":"
170
+ end
171
+ end
172
+
173
+ fully_formatted = if test.failure
174
+ fully_formatted = "\n" + test.failure.message.split("\n").first
175
+
176
+ test.failure.backtrace.each do |l|
177
+ if !l["/cache/"]
178
+ fully_formatted << "\n " + cyan + l + "\033[0m"
179
+ end
180
+ end
181
+
182
+ fully_formatted
183
+ end
184
+
185
+ output_inside = output&.split("\n")&.select do |line|
186
+ !line["Screenshot"]
187
+ end&.join("\n")
188
+ event_data = {
189
+ test_class: Suite.new(test.klass),
190
+ test_name: test.name.gsub(/^test_\\d*/, "").gsub(/^test_: /, "test:").gsub(/^_/, "").strip,
191
+ assertions_count: test.assertions,
192
+ location: location,
193
+ status: status(test),
194
+ run_time: test.time,
195
+ fully_formatted: fully_formatted,
196
+ output_inside: output_inside,
197
+ screenshots_base64: [screenshots_base64(output)]
198
+ }
199
+
200
+ msg('test_finished', event_data)
201
+ if ENV['RBCI_REMOTE_TESTS'] == 'true'
202
+ send_events if @events.length >= 10
203
+ end
204
+ end
205
+
206
+ def status(test)
207
+ if test.passed?
208
+ "passed"
209
+ elsif test.error?
210
+ "error"
211
+ elsif test.skipped?
212
+ "skipped"
213
+ elsif test.failure
214
+ "failed"
215
+ else
216
+ raise("Status not found")
217
+ end
218
+ end
70
219
 
71
220
  private
72
221
 
222
+ def msg(event, data)
223
+ @events << ["minitest_#{event}".upcase, data]
224
+ end
225
+
226
+ def send_events
227
+ return unless @events.length > 0
228
+
229
+ json_events = {
230
+ build_id: RubyCI.configuration.orig_build_id,
231
+ compressed_data: Base64.strict_encode64(Zlib::Deflate.deflate(JSON.fast_generate(@events), 9)),
232
+ }
233
+
234
+ RubyCI.send_events(json_events)
235
+
236
+ @events = []
237
+ end
238
+
73
239
  def test_description(name)
74
240
  test_name = name.split('test_').last
75
241
  test_name = test_name[2..-1] if test_name.starts_with?(': ')
@@ -6,11 +6,25 @@ require 'zlib'
6
6
  module RubyCI
7
7
  module Brakeman
8
8
  def self.start
9
+ events = []
10
+ events << ['brakeman_run'.upcase, {}]
9
11
  RubyCI::Brakeman::Commandline.start(output_files: ['tmp/brakeman.json'], ensure_ignore_notes: false)
10
12
 
11
13
  content = File.read('tmp/brakeman.json')
12
14
  compressed_data = ::Base64.strict_encode64(Zlib::Deflate.deflate(content, 9))
13
- RubyCI.report_brakeman(compressed_data, 'passed')
15
+
16
+ events << ['brakeman_exit_status'.upcase, ['0', { exitstatus: 0, stderr: '', output: '', compressed_data: compressed_data ]]
17
+
18
+ if ENV['RBCI_REMOTE_TESTS'] == 'true'
19
+ json_events = {
20
+ build_id: RubyCI.configuration.orig_build_id,
21
+ compressed_data: Base64.strict_encode64(Zlib::Deflate.deflate(JSON.fast_generate(events), 9)),
22
+ }
23
+
24
+ RubyCI.send_events(json_events)
25
+ else
26
+ RubyCI.report_brakeman(compressed_data, 'passed')
27
+ end
14
28
  end
15
29
  end
16
30
  end
@@ -3,7 +3,7 @@
3
3
  module RubyCI
4
4
  class Configuration
5
5
  attr_accessor :run_key, :build_id, :commit_msg, :commit, :branch,
6
- :api_url, :secret_key, :author
6
+ :api_url, :secret_key, :author, :rubyci_main_url, :rubyci_api_url, :orig_build_id
7
7
 
8
8
  def initialize
9
9
  # Settings defaults
@@ -15,6 +15,9 @@ module RubyCI
15
15
  self.api_url = ENV["RUBY_CI_API_URL"] || "api.fast.ci"
16
16
  self.secret_key = ENV.fetch("RUBY_CI_SECRET_KEY")
17
17
  self.author = guess_author
18
+ self.rubyci_main_url = ENV.fetch('RUBYCI_MAIN_URL', 'https://events.ruby.ci')
19
+ self.rubyci_api_url = ENV.fetch('RUBYCI_API_RB_URL', 'https://fast.ruby.ci')
20
+ self.orig_build_id = ENV['RBCI_ORIG_BUILD_ID']
18
21
  end
19
22
 
20
23
  def reset
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+ require_relative "rspec_formatter"
3
+ require_relative "extract_definitions"
4
+
5
+ module RubyCI
6
+ module DryrunRunnerPrepend
7
+ def run(err, out)
8
+ @rspec_started_at = Time.now
9
+ super
10
+ end
11
+
12
+ def exit_code(examples_passed=false)
13
+ run_time = Time.now - (@rspec_started_at || 1.second.ago)
14
+ events = @world.non_example_failure ? [['RSPEC_DRYRUN', { failed_after: run_time, test_env_number: ENV["TEST_ENV_NUMBER"], data: 'error' }]] : [['RSPEC_DRYRUN', { succeed_after: run_time, test_env_number: ENV["TEST_ENV_NUMBER"] }]]
15
+ STDOUT.puts events.inspect
16
+ json_events = {
17
+ build_id: RubyCI.configuration.orig_build_id,
18
+ compressed_data: Base64.strict_encode64(Zlib::Deflate.deflate(JSON.fast_generate(events), 9)),
19
+ }
20
+ RubyCI.send_events(json_events)
21
+
22
+ return @configuration.error_exit_code || @configuration.failure_exit_code if @world.non_example_failure
23
+ return @configuration.failure_exit_code unless examples_passed
24
+
25
+ 0
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyCI
4
+ class RspecDryrunFormatter
5
+ RSpec::Core::Formatters.register self,
6
+ :start,
7
+ :message,
8
+ :example_passed,
9
+ :example_failed,
10
+ :example_pending,
11
+ :example_group_finished,
12
+ :example_group_started,
13
+ :dump_summary,
14
+ :close
15
+
16
+ def initialize(output)
17
+ @output = output
18
+ @current_group_path = []
19
+ @current_file = nil
20
+ @current_file_count = 0
21
+ @events = []
22
+ end
23
+
24
+ def message(message_notification)
25
+ @output.print message_notification.message
26
+ @output.print "\n"
27
+ end
28
+
29
+ def start(example_count)
30
+ msg(:start, { "example_count" => example_count.count, "timestamp" => time_now })
31
+ end
32
+
33
+ def close(*args)
34
+ msg(:close, { "timestamp" => time_now })
35
+ send_events
36
+ end
37
+
38
+ def dump_summary(summary_notification)
39
+ end
40
+
41
+ def time_now
42
+ time_frozen? ? Timecop.return { Time.now } : Time.now
43
+ end
44
+
45
+ def time_frozen?
46
+ return unless defined?(Timecop)
47
+ Timecop.frozen?
48
+ end
49
+
50
+ def example_passed(example_notification)
51
+ example_finished(example_notification)
52
+ @output.print RSpec::Core::Formatters::ConsoleCodes.wrap('.', :success)
53
+ end
54
+
55
+ def example_failed(example_notification)
56
+ example_finished(example_notification)
57
+ @output.print RSpec::Core::Formatters::ConsoleCodes.wrap('F', :failure)
58
+ end
59
+
60
+ def example_pending(example_notification)
61
+ example_finished(example_notification)
62
+ @output.print RSpec::Core::Formatters::ConsoleCodes.wrap('*', :pending)
63
+ end
64
+
65
+ def start_dump(_notification)
66
+ @output.print "\n"
67
+ end
68
+
69
+ def example_group_finished(_group_notification)
70
+ @current_group_path.pop
71
+ if @current_group_path.empty? # its a file
72
+ msg(:file_examples_count, [@current_file, @current_file_count])
73
+ @current_file_count = 0
74
+ @current_file = nil
75
+ end
76
+ end
77
+
78
+ def example_group_started(group_notification)
79
+ if @current_group_path.size == 0
80
+ @current_file = group_notification.group.metadata[:file_path].gsub("./".freeze, "".freeze)
81
+ @current_file_count = 0
82
+ end
83
+ @current_group_path << 1
84
+ end
85
+
86
+ private
87
+
88
+ def example_finished(example_notification)
89
+ @current_file_count += 1
90
+ end
91
+
92
+ def send_events
93
+ return unless @events.length > 0
94
+
95
+ json_events = {
96
+ build_id: RubyCI.configuration.orig_build_id,
97
+ compressed_data: Base64.strict_encode64(Zlib::Deflate.deflate(JSON.fast_generate(@events), 9)),
98
+ }
99
+
100
+ RubyCI.send_events(json_events)
101
+
102
+ @events = []
103
+ end
104
+
105
+ def msg(event, data)
106
+ @events << ["rspec_dryrun_#{event}".upcase, ['0', data]]
107
+ end
108
+
109
+ def get_scope_id(metadata)
110
+ metadata[:scoped_id].split(":").last || raise("No scoped id")
111
+ end
112
+ end
113
+ end
@@ -4,9 +4,57 @@ module RubyCI
4
4
  class RspecFormatter
5
5
  attr_reader :current_test_key
6
6
 
7
- def initialize
8
- @output = {}
7
+ def initialize(output)
8
+ @output = output
9
+ @event_output = {}
9
10
  @is_failed = false
11
+ @current_path = []
12
+ @current_path_started_at = []
13
+ @max_heap_live_num = 0
14
+ @dup_stdout = STDOUT.clone
15
+ @events = []
16
+
17
+ $stdout = StringIO.new()
18
+
19
+ @log_thread = Thread.new do
20
+ loop do
21
+ sleep 10
22
+ check_heap_live_num
23
+ @should_send_events = true
24
+ end
25
+ end
26
+ end
27
+
28
+ def time_now
29
+ time_frozen? ? Timecop.return { Time.now } : Time.now
30
+ end
31
+
32
+ def time_frozen?
33
+ return unless defined?(Timecop)
34
+ Timecop.frozen?
35
+ end
36
+
37
+ def rspec_runner_index
38
+ ENV["TEST_ENV_NUMBER"]
39
+ end
40
+
41
+ def send_events
42
+ @should_send_events = false
43
+
44
+ if @events.length > 0
45
+ json_events = {
46
+ build_id: RubyCI.configuration.orig_build_id,
47
+ compressed_data: Base64.strict_encode64(Zlib::Deflate.deflate(JSON.fast_generate(@events), 9)),
48
+ }
49
+
50
+ RubyCI.send_events(json_events)
51
+
52
+ @events = []
53
+ end
54
+ end
55
+
56
+ def check_heap_live_num
57
+ @max_heap_live_num = [@max_heap_live_num, GC.stat[:heap_live_slots] || GC.stat[:heap_live_num]].max
10
58
  end
11
59
 
12
60
  def passed?
@@ -17,13 +65,100 @@ module RubyCI
17
65
  @current_test_key = value
18
66
  end
19
67
 
68
+ def start(start_notification)
69
+ # $stderr = $stdout
70
+
71
+ data = {
72
+ load_time: start_notification.load_time,
73
+ example_count: start_notification.count,
74
+ started_at: time_now.to_s
75
+ }
76
+
77
+ return if running_only_failed? ||
78
+ running_gem_or_engine? ||
79
+ ENV["EXTRA_SLOWER_RUN"]
80
+
81
+ msg(:start, data)
82
+ end
83
+
84
+ def close(null_notification)
85
+ # check_heap_live_num
86
+ msg(:gc_stat, GC.stat.merge(max_heap_live_num: @max_heap_live_num))
87
+ unless running_only_failed? || ENV["EXTRA_SLOWER_RUN"] || running_gem_or_engine?
88
+ msg(:close, {final_output: get_output})
89
+ end
90
+ send_events
91
+ $stdout = @dup_stdout
92
+ end
93
+
94
+ def example_group_started(group_notification)
95
+ metadata = group_notification.group.metadata
96
+ @current_path_started_at << time_now
97
+
98
+ if @current_path.size == 0
99
+ @example_failed_index = 0
100
+ file_path = metadata[:file_path].gsub("./".freeze, "".freeze)
101
+ file_path = [ENV["DIR_PREFIX"], file_path].join("/") if ENV["DIR_PREFIX"]
102
+ @current_path << file_path
103
+ end
104
+
105
+ @current_path << id(metadata)
106
+
107
+ msg(:group_started, [
108
+ path_with_file(group_notification.group),
109
+ {
110
+ line_number: metadata[:line_number],
111
+ description: metadata[:description],
112
+ }
113
+ ])
114
+ end
115
+
116
+ def example_started(example_notification)
117
+ @output_before = get_output
118
+ end
119
+
120
+ def example_passed(example_notification)
121
+ metadata = example_notification.example.metadata
122
+ broadcast_example_finished(serialize_example(metadata, "passed".freeze), example_notification.example)
123
+ end
124
+
125
+ def example_failed(example_notification)
126
+ @example_failed_index += 1
127
+ metadata = example_notification.example.metadata
128
+ fully_formatted = example_notification.fully_formatted(@example_failed_index, ::RSpec::Core::Formatters::ConsoleCodes)
129
+
130
+ broadcast_example_finished(
131
+ serialize_example(metadata, "failed".freeze, fully_formatted),
132
+ example_notification.example
133
+ )
134
+ end
135
+
136
+ def example_pending(example_notification)
137
+ metadata = example_notification.example.metadata
138
+ broadcast_example_finished(
139
+ serialize_example(metadata, "pending".freeze),
140
+ example_notification.example
141
+ )
142
+ end
143
+
144
+ def example_group_finished(group_notification)
145
+ run_time = time_now - @current_path_started_at.pop
146
+ if (run_time < 0) || (run_time > 2400)
147
+ run_time = 0.525
148
+ end
149
+ msg(:group_finished, [path_with_file(group_notification.group), {run_time: run_time}])
150
+ # msg(:group_finished, [@current_path.map(&:to_s), {run_time: run_time}])
151
+ @current_path.pop
152
+ @current_path.pop if @current_path.size == 1 # Remove the file_path at the beggining
153
+ end
154
+
20
155
  def example_finished(notification)
21
156
  example = notification.example
22
157
  metadata = example.metadata
23
158
 
24
159
  *example_group_ids, example_id = metadata[:scoped_id].split(":")
25
160
 
26
- file_output = @output[current_test_key] ||= {}
161
+ file_output = @event_output[current_test_key] ||= {}
27
162
 
28
163
  example_group = example_group_ids.reduce(file_output) do |output, scope_id|
29
164
  output[scope_id] ||= {}
@@ -49,9 +184,91 @@ module RubyCI
49
184
  end
50
185
 
51
186
  def dump_and_reset
52
- output = @output
53
- @output = {}
54
- output
187
+ event_output = @event_output
188
+ @event_output = {}
189
+ event_output
190
+ end
191
+
192
+ def path_with_file(group)
193
+ file_path = group.parent_groups.last.file_path.gsub("./".freeze, "".freeze)
194
+
195
+ group.metadata[:scoped_id].split(":").unshift(file_path)
196
+ end
197
+
198
+ private
199
+
200
+ def running_gem_or_engine?
201
+ !!ENV["DIR_PREFIX"]
202
+ end
203
+
204
+ def running_only_failed?
205
+ !!ENV["RERUN_FAILED_FILES"]
206
+ end
207
+
208
+ def serialize_example(metadata, status, fully_formatted = nil)
209
+ run_time = metadata[:execution_result].run_time
210
+ if (run_time < 0) || (run_time > 2400)
211
+ run_time = 0.525
212
+ end
213
+
214
+ result = {
215
+ id: id(metadata),
216
+ status: status,
217
+ line_number: metadata[:line_number].to_s,
218
+ description: metadata[:description],
219
+ run_time: run_time,
220
+ fully_formatted: fully_formatted,
221
+ scoped_id: metadata[:scoped_id],
222
+ }.compact
223
+
224
+ result[:gem_or_engine] = true if running_gem_or_engine?
225
+
226
+ if running_only_failed?
227
+ result[:reruned] = true
228
+ elsif status == "failed" && !running_gem_or_engine?
229
+ File.write('tmp/rspec_failures', "#{@current_path.first}[#{metadata[:scoped_id]}]", mode: 'a+')
230
+ end
231
+
232
+ if status == "failed"
233
+ img_path = metadata.dig(:screenshot, :image) ||
234
+ fully_formatted&.scan(/\[Screenshot Image\]: (.*)$/).flatten.first&.strip&.chomp ||
235
+ fully_formatted&.scan(/\[Screenshot\]: (.*)$/).flatten.first&.strip&.chomp
236
+
237
+ if img_path && File.exist?(img_path)
238
+ STDOUT.puts "SCREENSHOT!"
239
+ result[:screenshots_base64] ||= []
240
+ result[:screenshots_base64] << Base64.strict_encode64(File.read(img_path))
241
+ end
242
+ end
243
+ @last_example_finished_at = time_now
244
+ # TODO annalyze this: run_time: metadata[:execution_result].run_time,
245
+ result
246
+ end
247
+
248
+ def msg(event, data)
249
+ @events << ["rspec_#{event}".upcase, [rspec_runner_index, data]]
250
+ end
251
+
252
+ def id(metadata)
253
+ metadata[:scoped_id].split(":").last || raise("No scoped id")
254
+ end
255
+
256
+ def broadcast_example_finished(data, example)
257
+ msg(:example_finished, [
258
+ path_with_file(example.example_group),
259
+ data.merge(output_inside: get_output, output_before: @output_before)
260
+ ])
261
+
262
+ send_events if @should_send_events
263
+ end
264
+
265
+ def get_output
266
+ return if $stdout.pos == 0
267
+ $stdout.rewind
268
+ res = $stdout.read
269
+ $stdout.flush
270
+ $stdout.rewind
271
+ res
55
272
  end
56
273
  end
57
274
  end
@@ -10,6 +10,8 @@ module RubyCI
10
10
  module Cli
11
11
  class Application < ::RubyCritic::Cli::Application
12
12
  def execute
13
+ events = []
14
+ events << ['ruby_critic_run'.upcase, {}]
13
15
  status = super
14
16
 
15
17
  content = File.read('tmp/rubycritic/report.json')
@@ -29,8 +31,18 @@ module RubyCI
29
31
  end
30
32
 
31
33
  compressed_data = ::Base64.strict_encode64(Zlib::Deflate.deflate(report.to_json, 9))
32
- RubyCI.report_ruby_critic(compressed_data, 'passed')
34
+ events << ['ruby_critic_exit_status'.upcase, { exitstatus: status, output: '', compressed_data: compressed_data }]
33
35
 
36
+ if ENV['RBCI_REMOTE_TESTS'] == 'true'
37
+ json_events = {
38
+ build_id: RubyCI.configuration.orig_build_id,
39
+ compressed_data: Base64.strict_encode64(Zlib::Deflate.deflate(JSON.fast_generate(events), 9)),
40
+ }
41
+
42
+ RubyCI.send_events(json_events)
43
+ else
44
+ RubyCI.report_ruby_critic(compressed_data, 'passed')
45
+ end
34
46
  return status
35
47
  end
36
48
  end
@@ -5,6 +5,13 @@ require_relative "extract_definitions"
5
5
  module RubyCI
6
6
  module RunnerPrepend
7
7
  def run_specs(example_groups)
8
+ @rspec_started_at = Time.now
9
+ json_events = {
10
+ build_id: RubyCI.configuration.orig_build_id,
11
+ compressed_data: Base64.strict_encode64(Zlib::Deflate.deflate(JSON.fast_generate([['RSPEC_RUN', { started_at: @rspec_started_at, test_env_number: ENV["TEST_ENV_NUMBER"] }]]), 9)),
12
+ }
13
+ RubyCI.send_events(json_events)
14
+
8
15
  examples_count = @world.example_count(example_groups)
9
16
 
10
17
  example_groups = example_groups.reduce({}) do |acc, ex_group|
@@ -43,9 +50,19 @@ module RubyCI
43
50
  return @configuration.failure_exit_code
44
51
  end
45
52
 
46
- formatter = RubyCI::RspecFormatter.new
53
+ formatter = RubyCI::RspecFormatter.new(STDOUT)
47
54
 
48
55
  reporter.register_listener(formatter, :example_finished)
56
+ if ENV['RBCI_REMOTE_TESTS'] == 'true'
57
+ reporter.register_listener(formatter, :start)
58
+ reporter.register_listener(formatter, :example_group_started)
59
+ reporter.register_listener(formatter, :example_started)
60
+ reporter.register_listener(formatter, :example_passed)
61
+ reporter.register_listener(formatter, :example_failed)
62
+ reporter.register_listener(formatter, :example_pending)
63
+ reporter.register_listener(formatter, :example_group_finished)
64
+ reporter.register_listener(formatter, :close)
65
+ end
49
66
 
50
67
  RubyCI.rspec_ws.on(:deq) do |tests|
51
68
  tests.each do |test|
@@ -71,6 +88,14 @@ module RubyCI
71
88
  end
72
89
 
73
90
  def exit_code(examples_passed=false)
91
+ run_time = Time.now - (@rspec_started_at || 1.second.ago)
92
+ events = @world.non_example_failure ? [['RSPEC_RUN', { failed_after: run_time, test_env_number: ENV["TEST_ENV_NUMBER"] }]] : [['RSPEC_RUN', { succeed_after: run_time, test_env_number: ENV["TEST_ENV_NUMBER"] }]]
93
+ json_events = {
94
+ build_id: RubyCI.configuration.orig_build_id,
95
+ compressed_data: Base64.strict_encode64(Zlib::Deflate.deflate(JSON.fast_generate(events), 9)),
96
+ }
97
+ RubyCI.send_events(json_events)
98
+
74
99
  return @configuration.error_exit_code || @configuration.failure_exit_code if @world.non_example_failure
75
100
  return @configuration.failure_exit_code unless examples_passed
76
101
 
@@ -2,6 +2,67 @@ require_relative "simple_cov/reporting"
2
2
 
3
3
  module RubyCI
4
4
  module SimpleCov
5
- ::SimpleCov.send(:include, RubyCI::SimpleCov::Reporting)
5
+ if ENV['RBCI_REMOTE_TESTS'] == 'true' && ENV["SIMPLECOV_ACTIVE"] && ENV['DRYRUN'] != 'true'
6
+ ::SimpleCov.send(:at_exit) do
7
+ ::SimpleCov.result.format!
8
+
9
+ config = {
10
+ minimum_coverage: ::SimpleCov.minimum_coverage,
11
+ maximum_coverage_drop: ::SimpleCov.maximum_coverage_drop,
12
+ minimum_coverage_by_file: ::SimpleCov.minimum_coverage_by_file,
13
+ }
14
+ rspec_runner_index = ENV["TEST_ENV_NUMBER".freeze].to_i
15
+ events = [['simplecov_config'.upcase, [ rspec_runner_index, config ]]]
16
+
17
+ json_events = {
18
+ build_id: RubyCI.configuration.orig_build_id,
19
+ compressed_data: Base64.strict_encode64(Zlib::Deflate.deflate(JSON.fast_generate(events), 9)),
20
+ }
21
+
22
+ RubyCI.send_events(json_events)
23
+ end
24
+
25
+ module PrependSc
26
+ def start(*args, &block)
27
+ add_filter "tmp"
28
+ merge_timeout 3600
29
+ command_name "RSpec_#{ENV["TEST_ENV_NUMBER".freeze].to_i}"
30
+
31
+ if ENV["NO_COVERAGE"]
32
+ use_merging false
33
+ return
34
+ end
35
+ super
36
+ end
37
+ end
38
+ ::SimpleCov.singleton_class.prepend(PrependSc)
39
+
40
+ module Scf
41
+ def format!
42
+ return if ENV["NO_COVERAGE"]
43
+ rspec_runner_index = ENV["TEST_ENV_NUMBER".freeze].to_i
44
+
45
+ original_result_json = if ENV['CI_PROJECT_DIR'].present?
46
+ JSON.fast_generate(original_result.transform_keys {|key| key.sub(ENV['CI_PROJECT_DIR'], '/app') })
47
+ else
48
+ JSON.fast_generate(original_result)
49
+ end
50
+ compressed_data = Base64.strict_encode64(Zlib::Deflate.deflate(original_result_json, 9))
51
+ events = [['simplecov_result'.upcase, [ rspec_runner_index, compressed_data ]]]
52
+
53
+ json_events = {
54
+ build_id: RubyCI.configuration.orig_build_id,
55
+ compressed_data: Base64.strict_encode64(Zlib::Deflate.deflate(JSON.fast_generate(events), 9)),
56
+ }
57
+
58
+ RubyCI.send_events(json_events)
59
+ super
60
+ end
61
+ end
62
+
63
+ ::SimpleCov::Result.prepend(Scf)
64
+ else
65
+ ::SimpleCov.send(:include, RubyCI::SimpleCov::Reporting) unless ENV['DRYRUN'] == 'true'
66
+ end
6
67
  end
7
68
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyCI
4
- VERSION = "0.2.5"
4
+ VERSION = "0.2.7"
5
5
  end
data/lib/ruby_ci.rb CHANGED
@@ -67,7 +67,12 @@ module RubyCI
67
67
  end
68
68
 
69
69
  def post_report(data)
70
- uri = URI('https://fast.ruby.ci/api/runs')
70
+ uri = URI("#{RubyCI.configuration.rubyci_api_url}/api/runs")
71
+ res = Net::HTTP.post_form(uri, data)
72
+ end
73
+
74
+ def send_events(data)
75
+ uri = URI("#{RubyCI.configuration.rubyci_main_url}/api/v1/gitlab_events")
71
76
  res = Net::HTTP.post_form(uri, data)
72
77
  end
73
78
  end
@@ -142,6 +147,9 @@ module RubyCI
142
147
  else
143
148
  puts response
144
149
  end
150
+ rescue => e
151
+ puts e.message
152
+ puts e.backtrace.join("\n")
145
153
  end
146
154
  end
147
155
  end
data/ruby_ci.gemspec CHANGED
@@ -30,5 +30,6 @@ Gem::Specification.new do |spec|
30
30
  spec.add_dependency "async-websocket", '<= 0.20.0'
31
31
  spec.add_dependency "rubycritic", "~> 4.8.0"
32
32
  spec.add_dependency "brakeman", "~> 5.4.1"
33
+ spec.add_dependency "minitest-rails", ">= 5.1"
33
34
  spec.add_development_dependency "pry"
34
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_ci
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ale ∴
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-29 00:00:00.000000000 Z
11
+ date: 2024-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: console
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
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'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: pry
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -109,8 +123,10 @@ files:
109
123
  - lib/ruby_ci/brakeman.rb
110
124
  - lib/ruby_ci/brakeman/commandline.rb
111
125
  - lib/ruby_ci/configuration.rb
126
+ - lib/ruby_ci/dryrun_runner_prepend.rb
112
127
  - lib/ruby_ci/exceptions.rb
113
128
  - lib/ruby_ci/extract_definitions.rb
129
+ - lib/ruby_ci/rspec_dryrun_formatter.rb
114
130
  - lib/ruby_ci/rspec_formatter.rb
115
131
  - lib/ruby_ci/ruby_critic/cli/application.rb
116
132
  - lib/ruby_ci/runner_prepend.rb