ci-queue 0.78.0 → 0.79.0

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: 68c5b1264396c9d74c0de954e922c38bed02035599ac2a5739f6ff4f5d304ce2
4
- data.tar.gz: 9879b14f07961c581cc6ee98b33e97e9e5ea7ce97ad6be8c114ddb946ab9c26e
3
+ metadata.gz: 3a6bc964bea9e748549dc7e57a2ec4c0207e080fa5d644fac6d75165b88b44cf
4
+ data.tar.gz: 22acfa15e29f811514aea54861ae9f4c422e11d42eadbed7241b030f5a3ed79f
5
5
  SHA512:
6
- metadata.gz: f9791de60dc9e636ce6dca98ff370afad264f95437af6d232df651a7c66b607fc4cb2dbfb9955f3e3f558f7cd16e330548f0a9ef2c1fec67ce56e3157ff2accd
7
- data.tar.gz: 21a6d847e04e2d8cb9b5e21154d29d41040c9000fd809c65d8946478d8dd6a70358d077411dbaa798d17fc495c77a488486930137342354cb9c63860a78c28d9
6
+ metadata.gz: 02b7be5eea0c4f50eacd9caa19bb64f7ab52720deb92897573efad680bf1130aa717f09302b3c6573bd0c7e5eed592ba3acb601cfeb8a2eabbdc9cb422826d2e
7
+ data.tar.gz: dbdca360f7eba2da549559f982c73175302dc5e92f414972f39c8a6fb77de9a95d3dfc783bae4be3a63dcefa2844c69e5fae3842f828dff42d66a2b9058aae64
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ci-queue (0.78.0)
4
+ ci-queue (0.79.0)
5
5
  logger
6
6
 
7
7
  GEM
@@ -2,7 +2,7 @@
2
2
 
3
3
  module CI
4
4
  module Queue
5
- VERSION = '0.78.0'
5
+ VERSION = '0.79.0'
6
6
  DEV_SCRIPTS_ROOT = ::File.expand_path('../../../../../redis', __FILE__)
7
7
  RELEASE_SCRIPTS_ROOT = ::File.expand_path('../redis', __FILE__)
8
8
  end
@@ -153,7 +153,10 @@ module Minitest
153
153
  puts
154
154
 
155
155
  errors = error_reports
156
- puts errors
156
+ if errors.any?
157
+ pretty_print_summary(errors)
158
+ pretty_print_failures(errors)
159
+ end
157
160
 
158
161
  build.worker_errors.to_a.sort.each do |worker_id, error|
159
162
  puts red("Worker #{worker_id } crashed")
@@ -224,6 +227,37 @@ module Minitest
224
227
 
225
228
  attr_reader :build, :supervisor
226
229
 
230
+ def pretty_print_summary(errors)
231
+ test_paths = errors.map(&:test_file).compact
232
+ return unless test_paths.any?
233
+
234
+ file_counts = test_paths.each_with_object(Hash.new(0)) { |path, counts| counts[path] += 1 }
235
+
236
+ puts "\n" + "=" * 80
237
+ puts "FAILED TESTS SUMMARY:"
238
+ puts "=" * 80
239
+ file_counts.sort_by { |path, _| path }.each do |path, count|
240
+ relative_path = Minitest::Queue.relative_path(path)
241
+ if count == 1
242
+ puts " #{relative_path}"
243
+ else
244
+ puts " #{relative_path} (#{count} failures)"
245
+ end
246
+ end
247
+ puts "=" * 80
248
+ end
249
+
250
+ def pretty_print_failures(errors)
251
+ errors.each_with_index do |error, index|
252
+ puts "\n" + "-" * 80
253
+ puts "Error #{index + 1} of #{errors.size}"
254
+ puts "-" * 80
255
+ puts error
256
+ end
257
+
258
+ puts "=" * 80
259
+ end
260
+
227
261
  def timed_out?
228
262
  supervisor.time_left.to_i <= 0
229
263
  end
@@ -1,4 +1,7 @@
1
1
  # frozen_string_literal: true
2
+ require 'rspec/queue/failure_formatter'
3
+ require 'rspec/queue/error_report'
4
+
2
5
  module RSpec
3
6
  module Queue
4
7
  class BuildStatusRecorder
@@ -6,7 +9,9 @@ module RSpec
6
9
 
7
10
  class << self
8
11
  attr_accessor :build
12
+ attr_accessor :failure_formatter
9
13
  end
14
+ self.failure_formatter = FailureFormatter
10
15
 
11
16
  def initialize(*)
12
17
  end
@@ -18,17 +23,13 @@ module RSpec
18
23
 
19
24
  def example_failed(notification)
20
25
  example = notification.example
21
- build.record_error(example.id, [
22
- notification.fully_formatted(nil),
23
- colorized_rerun_command(example),
24
- ].join("\n"))
26
+ build.record_error(example.id, dump(notification))
25
27
  end
