parallel_specs 0.9.0 → 0.9.1

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.
@@ -1,31 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'optparse'
4
- require 'fileutils'
5
- require 'pathname'
6
- require 'shellwords'
7
- require 'tmpdir'
3
+ require "optparse"
4
+ require "fileutils"
5
+ require "pathname"
6
+ require "shellwords"
7
+ require "tmpdir"
8
8
 
9
- require 'parallel_specs'
10
- require 'parallel_specs/cli/dashboard'
11
- require 'parallel_specs/rspec/runner'
9
+ require "parallel_specs"
10
+ require "parallel_specs/cli/dashboard"
11
+ require "parallel_specs/rspec/runner"
12
12
 
13
13
  module ParallelSpecs
14
14
  class CLI
15
+ DEFAULT_RERUN_COMMAND_SPEC_FILE_LIMIT = 25
16
+ DEFAULT_RERUN_COMMAND_CHAR_LIMIT = 2_000
17
+
15
18
  def initialize
16
19
  @runner = ParallelSpecs::RSpec::Runner
17
20
  end
18
21
 
19
22
  def run(argv)
20
- Signal.trap('INT') { handle_interrupt }
23
+ Signal.trap("INT") { handle_interrupt }
21
24
 
22
25
  options = parse_options!(argv)
23
- ENV['DISABLE_SPRING'] ||= '1'
26
+ ENV["DISABLE_SPRING"] ||= "1"
24
27
 
25
28
  num_processes = ParallelSpecs.determine_number_of_processes(options[:count])
26
- abort 'Process count must be greater than 0' unless num_processes.positive?
29
+ abort "Process count must be greater than 0" unless num_processes.positive?
27
30
 
28
31
  run_tests_in_parallel(num_processes, options)
32
+ rescue ParallelSpecs::ConfigurationError => e
33
+ abort e.message
34
+ rescue ParallelSpecs::Test::Runner::MissingTestFileError => e
35
+ abort e.message
29
36
  end
30
37
 
31
38
  private
@@ -137,7 +144,7 @@ module ParallelSpecs
137
144
  runtime_log = options[:runtime_log] || @runner.runtime_log
138
145
  should_merge_runtime_logs = false
139
146
 
140
- Dir.mktmpdir('parallel_specs-runtime') do |dir|
147
+ Dir.mktmpdir("parallel_specs-runtime") do |dir|
141
148
  runtime_log_files = groups.each_index.to_h do |index|
142
149
  [index, File.join(dir, "worker-#{index + 1}.log")]
143
150
  end
@@ -162,13 +169,13 @@ module ParallelSpecs
162
169
 
163
170
  missing_logs = runtime_log_files.values.reject { |path| File.file?(path) }
164
171
  unless missing_logs.empty?
165
- warn "parallel_specs: not updating runtime log #{runtime_log}; missing worker runtime logs: #{missing_logs.join(', ')}"
172
+ warn "parallel_specs: not updating runtime log #{runtime_log}; missing worker runtime logs: #{missing_logs.join(", ")}"
166
173
  return false
167
174
  end
168
175
 
169
176
  FileUtils.mkdir_p(File.dirname(runtime_log))
170
177
  temporary_runtime_log = "#{runtime_log}.#{Process.pid}.tmp"
171
- File.open(temporary_runtime_log, 'w') do |output|
178
+ File.open(temporary_runtime_log, "w") do |output|
172
179
  runtime_log_files.each_value do |path|
173
180
  File.foreach(path) { |line| output.write(line) }
174
181
  end
@@ -182,10 +189,10 @@ module ParallelSpecs
182
189
  def with_dashboard(groups, options)
183
190
  return yield unless options[:dashboard]
184
191
 
185
- Dir.mktmpdir('parallel_specs-dashboard') do |dir|
192
+ Dir.mktmpdir("parallel_specs-dashboard") do |dir|
186
193
  event_files = groups.each_index.to_h do |index|
187
194
  path = File.join(dir, "worker-#{index + 1}.jsonl")
188
- File.write(path, '')
195
+ File.write(path, "")
189
196
  [index, path]
190
197
  end
191
198
 
