turbo_tests2 3.1.14 → 3.2.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,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "json"
4
+ require "fileutils"
4
5
  require "parallel_tests/rspec/runner"
5
6
  require "rspec/core"
6
7
  require "shellwords"
@@ -11,6 +12,9 @@ require_relative "../utils/hash_extension"
11
12
  module TurboTests
12
13
  class Runner
13
14
  using CoreExtensions
15
+ DEFAULT_RUNTIME_LOG = "tmp/turbo_rspec_runtime.log"
16
+ DEFAULT_WORKER_OUTPUT_MODE = :warnings
17
+ WORKER_OUTPUT_MODES = %i[warnings stream buffered quiet].freeze
14
18
 
15
19
  class << self
16
20
  def create(count)
@@ -33,7 +37,7 @@ module TurboTests
33
37
  parallel_options = opts[:parallel_options] || {}
34
38
 
35
39
  start_time = opts.fetch(:start_time) { RSpec::Core::Time.now }
36
- runtime_log = opts.fetch(:runtime_log, nil)
40
+ runtime_log = opts.fetch(:runtime_log, nil) || DEFAULT_RUNTIME_LOG
37
41
  example_status_log = opts.fetch(:example_status_log, nil)
38
42
  verbose = opts.fetch(:verbose, false)
39
43
  fail_fast = opts.fetch(:fail_fast, nil)
@@ -44,17 +48,22 @@ module TurboTests
44
48
  seed = generate_seed if seed_used && seed.nil?
45
49
  print_failed_group = opts.fetch(:print_failed_group, false)
46
50
  nice = opts.fetch(:nice, false)
51
+ worker_output = normalize_worker_output_mode(
52
+ opts[:worker_output] || ENV["TURBO_TESTS2_WORKER_OUTPUT"]
53
+ )
47
54
 
48
55
  use_runtime_info = default_file_discovery
56
+ parallel_options[:runtime_log] ||= runtime_log
49
57
 
50
58
  if example_status_log
51
59
  runtime_log = runtime_log_from_example_status(example_status_log)
52
60
  parallel_options[:runtime_log] = runtime_log
53
61
  elsif use_runtime_info
54
- parallel_options[:runtime_log] = runtime_log
62
+ parallel_options[:runtime_log] ||= runtime_log
55
63
  else
56
- parallel_options[:group_by] = :filesize
64
+ parallel_options[:group_by] ||= :filesize
57
65
  end
66
+ parallel_options[:group_by] ||= :filesize if parallel_options[:only_group]
58
67
 
59
68
  warn("VERBOSE") if verbose
60
69
 
@@ -78,10 +87,22 @@ module TurboTests
78
87
  print_failed_group: print_failed_group,
79
88
  use_runtime_info: use_runtime_info,
80
89
  parallel_options: parallel_options,
81
- nice: nice
90
+ nice: nice,
91
+ worker_output: worker_output
82
92
  ).run
83
93
  end
84
94
 
95
+ def normalize_worker_output_mode(mode)
96
+ value = mode.to_s.strip.downcase.tr("-", "_")
97
+ return DEFAULT_WORKER_OUTPUT_MODE if value.empty?
98
+
99
+ normalized = value.to_sym
100
+ return normalized if WORKER_OUTPUT_MODES.include?(normalized)
101
+
102
+ raise ArgumentError,
103
+ "Unsupported worker output mode #{mode.inspect}; expected one of: #{WORKER_OUTPUT_MODES.join(", ")}"
104
+ end
105
+
85
106
  def normalize_rspec_file_selection(files)
86
107
  selectors = {}
87
108
  files.each do |entry|
@@ -156,9 +177,10 @@ module TurboTests
156
177
  end
157
178
 
158
179
  case arg
159
- when "--pattern", "-P", "--default-path"
180
+ when "--pattern", "-P", "--default-path", "--format", "-f", "--out", "-o"
160
181
  skip_next = true
