Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,14 @@ Please file a bug if you notice a violation of semantic versioning.

### Fixed

- Fix a teardown race that intermittently dropped a worker's results. The exit-watcher thread previously signaled process exit as soon as the child was reaped, before the stdout/stderr readers had drained the pipe. Under CI contention handle_messages could reach process_count exits and stop while that worker's rows were still queued behind the exit signal, so they were never reported. Symptom was a nested run reporting "1 example, 0 failures" instead of "4 examples, 0 failures, 3 pending", with which worker vanished varying run to run (spec/integration/multi_process_spec.rb failed at :46 on one run and :52-54 on the next). Readers are now drained to EOF before the watcher signals exit, and the exit/error messages are a deduped fallback for a reader force-stopped before EOF. Drain uses one shared monotonic deadline across both streams (READER_DRAIN_TIMEOUT) so a wedged pipe whose write end stays open cannot double teardown time or hang; force-stop still closes the pipe and kills the reader as before.

- Fix spec discovery returning absolute paths on Windows, which crashed parallel_tests' File.stat during group sizing. rspec_configured_files_to_run made discovered paths relative to the cwd with a string prefix check. On Windows the cwd and the discovered files can name the same directory with two different spellings: Dir.pwd and ENV["TEMP"] report the 8.3 short name (C:/Users/RUNNER~1/AppData/Local/Temp) while Dir.glob, which RSpec uses to expand --pattern, reports the long name (C:/Users/runneradmin/AppData/Local/Temp). The prefix therefore never matched and the absolute temp path leaked through. File.realpath does not expand 8.3 short names, so canonicalizing first cannot reconcile the two spellings, and Pathname#relative_path_from returns nonsense such as "../../../../../runneradmin/...". The same class of mismatch arises from a symlinked ancestor on any platform, e.g. a Dir.pwd of /var/home/u/proj against a path spelled /home/u/proj/... Discovered paths are now made relative by walking up from the file and comparing each ancestor with File.identical?, which compares by filesystem identity (inode on Unix, file index on Windows) and so treats every spelling of one directory as equal. Extracted as TurboTests::Utils::Paths.relative_from/.within?.

### Security

## [3.2.14] - 2026-10-05
## [3.2.14] - 2026-10-07

- TAG: [v3.2.14][3.2.14t]
- COVERAGE: 96.81% -- 910/940 lines in 10 files
- BRANCH COVERAGE: 84.72% -- 244/288 branches in 10 files
- 36.73% documented
- COVERAGE: 96.93% -- 947/977 lines in 11 files
- BRANCH COVERAGE: 85.57% -- 255/298 branches in 11 files
- 39.42% documented

### Changed

Expand All @@ -56,6 +52,10 @@ Please file a bug if you notice a violation of semantic versioning.