@@ -193,7 +200,7 @@ module ParallelSpecs
193
200
  options[:dashboard_runner] = ParallelSpecs::CLI::Dashboard.new(
194
201
  groups: groups,
195
202
  event_files: event_files,
196
- mode: dashboard_mode,
203
+ mode: dashboard_mode(options),
197
204
  use_colors: use_colors?
198
205
  )
199
206
 
@@ -216,8 +223,8 @@ module ParallelSpecs
216
223
 
217
224
  puts "\nFailed worker output:\n"
218
225
  failures.each do |result|
219
- worker_label = result.dig(:env, 'TEST_ENV_NUMBER')
220
- worker_label = '1' if worker_label.to_s.empty?
226
+ worker_label = result.dig(:env, "TEST_ENV_NUMBER")
227
+ worker_label = "1" if worker_label.to_s.empty?
221
228
  puts "--- worker #{worker_label} ---"
222
229
  puts result[:stdout]
223
230
  end
@@ -227,18 +234,79 @@ module ParallelSpecs
227
234
  failures = test_results.reject { |result| result[:exit_status].zero? }
228
235
  return if failures.empty?
229
236
 
230
- puts "\nRerun failed worker commands:\n"
231
- failures.each do |result|
232
- command = @runner.rerun_command(result[:command], seed: result[:seed])
233
- @runner.print_command(command, result[:env] || {})
237
+ rerun_commands = failures.map do |result|
238
+ {result: result, command: @runner.rerun_command(result[:command], seed: result[:seed])}
239
+ end
240
+
241
+ if print_full_rerun_commands?(rerun_commands)
242
+ puts "\nRerun failed worker commands:\n"
243
+ rerun_commands.each do |entry|
244
+ @runner.print_command(entry[:command], entry[:result][:env] || {})
245
+ end
246
+ else
247
+ report_failure_rerun_command_summary(rerun_commands)
248
+ end
249
+ end
250
+
251
+ def print_full_rerun_commands?(rerun_commands)
252
+ return true if truthy_env?("PARALLEL_SPECS_FULL_RERUN_COMMANDS")
253
+
254
+ rerun_commands.all? do |entry|
255
+ rerun_command_spec_file_count(entry[:command]) <= rerun_command_spec_file_limit &&
256
+ rerun_command_length(entry[:command], entry[:result][:env] || {}) <= rerun_command_char_limit
257
+ end
258
+ end
259
+
260
+ def report_failure_rerun_command_summary(rerun_commands)
261
+ total_spec_files = rerun_commands.sum { |entry| rerun_command_spec_file_count(entry[:command]) }
262
+
263
+ puts "\nFull worker rerun commands omitted to keep failure output readable."
264
+ puts "#{pluralize(rerun_commands.size, "failed worker")} included #{pluralize(total_spec_files, @runner.test_file_name)}."
265
+ puts "RSpec failure output above includes failed example locations."
266
+ puts "Set PARALLEL_SPECS_FULL_RERUN_COMMANDS=1 to print full worker rerun commands."
267
+
268
+ rerun_commands.each do |entry|
269
+ result = entry[:result]
270
+ worker_label = result.dig(:env, "TEST_ENV_NUMBER")
271
+ worker_label = "1" if worker_label.to_s.empty?
272
+ seed = result[:seed] ? ", seed #{result[:seed]}" : ""
273
+ puts "worker #{worker_label}: #{pluralize(rerun_command_spec_file_count(entry[:command]), @runner.test_file_name)}#{seed}"
234
274
  end
235
275
  end
236
276
 
277
+ def rerun_command_spec_file_count(command)
278
+ command.count { |arg| arg.end_with?("_spec.rb") }
279
+ end
280
+
281
+ def rerun_command_length(command, env)
282
+ rerun_env = env.slice("TEST_ENV_NUMBER", "PARALLEL_SPECS_GROUPS").reject { |_key, value| value.to_s.empty? }
283
+ env_string = rerun_env.map { |key, value| "#{key}=#{Shellwords.escape(value)}" }.join(" ")
284
+ [env_string, Shellwords.shelljoin(command)].reject(&:empty?).join(" ").length
285
+ end
286
+
287
+ def rerun_command_spec_file_limit
288
+ positive_integer_env("PARALLEL_SPECS_RERUN_COMMAND_SPEC_FILE_LIMIT") || DEFAULT_RERUN_COMMAND_SPEC_FILE_LIMIT
289
+ end
290
+
291
+ def rerun_command_char_limit
292
+ positive_integer_env("PARALLEL_SPECS_RERUN_COMMAND_CHAR_LIMIT") || DEFAULT_RERUN_COMMAND_CHAR_LIMIT
293
+ end
294
+
295
+ def positive_integer_env(name)
296
+ Integer(ENV.fetch(name, nil)).then { |value| value.positive? ? value : nil }
297
+ rescue ArgumentError, TypeError
298
+ nil
299
+ end
300
+
301
+ def truthy_env?(name)
302
+ %w[1 true yes].include?(ENV.fetch(name, "").downcase)
303
+ end
304
+
237
305
  def report_number_of_tests(groups)