161
- when /\A--pattern=/, /\A-P.+/, /\A--default-path=/
182
+ when /\A--pattern=/, /\A-P.+/, /\A--default-path=/,
183
+ /\A--format=/, /\A-f.+/, /\A--out=/, /\A-o.+/
162
184
  next
163
185
  else
164
186
  filtered << arg
@@ -200,10 +222,10 @@ module TurboTests
200
222
 
201
223
  # Supports runtime_log as a top level option,
202
224
  # but also nested inside parallel_options
203
- @runtime_log = opts[:runtime_log] || "tmp/turbo_rspec_runtime.log"
225
+ @runtime_log = opts[:runtime_log] || DEFAULT_RUNTIME_LOG
204
226
  @parallel_options = opts.fetch(:parallel_options, {})
205
227
  @parallel_options[:runtime_log] ||= @runtime_log
206
- @record_runtime = @parallel_options[:group_by] == :runtime
228
+ @record_runtime = true
207
229
 
208
230
  @messages = Thread::Queue.new
209
231
  @threads = []
@@ -214,10 +236,12 @@ module TurboTests
214
236
  @deferred_run_options_messages = Hash.new { |hash, message| hash[message] = [] }
215
237
  @error = false
216
238
  @print_failed_group = opts[:print_failed_group]
239
+ @worker_output_mode = self.class.normalize_worker_output_mode(opts.fetch(:worker_output, DEFAULT_WORKER_OUTPUT_MODE))
217
240
  end
218
241
 
219
242
  def run
220
- tests_with_size = ParallelTests::RSpec::Runner.tests_with_size(@files, {})
243
+ parallel_tests_options = @parallel_options.reject { |key, _value| key == :only_group }
244
+ tests_with_size = ParallelTests::RSpec::Runner.tests_with_size(@files, parallel_tests_options.merge(quiet: true))
221
245
  @num_processes = [
222
246
  ParallelTests.determine_number_of_processes(@count),
223
247
  tests_with_size.size
@@ -233,8 +257,9 @@ module TurboTests
233
257
  ParallelTests::RSpec::Runner.tests_in_groups(
234
258
  @files,
235
259
  @num_processes,
236
- **@parallel_options
260
+ **parallel_tests_options
237
261
  )
262
+ tests_in_groups = selected_groups(tests_in_groups) if @parallel_options[:only_group]
238
263
  @tests_in_groups = tests_in_groups
239
264
 
240
265
  subprocess_opts = {
@@ -264,10 +289,11 @@ module TurboTests
264
289
  statuses = @wait_threads.map(&:value)
265
290
 
266
291
  if @reporter.failed_examples.empty? && statuses.all?(&:success?)
292
+ flush_successful_worker_output
267
293
  report_coverage = true
268
294
  exit_status = 0
269
295
  else
270
- flush_worker_output
296
+ flush_worker_output unless stream_worker_output?
271
297
  # From https://github.com/galtzo-floss/turbo_tests2/pull/20/
272
298
  exit_status = statuses.map(&:exitstatus).max
273
299
  end
@@ -280,6 +306,18 @@ module TurboTests
280
306
 
281
307
  private
282
308
 
309
+ def selected_groups(tests_in_groups)
310
+ requested_groups = @parallel_options[:only_group]
311
+ missing_groups = requested_groups.select { |index| index > tests_in_groups.size }
312
+ unless missing_groups.empty?
313
+ raise ArgumentError,
314
+ "Selected group index(es) out of range: #{missing_groups.join(", ")} " \
315
+ "(available groups: #{tests_in_groups.size})"
316
+ end
317
+
318
+ requested_groups.map { |index| tests_in_groups[index - 1] }
319
+ end
320
+
283
321
  def handle_interrupt
284
322
  if @interrupt_handled
285
323
  Kernel.exit
@@ -337,6 +375,7 @@ module TurboTests
337
375
 
338
376
  record_runtime_options =
339
377
  if record_runtime
378
+ FileUtils.mkdir_p(File.dirname(@runtime_log))
340
379
  [
341
380
  "--format",
342
381
  "ParallelTests::RSpec::RuntimeLogger",
@@ -483,7 +522,25 @@ module TurboTests
483
522
  end
484
523
 
485
524
  io = (stream == :stderr) ? $stderr : $stdout
486
- io.write(msg) if @verbose
525
+ io.write(msg) if stream_worker_output?
526
+ end
527
+
528
+ def stream_worker_output?
529
+ @verbose || @worker_output_mode == :stream
530
+ end
531
+
532
+ def flush_successful_worker_output
533
+ case @worker_output_mode
534
+ when :warnings
535
+ flush_worker_warnings unless stream_worker_output?
536
+ when :buffered
537
+ flush_worker_output unless stream_worker_output?
538
+ when :quiet, :stream
539
+ nil
540
+ else
541
+ raise ArgumentError,
542
+ "Unsupported worker output mode #{@worker_output_mode.inspect}; expected one of: #{WORKER_OUTPUT_MODES.join(", ")}"
543
+ end
487
544
  end
488
545
 
489
546
  def flush_worker_output
@@ -504,6 +561,43 @@ module TurboTests
504
561
  end
505
562
  end
506
563
 
564
+ def flush_worker_warnings
565
+ output_by_process = @worker_output_mutex.synchronize do
566
+ @worker_output.transform_values(&:dup)
567
+ end
568
+
569
+ output_by_process.each do |process_id, streams|
570
+ streams.each do |stream, output|
571
+ warnings = warning_lines(output)
572
+ next if warnings.empty?
573
+
574
+ io = (stream == :stderr) ? $stderr : $stdout
575
+ io.puts
576
+ io.puts("TurboTests worker #{process_id} #{stream} warnings:")
577
+ warnings.each { |line| io.puts(line) }
578
+ end
579
+ end
580
+ end
581
+
582
+ def warning_lines(output)
583
+ output.each_line.each_with_object([]) do |line, warnings|
584
+ stripped = line.strip
585
+ next if stripped.empty?
586
+ next unless warning_line?(stripped)
587
+ next if coverage_output_line?(stripped)
588
+
589
+ warnings << stripped
590
+ end
591
+ end
592
+
593
+ def warning_line?(line)
594
+ line.match?(/warning:/i) || line.match?(/deprecat/i)
595
+ end
596
+
597
+ def coverage_output_line?(line)
598
+ line.start_with?("Coverage report generated for ", "JSON Coverage report generated for ", "Line coverage:", "Branch coverage:", "Line Coverage:", "Branch Coverage:")
599
+ end
600
+
507
601
  def flush_coverage_summary
508
602
  line_coverage = nil
509
603
  branch_coverage = nil
@@ -2,7 +2,7 @@
2
2
 
3
3
  module TurboTests
4
4
  module Version
5
- VERSION = "3.1.14"
5
+ VERSION = "3.2.1"
6
6
  end
7
7
  VERSION = Version::VERSION # Traditional Constant Location
8
8
  end
data.tar.gz.sig CHANGED
@@ -1,2 +1,2 @@
1
- MX™gt#�x(n
2
- ������u�9����6C ��Td{&B��Ԯ�)���,�OF§�n=����ѡd���8�S>{(�FZ��� ���=z�B(`�[IB*bM1|�0� ��t��:�b��ur@�iLv���Aw� V�h��t�sdy�J���j�=��WXiI�x9� M��G���2=��&դ;~�L
1
+ �A�c���N_W�O�#Q�V��:
2
+ ��9���H1m��k��`䡮�fdp��Q��G�a�>��=-P�m�*�c��^��1��-�J�)ړ���v b��82θ�̨�-���*jFG~��5��S3�ң@�q�kT����<jvm���8�U"I��IhL���y���PCP����BW甔�,�����3//O_��A�I��V��%���穎(!Sx9��J0���lf�:��q%я-� ����9k
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: turbo_tests2
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.14
4
+ version: 3.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Illia
@@ -110,7 +110,7 @@ dependencies:
110
110
  version: '2.3'
111
111
  - - ">="
112
112
  - !ruby/object:Gem::Version
113
- version: 2.3.5
113
+ version: 2.3.7
114
114
  type: :development
115
115
  prerelease: false
116
116
  version_requirements: !ruby/object:Gem::Requirement
@@ -120,7 +120,7 @@ dependencies:
120
120
  version: '2.3'
121
121
  - - ">="
122
122
  - !ruby/object:Gem::Version
123
- version: 2.3.5
123
+ version: 2.3.7
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: bundler-audit
126
126
  requirement: !ruby/object:Gem::Requirement
@@ -175,20 +175,20 @@ dependencies:
175
175
  requirements:
176
176
  - - "~>"
177
177
  - !ruby/object:Gem::Version
178
- version: '3.1'
178
+ version: '3.2'
179
179
  - - ">="
180
180
  - !ruby/object:Gem::Version
181
- version: 3.1.4
181
+ version: 3.2.0
182
182
  type: :development
183
183
  prerelease: false
184
184
  version_requirements: !ruby/object:Gem::Requirement
185
185
  requirements:
186
186
  - - "~>"
187
187
  - !ruby/object:Gem::Version
188
- version: '3.1'
188
+ version: '3.2'
189
189
  - - ">="
190
190
  - !ruby/object:Gem::Version
191
- version: 3.1.4
191
+ version: 3.2.0
192
192
  - !ruby/object:Gem::Dependency
193
193
  name: kettle-test
194
194
  requirement: !ruby/object:Gem::Requirement
@@ -198,7 +198,7 @@ dependencies:
198
198
  version: '2.0'
199
199
  - - ">="
200
200
  - !ruby/object:Gem::Version
201
- version: 2.0.10
201
+ version: 2.0.15
202
202
  type: :development
203
203
  prerelease: false
204
204
  version_requirements: !ruby/object:Gem::Requirement
@@ -208,7 +208,7 @@ dependencies:
208
208
  version: '2.0'
209
209
  - - ">="
210
210
  - !ruby/object:Gem::Version
211
- version: 2.0.10
211
+ version: 2.0.15
212
212
  - !ruby/object:Gem::Dependency
213
213
  name: ruby-progressbar
214
214
  requirement: !ruby/object:Gem::Requirement
@@ -273,28 +273,11 @@ email:
273
273
  executables:
274
274
  - turbo_tests2
275
275
  extensions: []
276
- extra_rdoc_files:
277
- - CHANGELOG.md
278
- - CITATION.cff
279
- - CODE_OF_CONDUCT.md
280
- - CONTRIBUTING.md
281
- - FUNDING.md
282
- - LICENSE.md
283
- - README.md
284
- - RUBOCOP.md
285
- - SECURITY.md
276
+ extra_rdoc_files: []
286
277
  files:
287
278
  - CHANGELOG.md
288
- - CITATION.cff
289
- - CODE_OF_CONDUCT.md
290
- - CONTRIBUTING.md
291
- - FUNDING.md
292
279
  - LICENSE.md
293
- - MIT.md
294
280
  - README.md
295
- - RUBOCOP.md
296
- - SECURITY.md
297
- - certs/pboling.pem
298
281
  - exe/turbo_tests2
299
282
  - lib/turbo_tests.rb
300
283
  - lib/turbo_tests/cli.rb
@@ -306,16 +289,15 @@ files:
306
289
  - lib/turbo_tests2.rb
307
290
  - lib/turbo_tests2/rspec/shared_contexts/simplecov_spawn.rb
308
291
  - lib/utils/hash_extension.rb
309
- - sig/turbo_tests/version.rbs
310
292
  homepage: https://github.com/galtzo-floss/turbo_tests2
311
293
  licenses:
312
294
  - MIT
313
295
  metadata:
314
296
  homepage_uri: https://turbo-tests2.galtzo.com
315
- source_code_uri: https://github.com/galtzo-floss/turbo_tests2/tree/v3.1.14
316
- changelog_uri: https://github.com/galtzo-floss/turbo_tests2/blob/v3.1.14/CHANGELOG.md
297
+ source_code_uri: https://github.com/galtzo-floss/turbo_tests2/tree/v3.2.1
298
+ changelog_uri: https://github.com/galtzo-floss/turbo_tests2/blob/v3.2.1/CHANGELOG.md
317
299
  bug_tracker_uri: https://github.com/galtzo-floss/turbo_tests2/issues
318
- documentation_uri: https://www.rubydoc.info/gems/turbo_tests2/3.1.14
300
+ documentation_uri: https://www.rubydoc.info/gems/turbo_tests2/3.2.1
319
301
  funding_uri: https://github.com/sponsors/pboling
320
302
  wiki_uri: https://github.com/galtzo-floss/turbo_tests2/wiki
321
303
  news_uri: https://www.railsbling.com/tags/turbo_tests2
@@ -345,7 +327,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
345
327
  - !ruby/object:Gem::Version
346
328
  version: '0'
347
329
  requirements: []
348
- rubygems_version: 4.0.16
330
+ rubygems_version: 4.0.17
349
331
  specification_version: 4
350
332
  summary: "\U0001F680 RSpec parallel test runner built on `parallel_tests`, with incremental
351
333
  summarized output"
metadata.gz.sig CHANGED
Binary file
data/CITATION.cff DELETED
@@ -1,20 +0,0 @@
1
- cff-version: 1.2.0
2
- title: "turbo_tests2"
3
- message: >-
4
- If you use this work and you want to cite it,
5
- then you can use the metadata from this file.
6
- type: software
7
- authors:
8
- - given-names: "Peter H."
9
- family-names: "Boling"
10
- email: "floss@galtzo.com"
11
- affiliation: "galtzo.com"
12
- orcid: 'https://orcid.org/0009-0008-8519-441X'
13
- identifiers:
14
- - type: url
15
- value: 'https://github.com/galtzo-floss/turbo_tests2'
16
- description: "turbo_tests2"
17
- repository-code: 'https://github.com/galtzo-floss/turbo_tests2'
18
- abstract: >-
19
- turbo_tests2
20
- license: See license file
data/CODE_OF_CONDUCT.md DELETED
@@ -1,134 +0,0 @@
1
- # Contributor Covenant Code of Conduct
2
-
3
- ## Our Pledge
4
-
5
- We as members, contributors, and leaders pledge to make participation in our
6
- community a harassment-free experience for everyone, regardless of age, body
7
- size, visible or invisible disability, ethnicity, sex characteristics, gender
8
- identity and expression, level of experience, education, socio-economic status,
9
- nationality, personal appearance, race, caste, color, religion, or sexual
10
- identity and orientation.
11
-
12
- We pledge to act and interact in ways that contribute to an open, welcoming,
13
- diverse, inclusive, and healthy community.
14
-
15
- ## Our Standards
16
-
17
- Examples of behavior that contributes to a positive environment for our
18
- community include:
19
-
20
- * Demonstrating empathy and kindness toward other people
21
- * Being respectful of differing opinions, viewpoints, and experiences
22
- * Giving and gracefully accepting constructive feedback
23
- * Accepting responsibility and apologizing to those affected by our mistakes,
24
- and learning from the experience
25
- * Focusing on what is best not just for us as individuals, but for the overall
26
- community
27
-
28
- Examples of unacceptable behavior include:
29
-
30
- * The use of sexualized language or imagery, and sexual attention or advances of
31
- any kind
32
- * Trolling, insulting or derogatory comments, and personal or political attacks
33
- * Public or private harassment
34
- * Publishing others' private information, such as a physical or email address,
35
- without their explicit permission
36
- * Other conduct which could reasonably be considered inappropriate in a
37
- professional setting
38
-
39
- ## Enforcement Responsibilities
40
-
41
- Community leaders are responsible for clarifying and enforcing our standards of
42
- acceptable behavior and will take appropriate and fair corrective action in
43
- response to any behavior that they deem inappropriate, threatening, offensive,
44
- or harmful.
45
-
46
- Community leaders have the right and responsibility to remove, edit, or reject
47
- comments, commits, code, wiki edits, issues, and other contributions that are
48
- not aligned to this Code of Conduct, and will communicate reasons for moderation
49
- decisions when appropriate.
50
-
51
- ## Scope
52
-
53
- This Code of Conduct applies within all community spaces, and also applies when
54
- an individual is officially representing the community in public spaces.
55
- Examples of representing our community include using an official email address,
56
- posting via an official social media account, or acting as an appointed
57
- representative at an online or offline event.
58
-
59
- ## Enforcement
60
-
61
- Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
- reported to the community leaders responsible for enforcement at
63
- [![Contact Maintainer][🚂maint-contact-img]][🚂maint-contact].
64
- All complaints will be reviewed and investigated promptly and fairly.
65
-
66
- All community leaders are obligated to respect the privacy and security of the
67
- reporter of any incident.
68
-
69
- ## Enforcement Guidelines
70
-
71
- Community leaders will follow these Community Impact Guidelines in determining
72
- the consequences for any action they deem in violation of this Code of Conduct:
73
-
74
- ### 1. Correction
75
-
76
- **Community Impact**: Use of inappropriate language or other behavior deemed
77
- unprofessional or unwelcome in the community.
78
-
79
- **Consequence**: A private, written warning from community leaders, providing
80
- clarity around the nature of the violation and an explanation of why the
81
- behavior was inappropriate. A public apology may be requested.
82
-
83
- ### 2. Warning
84
-
85
- **Community Impact**: A violation through a single incident or series of
86
- actions.
87
-
88
- **Consequence**: A warning with consequences for continued behavior. No
89
- interaction with the people involved, including unsolicited interaction with
90
- those enforcing the Code of Conduct, for a specified period of time. This
91
- includes avoiding interactions in community spaces as well as external channels
92
- like social media. Violating these terms may lead to a temporary or permanent
93
- ban.
94
-
95
- ### 3. Temporary Ban
96
-
97
- **Community Impact**: A serious violation of community standards, including
98
- sustained inappropriate behavior.
99
-
100
- **Consequence**: A temporary ban from any sort of interaction or public
101
- communication with the community for a specified period of time. No public or
102
- private interaction with the people involved, including unsolicited interaction
103
- with those enforcing the Code of Conduct, is allowed during this period.
104
- Violating these terms may lead to a permanent ban.
105
-
106
- ### 4. Permanent Ban
107
-
108
- **Community Impact**: Demonstrating a pattern of violation of community
109
- standards, including sustained inappropriate behavior, harassment of an
110
- individual, or aggression toward or disparagement of classes of individuals.
111
-
112
- **Consequence**: A permanent ban from any sort of public interaction within the
113
- community.
114
-
115
- ## Attribution
116
-
117
- This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118
- version 2.1, available at
119
- [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
120
-
121
- Community Impact Guidelines were inspired by
122
- [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
123
-
124
- For answers to common questions about this code of conduct, see the FAQ at
125
- [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
126
- [https://www.contributor-covenant.org/translations][translations].
127
-
128
- [homepage]: https://www.contributor-covenant.org
129
- [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
130
- [Mozilla CoC]: https://github.com/mozilla/diversity
131
- [FAQ]: https://www.contributor-covenant.org/faq
132
- [translations]: https://www.contributor-covenant.org/translations
133
- [🚂maint-contact]: http://www.railsbling.com/contact
134
- [🚂maint-contact-img]: https://img.shields.io/badge/Contact-Maintainer-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red