26
28
 
27
29
  private
28
30
 
29
- def colorized_rerun_command(example, colorizer=::RSpec::Core::Formatters::ConsoleCodes)
30
- colorizer.wrap("rspec #{example.location_rerun_argument}", RSpec.configuration.failure_color) + " " +
31
- colorizer.wrap("# #{example.full_description}", RSpec.configuration.detail_color)
31
+ def dump(notification)
32
+ ErrorReport.new(self.class.failure_formatter.new(notification).to_h).dump
32
33
  end
33
34
 
34
35
  def build
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+ module RSpec
3
+ module Queue
4
+ class ErrorReport
5
+ class << self
6
+ attr_accessor :coder
7
+
8
+ def load(payload)
9
+ new(coder.load(payload))
10
+ end
11
+ end
12
+
13
+ # Default to Marshal
14
+ self.coder = Marshal
15
+
16
+ # Try to use SnappyPack if available from consumer's bundle
17
+ begin
18
+ require 'snappy'
19
+ require 'msgpack'
20
+ require 'stringio'
21
+
22
+ module SnappyPack
23
+ extend self
24
+
25
+ MSGPACK = MessagePack::Factory.new
26
+ MSGPACK.register_type(0x00, Symbol)
27
+
28
+ def load(payload)
29
+ io = StringIO.new(Snappy.inflate(payload))
30
+ MSGPACK.unpacker(io).unpack
31
+ end
32
+
33
+ def dump(object)
34
+ io = StringIO.new
35
+ packer = MSGPACK.packer(io)
36
+ packer.pack(object)
37
+ packer.flush
38
+ io.rewind
39
+ Snappy.deflate(io.string).force_encoding(Encoding::UTF_8)
40
+ end
41
+ end
42
+
43
+ self.coder = SnappyPack
44
+ rescue LoadError
45
+ end
46
+
47
+ def initialize(data)
48
+ @data = data
49
+ end
50
+
51
+ def dump
52
+ self.class.coder.dump(@data)
53
+ end
54
+
55
+ def test_name
56
+ @data[:test_name]
57
+ end
58
+
59
+ def error_class
60
+ @data[:error_class]
61
+ end
62
+
63
+ def test_and_module_name
64
+ @data[:test_and_module_name]
65
+ end
66
+
67
+ def test_suite
68
+ @data[:test_suite]
69
+ end
70
+
71
+ def test_file
72
+ @data[:test_file]
73
+ end
74
+
75
+ def test_line
76
+ @data[:test_line]
77
+ end
78
+
79
+ def to_h
80
+ @data
81
+ end
82
+
83
+ def to_s
84
+ output
85
+ end
86
+
87
+ def output
88
+ @data[:output]
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+ require 'delegate'
3
+ require 'ci/queue/output_helpers'
4
+
5
+ module RSpec
6
+ module Queue
7
+ class FailureFormatter < SimpleDelegator
8
+ include ::CI::Queue::OutputHelpers
9
+
10
+ def initialize(notification)
11
+ @notification = notification
12
+ super
13
+ end
14
+
15
+ def to_s
16
+ [
17
+ @notification.fully_formatted(nil),
18
+ colorized_rerun_command(@notification.example)
19
+ ].join("\n")
20
+ end
21
+
22
+ def to_h
23
+ example = @notification.example
24
+ {
25
+ test_file: example.file_path,
26
+ test_line: example.metadata[:line_number],
27
+ test_and_module_name: example.id,
28
+ test_name: example.description,
29
+ test_suite: example.example_group.description,
30
+ error_class: @notification.exception.class.name,
31
+ output: to_s,
32
+ }
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader :notification
38
+
39
+ def colorized_rerun_command(example, colorizer=::RSpec::Core::Formatters::ConsoleCodes)
40
+ colorizer.wrap("rspec #{example.location_rerun_argument}", RSpec.configuration.failure_color) + " " +
41
+ colorizer.wrap("# #{example.full_description}", RSpec.configuration.detail_color)
42
+ end
43
+ end
44
+ end
45
+ end
data/lib/rspec/queue.rb CHANGED
@@ -5,6 +5,7 @@ require 'rspec/core'
5
5
  require 'ci/queue'
6
6
  require 'rspec/queue/build_status_recorder'
7
7
  require 'rspec/queue/order_recorder'
8
+ require 'rspec/queue/error_report'
8
9
 
9
10
  module RSpec
10
11
  module Queue
@@ -291,16 +292,56 @@ module RSpec
291
292
  end
292
293
  end
293
294
 
294
- # TODO: better reporting
295
- errors = supervisor.build.error_reports.sort_by(&:first).map(&:last)
295
+ errors = supervisor.build.error_reports.sort_by(&:first).map do |_, error_data|
296
+ RSpec::Queue::ErrorReport.load(error_data)
297
+ end
296
298
  if errors.empty?