238
306
  num_processes = groups.size
239
307
  num_tests = groups.map(&:size).sum
240
308
  tests_per_process = num_processes.zero? ? 0 : num_tests / num_processes
241
- puts "#{pluralize(num_processes, 'process')} for #{pluralize(num_tests, @runner.test_file_name)}, ~ #{pluralize(tests_per_process, @runner.test_file_name)} per process"
309
+ puts "#{pluralize(num_processes, "process")} for #{pluralize(num_tests, @runner.test_file_name)}, ~ #{pluralize(tests_per_process, @runner.test_file_name)} per process"
242
310
  end
243
311
 
244
312
  def any_test_failed?(test_results)
@@ -251,7 +319,8 @@ module ParallelSpecs
251
319
 
252
320
  def parse_options!(argv)
253
321
  newline_padding = 33
254
- options = { dashboard: true }
322
+ options = {dashboard: true}
323
+ cli_argv, rspec_argv = split_rspec_args(argv)
255
324
 
256
325
  OptionParser.new do |opts|
257
326
  opts.banner = <<~BANNER
@@ -266,48 +335,60 @@ module ParallelSpecs
266
335
  Options are:
267
336
  BANNER
268
337
 
269
- opts.on('-n PROCESSES', Integer, 'How many processes to use, default: available CPUs') { |n| options[:count] = n }
270
- opts.on('-o', '--test-options OPTIONS', 'Pass these options to rspec') { |arg| options[:test_options] = Shellwords.shellsplit(arg) }
271
- opts.on('--group-by TYPE', heredoc(<<~TEXT, newline_padding)) { |type| options[:group_by] = type.to_sym }
338
+ opts.on("-n PROCESSES", Integer, "How many processes to use, default: available CPUs") { |n| options[:count] = n }
339
+ opts.on("-o", "--test-options OPTIONS", "Pass these options to rspec") { |arg| options[:test_options] = Shellwords.shellsplit(arg) }
340
+ opts.on("--group-by TYPE", heredoc(<<~TEXT, newline_padding)) { |type| options[:group_by] = type.to_sym }
272
341
  group specs by:
273
342
  found - order of finding files
274
343
  filesize - by size of the file
275
344
  runtime - info from runtime log
276
345
  default - runtime when runtime log is filled otherwise filesize
277
346
  TEXT
278
- opts.on('--pattern PATTERN', 'Only run spec files matching PATTERN') { |pattern| options[:pattern] = Regexp.new(pattern) }
279
- opts.on('--exclude-pattern PATTERN', 'Skip spec files matching PATTERN') { |pattern| options[:exclude_pattern] = Regexp.new(pattern) }
280
- opts.on('--runtime-log PATH', 'Read spec runtimes from PATH; with --record-runtime, write the completed run there') { |path| options[:runtime_log] = path }
281
- opts.on('--allowed-missing COUNT', Integer, 'Allowed percentage of missing runtimes (default = 50)') { |percent| options[:allowed_missing_percent] = percent }
282
- opts.on('--unknown-runtime SECONDS', Float, 'Use given number as unknown runtime (otherwise use average time)') { |time| options[:unknown_runtime] = time }
283
- opts.on('--record-runtime', 'Record runtimes and replace the runtime log only after a successful complete run') { options[:record_runtime] = true }
284
- opts.on('--fail-fast', 'Stop remaining workers after one worker fails') { options[:fail_fast] = true }
285
- opts.on('-v', '--version', 'Show version') { puts ParallelSpecs::VERSION; exit 0 }
286
- opts.on('-h', '--help', 'Show this help') { puts opts; exit 0 }
287
- end.parse!(argv)
347
+ opts.on("--dashboard-mode MODE", %w[interactive plain], "Dashboard mode: interactive or plain") { |mode| options[:dashboard_mode] = mode.to_sym }
348
+ opts.on("--plain-dashboard", "Use the plain text dashboard output") { options[:dashboard_mode] = :plain }
349
+ opts.on("--plain", "Use the plain text dashboard output") { options[:dashboard_mode] = :plain }
350
+ opts.on("--pattern PATTERN", "Only run spec files matching PATTERN") { |pattern| options[:pattern] = Regexp.new(pattern) }
351
+ opts.on("--exclude-pattern PATTERN", "Skip spec files matching PATTERN") { |pattern| options[:exclude_pattern] = Regexp.new(pattern) }
352
+ opts.on("--runtime-log PATH", "Read spec runtimes from PATH; with --record-runtime, write the completed run there") { |path| options[:runtime_log] = path }
353
+ opts.on("--allowed-missing COUNT", Integer, "Allowed percentage of missing runtimes (default = 50)") { |percent| options[:allowed_missing_percent] = percent }
354
+ opts.on("--unknown-runtime SECONDS", Float, "Use given number as unknown runtime (otherwise use average time)") { |time| options[:unknown_runtime] = time }
355
+ opts.on("--record-runtime", "Record runtimes and replace the runtime log only after a successful complete run") { options[:record_runtime] = true }
356
+ opts.on("--fail-fast", "Stop remaining workers after one worker fails") { options[:fail_fast] = true }
357
+ opts.on("-v", "--version", "Show version") {
358
+ puts ParallelSpecs::VERSION
359
+ exit 0
360
+ }
361
+ opts.on("-h", "--help", "Show this help") {
362
+ puts opts
363
+ exit 0
364
+ }
365
+ end.parse!(cli_argv)
288
366
 
289
367
  options[:dashboard] = !options[:record_runtime]
290
368
 
291
- files, remaining = extract_file_paths(argv)
369
+ files, remaining = extract_file_paths(cli_argv, rspec_argv)
292
370
  files = [@runner.default_test_folder] if files.empty?
293
371
  options[:files] = files.map { |file_path| Pathname.new(file_path).cleanpath.to_s }
294
372
  append_test_options(options, remaining)
295
373
  options
296
374
  end
297
375
 
298
- def extract_file_paths(argv)
299
- dash_index = argv.rindex('--')
300
- file_args_at = (dash_index || -1) + 1
301
- [argv[file_args_at..], argv[0...(dash_index || 0)]]
376
+ def split_rspec_args(argv)
377
+ dash_index = argv.index("--")
378
+ return [argv, []] unless dash_index
379
+
380
+ [argv[0...dash_index], argv[(dash_index + 1)..]]
302
381
  end
303
382
 
304
- def extract_test_options(argv)
305
- dash_index = argv.index('--') || -1
306
- argv[dash_index + 1..]
383
+ def extract_file_paths(argv, rspec_argv)
384
+ dash_index = rspec_argv.index("--")
385
+ return [argv, rspec_argv] unless dash_index
386
+
387
+ [argv + rspec_argv[(dash_index + 1)..], rspec_argv[0...dash_index]]
307
388
  end
308
389
 
309
390
  def append_test_options(options, argv)
310
- new_opts = extract_test_options(argv)
391
+ new_opts = argv
311
392
  return if new_opts.empty?
312
393
 
313
394
  options[:test_options] ||= []
@@ -316,18 +397,18 @@ module ParallelSpecs
316
397
 
317
398
  def report_time_taken(&block)
318
399
  seconds = ParallelSpecs.delta(&block).to_i
319
- puts "\nTook #{pluralize(seconds, 'second')}#{detailed_duration(seconds)}"
400
+ puts "\nTook #{pluralize(seconds, "second")}#{detailed_duration(seconds)}"
320
401
  end
321
402
 
322
403
  def detailed_duration(seconds)
323
404
  parts = [seconds / 3600, (seconds % 3600) / 60, seconds % 60].drop_while(&:zero?)
324
405
  return if parts.size < 2
325
406
 
326
- " (#{parts.map { |part| format('%02d', part) }.join(':').sub(/^0/, '')})"
407
+ " (#{parts.map { |part| format("%02d", part) }.join(":").sub(/^0/, "")})"
327
408
  end
328
409
 
329
410
  def final_fail_message
330
- message = 'Specs Failed'
411
+ message = "Specs Failed"
331
412
  use_colors? ? "\e[31m#{message}\e[0m" : message
332
413
  end
333
414
 
@@ -339,11 +420,13 @@ module ParallelSpecs
339
420
  options[:dashboard_runner]&.plain?
340
421
  end
341
422
 
342
- def dashboard_mode
343
- override = ENV['PARALLEL_SPECS_DASHBOARD_MODE']
423
+ def dashboard_mode(options = {})
424
+ return options[:dashboard_mode] if options[:dashboard_mode]
425
+
426
+ override = ENV["PARALLEL_SPECS_DASHBOARD_MODE"]
344
427
  return override.to_sym if %w[interactive plain].include?(override)
345
428
 
346
- if ENV['CI'] || !$stdout.tty?
429
+ if ENV["CI"] || !$stdout.tty?
347
430
  :plain
348
431
  else
349
432
  :interactive
@@ -354,10 +437,10 @@ module ParallelSpecs
354
437
  return yield unless simulate
355
438
 
356
439
  progress_indicator = Thread.new do
357
- interval = Float(ENV['PARALLEL_SPECS_HEARTBEAT_INTERVAL'] || 60)
440
+ interval = Float(ENV["PARALLEL_SPECS_HEARTBEAT_INTERVAL"] || 60)
358
441
  loop do
359
442
  sleep interval
360
- $stdout.print '.'
443
+ $stdout.print "."
361
444
  $stdout.flush
362
445
  end
363
446
  end
@@ -368,12 +451,12 @@ module ParallelSpecs
368
451
  end
369
452
 
370
453
  def heredoc(text, newline_padding)
371
- text.rstrip.gsub("\n", "\n#{' ' * newline_padding}")
454
+ text.rstrip.gsub("\n", "\n#{" " * newline_padding}")
372
455
  end
373
456
 
374
457
  def pluralize(number, singular)
375
458
  return "1 #{singular}" if number == 1
376
- return "#{number} #{singular}es" if singular.end_with?('s', 'sh', 'ch', 'x', 'z')
459
+ return "#{number} #{singular}es" if singular.end_with?("s", "sh", "ch", "x", "z")
377
460
 
378
461
  "#{number} #{singular}s"
379
462
  end
@@ -4,12 +4,12 @@ module ParallelSpecs
4
4
  class Grouper
5
5
  class << self
6
6
  def in_even_groups_by_size(items, num_groups, _options = {})
7
- groups = Array.new(num_groups) { { items: [], size: 0 } }
7
+ groups = Array.new(num_groups) { {items: [], size: 0} }
8
8
 
9
9
  items_to_group(items).each do |item, size|
10
10
  group = groups.min_by { |entry| entry[:size] }
11
11
  group[:items] << item
12
- group[:size] += (size || 1)
12
+ group[:size] += size || 1
13
13
  end
14
14
 
15
15
  groups.map { |group| group[:items].sort }
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'json'
3
+ require "json"
4
4
 
5
5
  module ParallelSpecs
6
6
  class Pids
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "parallel_specs"
4
+
5
+ module ParallelSpecs
6
+ class Railtie < ::Rails::Railtie
7
+ rake_tasks do
8
+ require "parallel_specs/tasks"
9
+ end
10
+ end
11
+ end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'fileutils'
4
- require 'json'
5
- require 'rspec/core'
6
- require 'rspec/core/formatters/base_text_formatter'
3
+ require "fileutils"
4
+ require "json"
5
+ require "rspec/core"
6
+ require "rspec/core/formatters/base_text_formatter"
7
7
 
8
8
  module ParallelSpecs
9
9
  module RSpec
@@ -23,32 +23,32 @@ class ParallelSpecs::RSpec::DashboardLogger < RSpec::Core::Formatters::BaseTextF
23
23
  def initialize(output)
24
24
  super
25
25
 
26
- path = ENV['PARALLEL_SPECS_DASHBOARD_EVENT_LOG']
27
- raise 'A dashboard event log env var is required for DashboardLogger' if path.to_s.empty?
26
+ path = ENV["PARALLEL_SPECS_DASHBOARD_EVENT_LOG"]
27
+ raise "A dashboard event log env var is required for DashboardLogger" if path.to_s.empty?
28
28
 
29
29
  FileUtils.mkdir_p(File.dirname(path))
30
- @event_output = File.open(path, 'a')
30
+ @event_output = File.open(path, "a")
31
31
  @event_output.sync = true
32
32
  end
33
33
 
34
34
  def start(notification)
35
- emit(event: 'start', total: notification.count)
35
+ emit(event: "start", total: notification.count)
36
36
  end
37
37
 
38
38
  def example_started(notification)
39
- emit_example('example_started', notification)
39
+ emit_example("example_started", notification)
40
40
  end
41
41
 
42
42
  def example_passed(notification)
43
- emit_example('example_passed', notification)
43
+ emit_example("example_passed", notification)
44
44
  end
45
45
 
46
46
  def example_pending(notification)
47
- emit_example('example_pending', notification)
47
+ emit_example("example_pending", notification)
48
48
  end
49
49
 
50
50
  def example_failed(notification)
51
- emit_example('example_failed', notification)
51
+ emit_example("example_failed", notification)
52
52
  end
53
53
 
54
54
  def close(*)
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'fileutils'
4
- require 'rspec/core'
5
- require 'rspec/core/formatters/base_text_formatter'
3
+ require "fileutils"
4
+ require "rspec/core"
5
+ require "rspec/core/formatters/base_text_formatter"
6
6
 
7
7
  module ParallelSpecs
8
8
  module RSpec
@@ -17,11 +17,11 @@ class ParallelSpecs::RSpec::LoggerBase < RSpec::Core::Formatters::BaseTextFormat
17
17
  case @output
18
18
  when String
19
19
  FileUtils.mkdir_p(File.dirname(@output))
20
- File.open(@output, 'w') {}
21
- @output = File.open(@output, 'a')
20
+ File.open(@output, "w") {}
21
+ @output = File.open(@output, "a")
22
22
  when File
23
23
  @output.close
24
- @output = File.open(@output.path, 'a')
24
+ @output = File.open(@output.path, "a")
25
25
  end
26
26
  end
27
27
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'parallel_specs/test/runner'
3
+ require "parallel_specs/test/runner"
4
4
 
5
5
  module ParallelSpecs
6
6
  module RSpec
@@ -16,15 +16,15 @@ module ParallelSpecs
16
16
  end
17
17
 
18
18
  def runtime_log
19
- 'tmp/parallel_runtime_rspec.log'
19
+ "tmp/parallel_runtime_rspec.log"
20
20
  end
21
21
 
22
22
  def default_test_folder
23
- 'spec'
23
+ "spec"
24
24
  end
25
25
 
26
26
  def test_file_name
27
- 'spec'
27
+ "spec"
28
28
  end
29
29
 
30
30
  def line_is_result?(line)
@@ -36,9 +36,9 @@ module ParallelSpecs
36
36
  return text unless $stdout.tty?
37
37
 
38
38
  sums = send(:sum_up_results, results)
39
- color_code = if sums['failure'] > 0
39
+ color_code = if sums["failure"] > 0
40
40
  31
41
- elsif sums['pending'] > 0
41
+ elsif sums["pending"] > 0
42
42
  33
43
43
  else
44
44
  32
@@ -52,7 +52,7 @@ module ParallelSpecs
52
52
  end
53
53
 
54
54
  def command_with_seed(command, seed)
55
- [*remove_command_arguments(command, '--seed', '--order'), '--seed', seed]
55
+ [*remove_command_arguments(command, "--seed", "--order"), "--seed", seed]
56
56
  end
57
57
 
58
58
  private
@@ -69,17 +69,17 @@ module ParallelSpecs
69
69
  end
70
70
 
71
71
  def remove_rerun_only_formatters(command)
72
- remove_formatter(command, 'ParallelSpecs::RSpec::DashboardLogger')
73
- .then { |cmd| remove_formatter(cmd, 'ParallelSpecs::RSpec::RuntimeLogger') }
72
+ remove_formatter(command, "ParallelSpecs::RSpec::DashboardLogger")
73
+ .then { |cmd| remove_formatter(cmd, "ParallelSpecs::RSpec::RuntimeLogger") }
74
74
  end
75
75
 
76
76
  def remove_formatter(command, formatter)
77
77
  cleaned = []
78
78
  index = 0
79
79
  while index < command.length
80
- if command[index] == '--format' && command[index + 1] == formatter
80
+ if command[index] == "--format" && command[index + 1] == formatter
81
81
  index += 2
82
- elsif command[index] == '--out' && command[index - 2] == '--format' && command[index - 1] == formatter
82
+ elsif command[index] == "--out" && command[index - 2] == "--format" && command[index - 1] == formatter
83
83
  index += 2
84
84
  else
85
85
  cleaned << command[index]
@@ -90,12 +90,12 @@ module ParallelSpecs
90
90
  end
91
91
 
92
92
  def executable
93
- if File.exist?('bin/rspec')
94
- ParallelSpecs.with_ruby_binary('bin/rspec')
93
+ if File.exist?("bin/rspec")
94
+ ParallelSpecs.with_ruby_binary("bin/rspec")
95
95
  elsif ParallelSpecs.bundler_enabled?
96
96
  %w[bundle exec rspec]
97
97
  else
98
- ['rspec']
98
+ ["rspec"]
99
99
  end
100
100
  end
101
101
 
@@ -104,7 +104,7 @@ module ParallelSpecs
104
104
  end
105
105
 
106
106
  def dashboard_formatter(options)
107
- ['--format', 'ParallelSpecs::RSpec::DashboardLogger'] if options[:dashboard]
107
+ ["--format", "ParallelSpecs::RSpec::DashboardLogger"] if options[:dashboard]
108
108
  end
109
109
 
110
110
  def record_runtime_formatters(process_number, options)
@@ -114,7 +114,7 @@ module ParallelSpecs
114
114
  options[:runtime_log] || runtime_log
115
115
  end
116
116
 
117
- ['--format', 'progress', '--format', 'ParallelSpecs::RSpec::RuntimeLogger', '--out', runtime_log_path]
117
+ ["--format", "progress", "--format", "ParallelSpecs::RSpec::RuntimeLogger", "--out", runtime_log_path]
118
118
  end
119
119
  end
120
120
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'parallel_specs'
4
- require 'parallel_specs/rspec/logger_base'
3
+ require "parallel_specs"
4
+ require "parallel_specs/rspec/logger_base"
5
5
 
6
6
  class ParallelSpecs::RSpec::RuntimeLogger < ParallelSpecs::RSpec::LoggerBase
7
7
  RSpec::Core::Formatters.register(self, :example_group_started, :example_group_finished, :start_dump)
@@ -26,18 +26,27 @@ class ParallelSpecs::RSpec::RuntimeLogger < ParallelSpecs::RSpec::LoggerBase
26
26
  super if defined?(super)
27
27
  end
28
28
 
29
- def seed(*); end
30
- def dump_summary(*); end
31
- def dump_failures(*); end
32
- def dump_failure(*); end
33
- def dump_pending(*); end
29
+ def seed(*)
30
+ end
31
+
32
+ def dump_summary(*)
33
+ end
34
+
35
+ def dump_failures(*)
36
+ end
37
+
38
+ def dump_failure(*)
39
+ end
40
+
41
+ def dump_pending(*)
42
+ end
34
43
 
35
44
  def start_dump(*)
36
- return unless ENV['TEST_ENV_NUMBER']
45
+ return unless ENV["TEST_ENV_NUMBER"]
37
46
 
38
47
  lock_output do
39
48
  @example_times.sort_by(&:last).reverse_each do |file, time|
40
- relative_path = file.sub(%r{^#{Regexp.escape(Dir.pwd)}/}, '').sub(%r{^\./}, '')
49
+ relative_path = file.sub(%r{^#{Regexp.escape(Dir.pwd)}/}, "").sub(%r{^\./}, "")
41
50
  @output.puts "#{relative_path}:#{[time, 0].max}"
42
51
  end
43
52
  end