parallel_specs 0.9.1 → 0.9.2

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: 7220b40d98f5c203c37cc69d12e9145e909dd4877d35e77fb0ae011f23ab3d3e
4
- data.tar.gz: 40eadee9e0eb4748c3c17ad8c4b0bf016328c4564d655e014c8a0e22fbc5ae81
3
+ metadata.gz: 3cd867c0ba3d8a33ab05fb0a4f6690750fbeeecf4b2fd2e149cd649545aa27b2
4
+ data.tar.gz: bc1de229e2308c537a09bca00ac8dd70f7b085e91a6327b9e01cca89336e4812
5
5
  SHA512:
6
- metadata.gz: 83ae2b21bd87c2445be0a1af045df3a2e0563a84eded7c62d08cb47792f7bc73d55f6416dea0aaa37b3ae49ebac3876804eb391c5219ff4c521e88074188aed5
7
- data.tar.gz: 12bef5dbb566c689b5721f5a88339a69c3936eae64f1251977b4e1c847de2ab41c5e518d911ea31a4405321bbf9a2fabc6dd35d5942cc44ce35c7ec0e0015d76
6
+ metadata.gz: 62156a6183d0e584b235a22ea195bacfde07b7a3ef5b1a5744c4a9a4d0cd445b10ca99311fd22357fcea58104763fa76c642e268add3fcfae45339e7ab5b9d4b
7
+ data.tar.gz: 18d8f259aaf40b753c8b2f7cf2472b0a36d0a2b4a24095446da00cad529f62d66209fb5195036fccb2a9efc796075eb46d5e92623ad750c5fa7bd7c1a6ad5a32
data/README.md CHANGED
@@ -71,6 +71,22 @@ bundle exec parallel_specs --record-runtime --runtime-log tmp/my_runtime.log
71
71
 
72
72
  `--runtime-log PATH` is used as the input path for balancing and, with `--record-runtime`, as the output destination for the completed run.
73
73
 
74
+ ## Keeping specs on dedicated workers
75
+
76
+ Use `--single` with `--isolate` to keep matching specs together on a dedicated worker. For example, on a 16-worker run:
77
+
78
+ ```bash
79
+ bundle exec parallel_specs -n 16 --single spec/features --isolate
80
+ ```
81
+
82
+ All files matching `spec/features` run sequentially on worker 1, while workers 2–16 handle the remaining specs. If `--isolate` is omitted, runtime balancing can add ordinary specs to the worker running the singled specs.
83
+
84
+ `--single` is repeatable when more than one pattern should use the singled worker. To spread singled specs across two dedicated workers instead, use `--isolate-n 2`:
85
+
86
+ ```bash
87
+ bundle exec parallel_specs -n 16 --single spec/features --isolate-n 2
88
+ ```
89
+
74
90
  ## Rails database tasks
75
91
 
76
92
  Rails apps that use `TEST_ENV_NUMBER` in `config/database.yml` can prepare per-worker test databases without depending on `parallel_tests`.
@@ -344,6 +344,13 @@ module ParallelSpecs
344
344
  runtime - info from runtime log
345
345
  default - runtime when runtime log is filled otherwise filesize
346
346
  TEXT
347
+ opts.on("-s PATTERN", "--single PATTERN", "Run all matching spec files in the same process") do |pattern|
348
+ (options[:single_process] ||= []) << Regexp.new(pattern)
349
+ end
350
+ opts.on("-i", "--isolate", "Do not run other specs in workers reserved by --single") { options[:isolate] = true }
351
+ opts.on("--isolate-n PROCESSES", Integer, "Spread --single specs across this many isolated workers") do |count|
352
+ options[:isolate_count] = count
353
+ end
347
354
  opts.on("--dashboard-mode MODE", %w[interactive plain], "Dashboard mode: interactive or plain") { |mode| options[:dashboard_mode] = mode.to_sym }
348
355
  opts.on("--plain-dashboard", "Use the plain text dashboard output") { options[:dashboard_mode] = :plain }
349
356
  opts.on("--plain", "Use the plain text dashboard output") { options[:dashboard_mode] = :plain }
@@ -364,8 +371,6 @@ module ParallelSpecs
364
371
  }
365
372
  end.parse!(cli_argv)
366
373
 
367
- options[:dashboard] = !options[:record_runtime]
368
-
369
374
  files, remaining = extract_file_paths(cli_argv, rspec_argv)
370
375
  files = [@runner.default_test_folder] if files.empty?
371
376
  options[:files] = files.map { |file_path| Pathname.new(file_path).cleanpath.to_s }
@@ -3,13 +3,27 @@
3
3
  module ParallelSpecs
4
4
  class Grouper
5
5
  class << self
6
- def in_even_groups_by_size(items, num_groups, _options = {})
6
+ def in_even_groups_by_size(items, num_groups, options = {})
7
7
  groups = Array.new(num_groups) { {items: [], size: 0} }
8
+ single_process_patterns = options[:single_process] || []
9
+ single_items, items = items.partition do |item, _size|
10
+ single_process_patterns.any? { |pattern| item.match?(pattern) }
11
+ end
12
+ isolate_count = isolated_process_count(options)
8
13
 
9
- items_to_group(items).each do |item, size|
10
- group = groups.min_by { |entry| entry[:size] }
11
- group[:items] << item
12
- group[:size] += size || 1
14
+ if options.key?(:isolate_count) && !isolate_count.positive?
15
+ raise ParallelSpecs::ConfigurationError, "Isolated process count must be greater than 0"
16
+ end
17
+ if isolate_count >= num_groups
18
+ raise ParallelSpecs::ConfigurationError, "Isolated process count must be less than total process count"
19
+ end
20
+
21
+ if isolate_count.positive?
22
+ group_by_size(single_items, groups.first(isolate_count))
23
+ group_by_size(items, groups.drop(isolate_count))
24
+ else
25
+ single_items.each { |item, size| add_to_group(groups.first, item, size) }
26
+ group_by_size(items, groups)
13
27
  end
14
28
 
15
29
  groups.map { |group| group[:items].sort }
@@ -17,6 +31,21 @@ module ParallelSpecs
17
31
 
18
32
  private
19
33
 
34
+ def isolated_process_count(options)
35
+ options[:isolate_count] || (options[:isolate] ? 1 : 0)
36
+ end
37
+
38
+ def group_by_size(items, groups)
39
+ items_to_group(items).each do |item, size|
40
+ add_to_group(groups.min_by { |group| group[:size] }, item, size)
41
+ end
42
+ end
43
+
44
+ def add_to_group(group, item, size)
45
+ group[:items] << item
46
+ group[:size] += size || 1
47
+ end
48
+
20
49
  def items_to_group(items)
21
50
  return items unless items.first&.size == 2
22
51
 
@@ -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", "ParallelSpecs::RSpec::RuntimeLogger", "--out", runtime_log_path]
118
118
  end
119
119
  end
120
120
  end
@@ -13,7 +13,7 @@ module ParallelSpecs
13
13
 
14
14
  class << self
15
15
  def tests_in_groups(tests, num_groups, options = {})
16
- ParallelSpecs::Grouper.in_even_groups_by_size(tests_with_size(tests, options), num_groups)
16
+ ParallelSpecs::Grouper.in_even_groups_by_size(tests_with_size(tests, options), num_groups, options)
17
17
  end
18
18
 
19
19
  def tests_with_size(tests, options)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ParallelSpecs
4
- VERSION = "0.9.1"
4
+ VERSION = "0.9.2"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parallel_specs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Watermasysk
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-06-15 00:00:00.000000000 Z
11
+ date: 2026-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parallel