- rspec_configured_files_to_run: normalize discovered spec paths against the root cwd instead of the nearest ancestor .rspec. In stacked monorepos (root .rspec aggregating gems/*/spec via --pattern, where each gem also has its own .rspec), the nearest-ancestor walk stripped aggregated specs to bare member-relative spec/... paths that do not exist at the root, crashing parallel_tests File.stat during group sizing and aborting the whole run. Regression introduced in 3.2.13.

- Fix a teardown race that intermittently dropped a worker's results. The exit-watcher thread previously signaled process exit as soon as the child was reaped, before the stdout/stderr readers had drained the pipe. Under CI contention handle_messages could reach process_count exits and stop while that worker's rows were still queued behind the exit signal, so they were never reported. Symptom was a nested run reporting "1 example, 0 failures" instead of "4 examples, 0 failures, 3 pending", with which worker vanished varying run to run (spec/integration/multi_process_spec.rb failed at :46 on one run and :52-54 on the next). Readers are now drained to EOF before the watcher signals exit, and the exit/error messages are a deduped fallback for a reader force-stopped before EOF. Drain uses one shared monotonic deadline across both streams (READER_DRAIN_TIMEOUT) so a wedged pipe whose write end stays open cannot double teardown time or hang; force-stop still closes the pipe and kills the reader as before.

- Fix spec discovery returning absolute paths on Windows, which crashed parallel_tests' File.stat during group sizing. rspec_configured_files_to_run made discovered paths relative to the cwd with a string prefix check. On Windows the cwd and the discovered files can name the same directory with two different spellings: Dir.pwd and ENV["TEMP"] report the 8.3 short name (C:/Users/RUNNER~1/AppData/Local/Temp) while Dir.glob, which RSpec uses to expand --pattern, reports the long name (C:/Users/runneradmin/AppData/Local/Temp). The prefix therefore never matched and the absolute temp path leaked through. File.realpath does not expand 8.3 short names, so canonicalizing first cannot reconcile the two spellings, and Pathname#relative_path_from returns nonsense such as "../../../../../runneradmin/...". The same class of mismatch arises from a symlinked ancestor on any platform, e.g. a Dir.pwd of /var/home/u/proj against a path spelled /home/u/proj/... Discovered paths are now made relative by walking up from the file and comparing each ancestor with File.identical?, which compares by filesystem identity (inode on Unix, file index on Windows) and so treats every spelling of one directory as equal. Extracted as TurboTests::Utils::Paths.relative_from/.within?.

## [3.2.13] - 2026-10-01

- TAG: [v3.2.13][3.2.13t]
Expand Down
56 changes: 28 additions & 28 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ GEM
geom2d (0.4.1)
gitmoji-regex (2.0.15)
version_gem (~> 1.1, >= 1.1.15)
hexapdf (1.11.0)
hexapdf (1.11.1)
cmdparse (~> 3.0, >= 3.0.3)
geom2d (~> 0.4, >= 0.4.1)
openssl (>= 2.2.1)
Expand All @@ -149,7 +149,7 @@ GEM
prism (>= 1.3.0)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
json (2.21.2)
json (3.0.2)
json-merge (7.1.9)
ast-merge (= 7.1.9)
tree_haver (= 7.1.9)
Expand All @@ -158,7 +158,7 @@ GEM
ast-crispr-markdown-markly (~> 7.1, >= 7.1.1)
kettle-dev (~> 3.1, >= 3.1.2)
version_gem (~> 1.1, >= 1.1.15)
kettle-dev (3.1.7)
kettle-dev (3.1.8)
emoji_regex (>= 15.0)
kettle-gha-pins (~> 0.3, >= 0.3.16)
kettle-ndjson (~> 0.1, >= 0.1.18)
Expand All @@ -167,11 +167,11 @@ GEM
ruby-progressbar (~> 1.13)
tty-progressbar (~> 0.18)
version_gem (~> 1.1, >= 1.1.15)
kettle-family (1.3.5)
kettle-family (1.3.6)
command_kit (~> 0.6)
command_kit-completion (~> 0.1)
kettle-changelog (~> 1.0, >= 1.0.8)
kettle-dev (~> 3.1, >= 3.1.7)
kettle-dev (~> 3.1, >= 3.1.8)
kettle-gha-pins (~> 0.3, >= 0.3.16)
kettle-jem (~> 7.1, >= 7.1.28)
kettle-test (~> 2.0, >= 2.0.23)
Expand Down Expand Up @@ -358,8 +358,8 @@ GEM
rspec-support (3.13.7)
rspec_junit_formatter (0.6.0)
rspec-core (>= 2, < 4, != 2.12.0)
rubocop (1.88.2)
json (~> 2.3)
rubocop (1.91.0)
json (>= 2.3)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
parallel (>= 1.10)
Expand Down Expand Up @@ -407,9 +407,9 @@ GEM
rubocop-md (2.0.4)
lint_roller (~> 1.1)
rubocop (>= 1.72.1)
rubocop-minitest (0.40.0)
rubocop-minitest (0.41.0)
lint_roller (~> 1.1)
rubocop (>= 1.75.0, < 2.0)
rubocop (>= 1.89.0, < 2.0)
rubocop-ast (>= 1.38.0, < 2.0)
rubocop-on-rbs (2.2.0)
lint_roller (~> 1.1)
Expand All @@ -429,9 +429,9 @@ GEM
rubocop-rspec-extra (0.3.0)
lint_roller (~> 1.1)
rubocop (>= 1.72.1, < 2.0)
rubocop-rspec_rails (2.32.0)
rubocop-rspec_rails (2.33.0)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop (~> 1.89)
rubocop-rspec (~> 3.5)
rubocop-ruby2_4 (3.0.8)
rubocop-gradual (~> 0.3, >= 0.3.6)
Expand All @@ -440,9 +440,9 @@ GEM
rubocop-thread_safety (~> 0.7, >= 0.7.3)
standard-rubocop-lts (~> 2.0, >= 2.0.14)
version_gem (~> 1.1, >= 1.1.15)
rubocop-thread_safety (0.7.3)
rubocop-thread_safety (0.8.0)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop (~> 1.89)
rubocop-ast (>= 1.44.0, < 2.0)
ruby-merge (7.1.9)
ast-merge (= 7.1.9)
Expand All @@ -468,11 +468,11 @@ GEM
simplecov (>= 0.4.1)
simplecov_lcov_formatter (0.9.0)
simplecov (>= 0.18)
sorbet-runtime (0.6.13528)
standard (1.56.0)
sorbet-runtime (0.6.13532)
standard (1.57.0)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.0)
rubocop (~> 1.88.0)
rubocop (~> 1.91.0)
standard-custom (~> 1.0.0)
standard-performance (~> 1.8)
standard-custom (1.0.2)
Expand Down Expand Up @@ -645,7 +645,7 @@ CHECKSUMS
bash-merge (7.1.9) sha256=fde66a0e5eaaa2df0eae456bd5a45be631e61806c356f345d2a43085e4138757
benchmark (0.5.0) sha256=465df122341aedcb81a2a24b4d3bd19b6c67c1530713fd533f3ff034e419236c
bigdecimal (4.1.3) sha256=61ebe1e5e559bdc3cc6f2c0ee7f427321fc838f59611c294356eb04d6e21cf66
bundler (4.0.22) sha256=d8d5ec84c8555e0af71db63ed7aee4d1a8fb839ec46d84212d61979242a5d75a
bundler (4.0.21) sha256=7cbf5499b426076aa16c8d28a59e4c2c3aad5a438402abcd961f0119f29f1dd0
bundler-audit (0.9.3) sha256=81c8766c71e47d0d28a0f98c7eed028539f21a6ea3cd8f685eb6f42333c9b4e9
cgi (0.5.2) sha256=61ca30298171190fd4fa0d8018e57ada456eae9b7a2b78526debf7f0a0e6f8bb
citrus (3.0.2) sha256=4ec2412fc389ad186735f4baee1460f7900a8e130ffe3f216b30d4f9c684f650
Expand Down Expand Up @@ -682,14 +682,14 @@ CHECKSUMS
gem_bench (2.0.5) sha256=0dc0fb44a5a5eb7b2f5c1c68a5b0164d72007132822c012bac3abe976b199ead
geom2d (0.4.1) sha256=ea0998ea90c4f2752e24fe13d85a4f89bee689d151316140ebcc6369bf634ed9
gitmoji-regex (2.0.15) sha256=c6571bffd757f95c06d84a7d2d0b3f180eca7fe576882c371cee1f1a081cd968
hexapdf (1.11.0) sha256=72e0459dd2482ec1791f9a44a97144566a00188889cc8742dda97413ca679c62
hexapdf (1.11.1) sha256=914578c3b2024f76b533144344379c7123d3eaa3ea586f4d98add59534b783a9
io-console (0.9.4) sha256=a403304f32928ee85e56d457b4612ca43f2703b561a3258844992bd24085fbb1
irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3
json (2.21.2) sha256=1f1d3b7cf2b3ba1a69beca0bb6db13d5438b80bff3cd54cdaaa620b9b07c1c6a
json (3.0.2) sha256=8e6d7e7b11384c21230430cef90b71f14849a34a1f4452796670f7c981bd19df
json-merge (7.1.9) sha256=13c979c1398e6e3126ec6c1d4acccd08a138fb06a58152f51ad9079caf03b39e
kettle-changelog (1.0.8) sha256=08ded13e84276e58cd6375c1750ee6dab45fd2f67c0f0fed623a7267ddb9e300
kettle-dev (3.1.7) sha256=23e4b9d678d307a1ad314122b028087430811da0c3ee99131849ff6aa6795c87
kettle-family (1.3.5) sha256=792328eae94386c84873cf04ba6e22a3b8285b2b2c30299fb45994a9bdfce472
kettle-dev (3.1.8) sha256=0923d5e6908e7554d65ff6d064b587aef01cf1d328bb64c184ce29acbc190a9e
kettle-family (1.3.6) sha256=73aac0e22a44651773c4f6aba45d878c2e743292b63fb1473e985512c52d7623
kettle-gha-pins (0.3.16) sha256=4ee906232dae309e8dbd1fca8e993bbfdad20f24892fc73776c9960081bbbbdb
kettle-jem (7.1.28) sha256=6bd38a850bc3a73786cd26f3c3489f37ab6040832143df8fbd5e41ad73085d14
kettle-ndjson (0.1.18) sha256=0608518194739eafee1d2e84871a3f9759350ced5ed7aaaa1a81c72e7d17468c
Expand Down Expand Up @@ -749,7 +749,7 @@ CHECKSUMS
rspec-stubbed_env (1.0.16) sha256=7ea81332e37f637c3b6289b1c7afc8e6ea0a1c3e3ab36ff2c9611b0416367d52
rspec-support (3.13.7) sha256=0640e5570872aafefd79867901deeeeb40b0c9875a36b983d85f54fb7381c47c
rspec_junit_formatter (0.6.0) sha256=40dde674e6ae4e6cc0ff560da25497677e34fefd2338cc467a8972f602b62b15
rubocop (1.88.2) sha256=8def251c90cd955feb4daa3edc0ab56893250c4ce90ef81e6c80c03f9a939bbf
rubocop (1.91.0) sha256=9c82b7bf391c5d7e3798c5b9996e22a1fe3bd7468e351dfdeb96140c058296d0
rubocop-ast (1.50.0) sha256=b9ca88300da0803ee222ad20cdb30494c0a784eed06fdc35d254b06d662788db
rubocop-capybara (2.23.0) sha256=f9ea1ba3a7561ee8e88cf76fc378ce517ce5327155f305ee7b5c2500e5aee357
rubocop-env (0.1.0) sha256=5ab9a259e71822bf514c8e900a9b68cc2f74ccc87d5493efcd03213f3068e718
Expand All @@ -759,16 +759,16 @@ CHECKSUMS
rubocop-lts-rspec (1.0.7) sha256=7bf96c2745b9d000f418ab739f27a11037ba2b1dc4980aff53bbc9fec2ac4272
rubocop-lts-ruby (0.1.5) sha256=09c47d2d666693ee759e1d5549e5534a5465f10e2580fbf9049c8a341a04999e
rubocop-md (2.0.4) sha256=0d076b6b5e99dea2ddc928c4bd702497decb9a8400da7808091e02ebcafcfb93
rubocop-minitest (0.40.0) sha256=353c698199115f12151144cf0b5a96f69bb9d77b660cf6536df2c4250c672a9d
rubocop-minitest (0.41.0) sha256=c15bfe00134a30c8a00ce670b07ecc80440455ba277b8682cf0d515c98ee7426
rubocop-on-rbs (2.2.0) sha256=a78c1fa10fd9d78e26a9de67e9428a1ef6b5dc3b61e3db69e201222ccd588cf5
rubocop-packaging (0.6.0)
rubocop-performance (1.26.1) sha256=cd19b936ff196df85829d264b522fd4f98b6c89ad271fa52744a8c11b8f71834
rubocop-rake (0.7.1) sha256=3797f2b6810c3e9df7376c26d5f44f3475eda59eb1adc38e6f62ecf027cbae4d
rubocop-rspec (3.10.2) sha256=0b3e2ecc592cd10ecbf0095bb58d1e357905276e069643523cc19eb7495f65e2
rubocop-rspec-extra (0.3.0) sha256=ee4b6484d0332a0d23c4a465eeb607e41888eb3d4ed479f850b9f5212514f787
rubocop-rspec_rails (2.32.0) sha256=4a0d641c72f6ebb957534f539d9d0a62c47abd8ce0d0aeee1ef4701e892a9100
rubocop-rspec_rails (2.33.0) sha256=669e0a7a9a5fca6d6ccaf853ac65b5b8bdfde3519f604616f2c5278cbf565689
rubocop-ruby2_4 (3.0.8) sha256=d2d047d30d89330745af7101218931defcdc8b99363a36dc159b0fbc5465d72e
rubocop-thread_safety (0.7.3) sha256=067cdd52fbf5deffc18995437e45b5194236eaff4f71de3375a1f6052e48f431
rubocop-thread_safety (0.8.0) sha256=71fe5e7894fb9acfbd4c2dcd394feabc35bd690f75b0bc846e1504d9e31f9034
ruby-merge (7.1.9) sha256=935774793dcec28614019a7c0802f14f93f805664684e7a29184ad1b4db241fa
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
ruby_engine (2.0.3) sha256=ca2ae7def8cfcdc2bfb6a186d36d5d59c8b403245dc0256c3802b767fa278aaa
Expand All @@ -780,8 +780,8 @@ CHECKSUMS
simplecov-console (0.9.5) sha256=b1108bcfff5f210143e2b8301698c367b01586f20d25a73e95475a5df6fc6ff6
simplecov-rcov (0.3.7) sha256=372f50bf6df6b6350b7d0c840f2f8bdabe021861a43c26877b747c9ac96139fc
simplecov_lcov_formatter (0.9.0) sha256=4c1839bb31dcf7a8f7a6474c94ed228aa03b994e9dd5e1965e58b4121b049bed
sorbet-runtime (0.6.13528) sha256=c89d1c6936db4d2107732be5cc6d7649ccf3b5a095ae211a312e21fba82fd53a
standard (1.56.0) sha256=ae2af4d9669589162ac69ed5ef59dcf9f346d4afc81f7e62b84339310dfcb787
sorbet-runtime (0.6.13532) sha256=b75bf990d7d4b9e07a4bf1c470d6ff8df1f3c4a1b0137edebbc4f90d25781150
standard (1.57.0) sha256=4a65ea92421fbaf77fb54da91e16093cf79b335b8f62c35aaa3dd714c8592858
standard-custom (1.0.2) sha256=424adc84179a074f1a2a309bb9cf7cd6bfdb2b6541f20c6bf9436c0ba22a652b
standard-performance (1.9.0) sha256=49483d31be448292951d80e5e67cdcb576c2502103c7b40aec6f1b6e9c88e3f2
standard-rspec (0.5.1) sha256=94c6a0c94f6d303867df5cc403a0d4994cf0d72973e86c0a0c82e3b89843989a
Expand Down Expand Up @@ -822,4 +822,4 @@ CHECKSUMS
zeitwerk (2.8.3) sha256=2c85125a8467ce069e20123d1e709a08955c9d29c118c25b46b7b7fafdbb92e5

BUNDLED WITH
4.0.22
4.0.21
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,7 @@ Thanks for RTFM. ☺️
[📌gitmoji]: https://gitmoji.dev
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.940-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.977-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
[🔐security]: https://github.com/galtzo-floss/turbo_tests2/blob/main/SECURITY.md
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
Expand Down
4 changes: 2 additions & 2 deletions docs/TurboTests.html
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
<dl>
<dt>Defined in:</dt>
<dd>lib/turbo_tests.rb<span class="defines">,<br>
lib/turbo_tests/cli.rb,<br> lib/turbo_tests/shim.rb,<br> lib/turbo_tests/runner.rb,<br> lib/turbo_tests/version.rb,<br> lib/turbo_tests/reporter.rb,<br> lib/turbo_tests/json_rows_formatter.rb</span>
lib/turbo_tests/cli.rb,<br> lib/turbo_tests/shim.rb,<br> lib/turbo_tests/runner.rb,<br> lib/turbo_tests/version.rb,<br> lib/turbo_tests/reporter.rb,<br> lib/turbo_tests/utils/paths.rb,<br> lib/turbo_tests/json_rows_formatter.rb</span>

</dd>
</dl>
Expand All @@ -92,7 +92,7 @@ <h2>Defined Under Namespace</h2>
<p class="children">


<strong class="modules">Modules:</strong> <span class='object_link'><a href="TurboTests/Version.html" title="TurboTests::Version (module)">Version</a></span>
<strong class="modules">Modules:</strong> <span class='object_link'><a href="TurboTests/Utils.html" title="TurboTests::Utils (module)">Utils</a></span>, <span class='object_link'><a href="TurboTests/Version.html" title="TurboTests::Version (module)">Version</a></span>



Expand Down
Loading
Loading