297
299
  step(green('No errors found'))
298
300
  0
299
301
  else
300
302
  message = errors.size == 1 ? "1 error found" : "#{errors.size} errors found"
301
303
  step(red(message), collapsed: false)
302
- puts errors
304
+
305
+ pretty_print_summary(errors)
306
+ pretty_print_failures(errors)
303
307
  1
308
+ # Example output
309
+ #
310
+ # FAILED TESTS SUMMARY:
311
+ # =================================================================================
312
+ # ./spec/dummy_spec.rb
313
+ # ./spec/dummy_spec_2.rb (2 failures)
314
+ # ./spec/dummy_spec_3.rb (3 failures)
315
+ # =================================================================================
316
+ #
317
+ # --------------------------------------------------------------------------------
318
+ # Error 1 of 3
319
+ # --------------------------------------------------------------------------------
320
+ #
321
+ # Object doesn't work on first try
322
+ # Failure/Error: expect(1 + 1).to be == 42
323
+ #
324
+ # expected: == 42
325
+ # got: 2
326
+ #
327
+ # --- stacktrace will be here ---
328
+ # --- rerun command will be here ---
329
+ #
330
+ # --------------------------------------------------------------------------------
331
+ # Error 2 of 3
332
+ # --------------------------------------------------------------------------------
333
+ #
334
+ # Object doesn't work on first try
335
+ # Failure/Error: expect(1 + 1).to be == 42
336
+ #
337
+ # expected: == 42
338
+ # got: 2
339
+ #
340
+ # --- stacktrace will be here ---
341
+ # --- rerun command will be here ---
342
+ #
343
+ # ... etc
344
+ # =================================================================================
304
345
  end
305
346
  end
306
347
 
@@ -320,6 +361,38 @@ module RSpec
320
361
  invalid_usage!('Missing --queue parameter') unless queue_url
321
362
  invalid_usage!('Missing --build parameter') unless RSpec::Queue.config.build_id
322
363
  end
364
+
365
+ private
366
+
367
+ def pretty_print_summary(errors)
368
+ test_paths = errors.map(&:test_file).compact
369
+ return unless test_paths.any?
370
+
371
+ file_counts = test_paths.each_with_object(Hash.new(0)) { |path, counts| counts[path] += 1 }
372
+
373
+ puts "\n" + "=" * 80
374
+ puts "FAILED TESTS SUMMARY:"
375
+ puts "=" * 80
376
+ file_counts.sort_by { |path, _| path }.each do |path, count|
377
+ if count == 1
378
+ puts " #{path}"
379
+ else
380
+ puts " #{path} (#{count} failures)"
381
+ end
382
+ end
383
+ puts "=" * 80
384
+ end
385
+
386
+ def pretty_print_failures(errors)
387
+ errors.each_with_index do |error, index|
388
+ puts "\n" + "-" * 80
389
+ puts "Error #{index + 1} of #{errors.size}"
390
+ puts "-" * 80
391
+ puts error.to_s
392
+ end
393
+
394
+ puts "=" * 80
395
+ end
323
396
  end
324
397
 
325
398
  class QueueReporter < SimpleDelegator
@@ -362,7 +435,18 @@ module RSpec
362
435
  invalid_usage!('Missing --queue parameter') unless queue_url
363
436
  invalid_usage!('Missing --build parameter') unless RSpec::Queue.config.build_id
364
437
  invalid_usage!('Missing --worker parameter') unless RSpec::Queue.config.worker_id
365
- RSpec.configuration.backtrace_formatter.filter_gem('ci-queue')
438
+ RSpec.configure do |config|
439
+ config.backtrace_exclusion_patterns = [
440
+ # Filter bundler paths
441
+ %r{/tmp/bundle/},
442
+ # RSpec internals
443
+ %r{/gems/rspec-},
444
+ # ci-queue and rspec-queue internals
445
+ %r{exe/rspec-queue},
446
+ %r{lib/ci/queue/},
447
+ %r{rspec/queue}
448
+ ]
449
+ end
366
450
  end
367
451
 
368
452
  def run_specs(example_groups)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ci-queue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.78.0
4
+ version: 0.79.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean Boussier
@@ -234,6 +234,8 @@ files:
234
234
  - lib/minitest/reporters/statsd_reporter.rb
235
235
  - lib/rspec/queue.rb
236
236
  - lib/rspec/queue/build_status_recorder.rb
237
+ - lib/rspec/queue/error_report.rb
238
+ - lib/rspec/queue/failure_formatter.rb
237
239
  - lib/rspec/queue/order_recorder.rb
238
240
  homepage: https://github.com/Shopify/ci-queue
239
241
  licenses: