turbo_tests2 3.2.15 → 3.2.17
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +37 -1
- data/README.md +55 -1
- data/lib/turbo_tests/cli.rb +10 -0
- data/lib/turbo_tests/runner.rb +72 -15
- data/lib/turbo_tests/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +8 -8
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4d0f84a37aeb74853501933d16cd9476a1f82800b3d33e9da544af8ef0e0c145
|
|
4
|
+
data.tar.gz: 581d982f38436235925c6bc8180a4ac29513c198599ae841949e47bce114186f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9d0f7b4e2080fd36f4da47ff4bdebed7fce369995e9c1b6cb305bc2caf9ad935ec2d65eaa84483721b361c57a12eb24b36fd3d0c5fc0ce16a62638f14df16636
|
|
7
|
+
data.tar.gz: ffc015acc34a5ad4658a2a5aa53ceb02ec6621eea4e625bc1a7d2b6558c1cc728037ad984c32cc52e08108f8c322011dee41926dfdde3400c5c65ae7021c82dc
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,38 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [3.2.17] - 2026-10-14
|
|
34
|
+
|
|
35
|
+
- TAG: [v3.2.17][3.2.17t]
|
|
36
|
+
- COVERAGE: 95.94% -- 993/1035 lines in 11 files
|
|
37
|
+
- BRANCH COVERAGE: 83.86% -- 265/316 branches in 11 files
|
|
38
|
+
- 39.42% documented
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
|
|
42
|
+
- README: document the spawn-based (fork-free) worker architecture that makes parallel workers engine-portable to JRuby and TruffleRuby, and add a Resource-Constrained CI (JVM Engines) section with the canonical 2-worker + capped-heap + raised-watchdog setup, matching the kettle-jem CI templates
|
|
43
|
+
|
|
44
|
+
- Stall diagnostics and in-code docs now explain silent worker death: the 900s silence warning and the watchdog stall path point at the OOM killer as the most common cause of total silence in a parallel lane (spawned workers, JVM engines defaulting to 1/4 RAM heap each), with the fix inline (TURBO_TESTS2_MAX_PROCESSES=2 + capped heap); start_subprocess and max_processes_from_environment document the spawn-based engine-portable architecture
|
|
45
|
+
|
|
46
|
+
## [3.2.16] - 2026-10-14
|
|
47
|
+
|
|
48
|
+
- TAG: [v3.2.16][3.2.16t]
|
|
49
|
+
- COVERAGE: 95.94% -- 993/1035 lines in 11 files
|
|
50
|
+
- BRANCH COVERAGE: 83.86% -- 265/316 branches in 11 files
|
|
51
|
+
- 39.42% documented
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
|
|
55
|
+
- Watchdog kills now actually end the run: kill_remaining_workers takes pids from the live wait_threads (the parallel_tests pid file was unreliable — each track/untrack built a fresh Pids instance, so any normal worker exit wiped the file and the watchdog killed nothing), handle_messages stops at the watchdog sentinel instead of waiting for per-worker exits that can never arrive, and post-kill joins are bounded so a wedged worker can no longer hold the run past the watchdog (observed: CI job printed the stall report, then hung 14 more minutes until cancellation)
|
|
56
|
+
|
|
57
|
+
### Changed
|
|
58
|
+
|
|
59
|
+
- [kc] kettle-jem/template: updated 32 project files:
|
|
60
|
+
- code and tests (1)
|
|
61
|
+
- dependencies (3)
|
|
62
|
+
- other (1)
|
|
63
|
+
- workflows (27)
|
|
64
|
+
|
|
33
65
|
## [3.2.15] - 2026-10-13
|
|
34
66
|
|
|
35
67
|
- TAG: [v3.2.15][3.2.15t]
|
|
@@ -742,7 +774,11 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
742
774
|
|
|
743
775
|
- Initial release
|
|
744
776
|
|
|
745
|
-
[Unreleased]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.2.
|
|
777
|
+
[Unreleased]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.2.17...HEAD
|
|
778
|
+
[3.2.17]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.2.16...v3.2.17
|
|
779
|
+
[3.2.17t]: https://github.com/galtzo-floss/turbo_tests2/releases/tag/v3.2.17
|
|
780
|
+
[3.2.16]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.2.15...v3.2.16
|
|
781
|
+
[3.2.16t]: https://github.com/galtzo-floss/turbo_tests2/releases/tag/v3.2.16
|
|
746
782
|
[3.2.15]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.2.14...v3.2.15
|
|
747
783
|
[3.2.15t]: https://github.com/galtzo-floss/turbo_tests2/releases/tag/v3.2.15
|
|
748
784
|
[3.2.14]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.2.13...v3.2.14
|
data/README.md
CHANGED
|
@@ -384,6 +384,60 @@ count at the number of discovered test groups.
|
|
|
384
384
|
Known coverage formatter chatter remains collapsed into the concise coverage
|
|
385
385
|
summary.
|
|
386
386
|
|
|
387
|
+
### Resource-Constrained CI (JVM Engines)
|
|
388
|
+
|
|
389
|
+
Worker parallelism is spawn-based, not fork-based: each worker is started as a
|
|
390
|
+
real subprocess (`Process.spawn` / `Open3.popen3`), never `Kernel#fork`. That
|
|
391
|
+
makes parallel workers engine-portable — MRI, JRuby, and TruffleRuby all run
|
|
392
|
+
the same spawn-based pool, and the default worker count is the machine's core
|
|
393
|
+
count (`Etc.nprocessors`) on every engine. There is no serial-only mode for
|
|
394
|
+
JVM engines unless you ask for one with `TURBO_TESTS2_MAX_PROCESSES=1`.
|
|
395
|
+
|
|
396
|
+
The cost of that portability on JVM engines is memory: each JRuby or
|
|
397
|
+
TruffleRuby worker is a full JVM subprocess, and JRuby defaults its heap to
|
|
398
|
+
one quarter of machine RAM. On a CI runner, `Etc.nprocessors` workers each
|
|
399
|
+
grabbing a quarter of RAM is a recipe for the kernel's OOM killer, which kills
|
|
400
|
+
workers **silently** — every worker stops messaging at once, and the stall
|
|
401
|
+
watchdog then reports total silence. This is a resource problem, not a
|
|
402
|
+
parallelism problem.
|
|
403
|
+
|
|
404
|
+
The fix is to run fewer, smaller workers. This is the canonical
|
|
405
|
+
resource-constrained setup, and the `kettle-jem` CI templates bake it into
|
|
406
|
+
every JRuby workflow they generate:
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
TURBO_TESTS2_MAX_PROCESSES=2 \
|
|
410
|
+
JRUBY_OPTS="-J-Xmx1280m" \
|
|
411
|
+
TURBO_TESTS2_WATCHDOG_SECONDS=1500 \
|
|
412
|
+
bundle exec turbo_tests2
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
Or in a GitHub Actions workflow:
|
|
416
|
+
|
|
417
|
+
```yaml
|
|
418
|
+
env:
|
|
419
|
+
# Fewer, smaller JVM workers on constrained runners.
|
|
420
|
+
TURBO_TESTS2_MAX_PROCESSES: 2
|
|
421
|
+
# Cap each worker JVM's heap (JRuby default: 1/4 of runner RAM).
|
|
422
|
+
JRUBY_OPTS: "-J-Xmx1280m"
|
|
423
|
+
# JVM lanes are slow; give the watchdog room without hitting the job timeout.
|
|
424
|
+
TURBO_TESTS2_WATCHDOG_SECONDS: 1500
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
Guidance:
|
|
428
|
+
|
|
429
|
+
- **Cap workers** (`TURBO_TESTS2_MAX_PROCESSES=2`) when each worker is a heavy
|
|
430
|
+
process: JVM engines, large test suites, or shared/undersized runners. Two
|
|
431
|
+
JVM workers still roughly halve wall-clock time versus one.
|
|
432
|
+
- **Cap the heap** (`JRUBY_OPTS="-J-Xmx1280m"`, or your engine's equivalent)
|
|
433
|
+
so total memory is bounded regardless of runner size.
|
|
434
|
+
- **Raise the watchdog** (1500s) on slow engines: JIT warmup and heavy GC make
|
|
435
|
+
silence windows longer, and you want the watchdog report, not the provider
|
|
436
|
+
timeout, when something genuinely hangs.
|
|
437
|
+
- The same knobs apply to any engine where a worker process is expensive —
|
|
438
|
+
the principle is: bound `workers × per-worker memory` under the runner's
|
|
439
|
+
capacity.
|
|
440
|
+
|
|
387
441
|
### Stall watchdog
|
|
388
442
|
|
|
389
443
|
If the worker message queue goes silent — every worker alive but none
|
|
@@ -859,7 +913,7 @@ Thanks for RTFM. ☺️
|
|
|
859
913
|
[📌gitmoji]: https://gitmoji.dev
|
|
860
914
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
861
915
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
862
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-1.
|
|
916
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-1.035-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
863
917
|
[🔐security]: https://github.com/galtzo-floss/turbo_tests2/blob/main/SECURITY.md
|
|
864
918
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
865
919
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
data/lib/turbo_tests/cli.rb
CHANGED
|
@@ -243,6 +243,16 @@ module TurboTests
|
|
|
243
243
|
]
|
|
244
244
|
end
|
|
245
245
|
|
|
246
|
+
# Inclusive ceiling on the worker pool when neither --count nor --workers
|
|
247
|
+
# is passed. Explicit CLI counts always win. Two main uses:
|
|
248
|
+
#
|
|
249
|
+
# 1. Outer orchestrators (kettle-family) budgeting a machine-wide process
|
|
250
|
+
# pool across concurrent family jobs.
|
|
251
|
+
# 2. Resource-constrained CI, where each worker is an expensive process —
|
|
252
|
+
# JVM engines (JRuby, TruffleRuby) spawn a full JVM per worker, so cap
|
|
253
|
+
# the pool (typically 2) AND the per-worker heap (e.g. JRUBY_OPTS=
|
|
254
|
+
# "-J-Xmx1280m") to stay under runner RAM. See README
|
|
255
|
+
# "Resource-Constrained CI (JVM Engines)".
|
|
246
256
|
def max_processes_from_environment
|
|
247
257
|
value = ENV.fetch("TURBO_TESTS2_MAX_PROCESSES", "").strip
|
|
248
258
|
return if value.empty?
|
data/lib/turbo_tests/runner.rb
CHANGED
|
@@ -318,24 +318,41 @@ module TurboTests
|
|
|
318
318
|
|
|
319
319
|
handle_messages
|
|
320
320
|
|
|
321
|
-
@
|
|
321
|
+
if @watchdog_fired
|
|
322
|
+
# Workers were SIGKILLed by the watchdog; their reader threads end
|
|
323
|
+
# at EOF and waiters return as the OS reaps them — but if a kill
|
|
324
|
+
# failed (permissions, zombie, pid reuse) an unbounded join here
|
|
325
|
+
# would hang the run anyway, defeating the watchdog. Bound every
|
|
326
|
+
# join and treat any worker that still has not exited as failed.
|
|
327
|
+
@threads.each do |thread|
|
|
328
|
+
thread.join(FORCE_STOP_JOIN)
|
|
329
|
+
thread.kill if thread.alive?
|
|
330
|
+
end
|
|
331
|
+
@wait_threads.each do |wait_thr|
|
|
332
|
+
wait_thr.join(FORCE_STOP_JOIN)
|
|
333
|
+
end
|
|
334
|
+
flush_worker_output unless stream_worker_output?
|
|
335
|
+
exit_status = 1
|
|
336
|
+
else
|
|
337
|
+
@threads.each(&:join)
|
|
322
338
|
|
|
323
|
-
|
|
339
|
+
report_workers_without_results
|
|
324
340
|
|
|
325
|
-
|
|
341
|
+
report_failed_group(tests_in_groups) if @print_failed_group
|
|
326
342
|
|
|
327
|
-
|
|
343
|
+
Signal.trap(:INT, old_signal)
|
|
328
344
|
|
|
329
|
-
|
|
345
|
+
statuses = @wait_threads.map(&:value)
|
|
330
346
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
347
|
+
if @reporter.failed_examples.empty? && statuses.all?(&:success?)
|
|
348
|
+
flush_successful_worker_output
|
|
349
|
+
report_coverage = true
|
|
350
|
+
exit_status = 0
|
|
351
|
+
else
|
|
352
|
+
flush_worker_output unless stream_worker_output?
|
|
353
|
+
# From https://github.com/galtzo-floss/turbo_tests2/pull/20/
|
|
354
|
+
exit_status = statuses.map(&:exitstatus).max
|
|
355
|
+
end
|
|
339
356
|
end
|
|
340
357
|
end
|
|
341
358
|
|
|
@@ -391,6 +408,14 @@ module TurboTests
|
|
|
391
408
|
)
|
|
392
409
|
end
|
|
393
410
|
|
|
411
|
+
# Spawns one worker as a real OS subprocess via Open3.popen3 — never
|
|
412
|
+
# Kernel#fork. This is what makes the worker pool engine-portable: MRI,
|
|
413
|
+
# JRuby, and TruffleRuby all spawn subprocesses the same way, and the
|
|
414
|
+
# default pool size is Etc.nprocessors on every engine. Remember each
|
|
415
|
+
# worker is a full interpreter/VM process: on JVM engines that is a whole
|
|
416
|
+
# JVM with its own heap, so bound the pool (TURBO_TESTS2_MAX_PROCESSES)
|
|
417
|
+
# and the per-worker heap (e.g. JRUBY_OPTS) on memory-constrained
|
|
418
|
+
# runners — see README "Resource-Constrained CI (JVM Engines)".
|
|
394
419
|
def start_subprocess(env, extra_args, tests, process_id, record_runtime:)
|
|
395
420
|
if tests.empty?
|
|
396
421
|
@messages << {
|
|
@@ -739,6 +764,14 @@ module TurboTests
|
|
|
739
764
|
# on the queue forever — CI jobs hung for hours with no diagnostics.
|
|
740
765
|
# On a stall we kill the surviving worker pids, report which groups
|
|
741
766
|
# never finished, and fail the run instead.
|
|
767
|
+
#
|
|
768
|
+
# Note the OOM killer is the most common silent worker death on CI: the
|
|
769
|
+
# kernel kills the process with no stderr, no exit message, and no
|
|
770
|
+
# partial output. Workers are spawn-based real processes (never forked),
|
|
771
|
+
# so on JVM engines (JRuby, TruffleRuby) each one is a full JVM whose
|
|
772
|
+
# default heap can be 1/4 of machine RAM — a core-count pool of those
|
|
773
|
+
# exhausts a CI runner. Bound `workers x per-worker memory` on
|
|
774
|
+
# constrained runners (see README "Resource-Constrained CI").
|
|
742
775
|
def pop_message_with_watchdog
|
|
743
776
|
# 0 (the default) disables the watchdog: block indefinitely, exactly the
|
|
744
777
|
# pre-watchdog behavior.
|
|
@@ -759,6 +792,11 @@ module TurboTests
|
|
|
759
792
|
"turbo_tests2: watchdog fired after #{@watchdog_seconds}s without worker messages; workers killed\n#{stall_report}"
|
|
760
793
|
)
|
|
761
794
|
@error = true
|
|
795
|
+
# The run is over: workers were just SIGKILLed. handle_messages must
|
|
796
|
+
# not keep waiting for per-worker exit messages that can never
|
|
797
|
+
# arrive, and the caller must not re-enter this watchdog (which would
|
|
798
|
+
# warn-and-kill in a 1-second spin).
|
|
799
|
+
@watchdog_fired = true
|
|
762
800
|
return {type: "exit", process_id: :watchdog}
|
|
763
801
|
end
|
|
764
802
|
end
|
|
@@ -792,7 +830,19 @@ module TurboTests
|
|
|
792
830
|
end
|
|
793
831
|
|
|
794
832
|
def kill_remaining_workers
|
|
795
|
-
|
|
833
|
+
# The live waiter objects are authoritative: the parallel_tests pid file
|
|
834
|
+
# loses entries because every track/untrack call builds a fresh Pids
|
|
835
|
+
# instance whose in-memory list starts empty, so a save overwrites (or,
|
|
836
|
+
# for untrack, empties) the file. After any normal worker exit the file
|
|
837
|
+
# is guaranteed useless — exactly when the watchdog needs it most.
|
|
838
|
+
pids = (@wait_threads || []).map do |wait_thr|
|
|
839
|
+
begin
|
|
840
|
+
wait_thr.pid
|
|
841
|
+
rescue
|
|
842
|
+
nil
|
|
843
|
+
end
|
|
844
|
+
end.compact
|
|
845
|
+
(pids | tracked_pids).each do |pid|
|
|
796
846
|
begin
|
|
797
847
|
Process.kill("KILL", pid)
|
|
798
848
|
rescue
|
|
@@ -822,7 +872,10 @@ module TurboTests
|
|
|
822
872
|
"outer process watcher (a CI job timeout, a container orchestrator, or a local supervisor) will then " \
|
|
823
873
|
"be what eventually ends the run, usually without a useful stall report. A single long test only " \
|
|
824
874
|
"trips this in serial lanes (TURBO_TESTS2_MAX_PROCESSES=1); in parallel lanes other workers keep " \
|
|
825
|
-
"messages flowing."
|
|
875
|
+
"messages flowing. Total silence in a PARALLEL lane usually means workers died rather than slowed " \
|
|
876
|
+
"down — the most common cause is the kernel OOM killer (each worker is a real spawned process; on " \
|
|
877
|
+
"JVM engines each is a full JVM whose default heap is 1/4 of RAM). Cap workers x per-worker memory: " \
|
|
878
|
+
"TURBO_TESTS2_MAX_PROCESSES=2 with a capped heap (e.g. JRUBY_OPTS=\"-J-Xmx1280m\")."
|
|
826
879
|
)
|
|
827
880
|
warned_silence = true
|
|
828
881
|
end
|
|
@@ -870,6 +923,10 @@ module TurboTests
|
|
|
870
923
|
nil
|
|
871
924
|
when "exit"
|
|
872
925
|
process_id = message[:process_id]
|
|
926
|
+
# Watchdog exit: workers were just SIGKILLed and no further per-worker
|
|
927
|
+
# exit messages can be relied upon — stop the loop immediately
|
|
928
|
+
# instead of waiting for process_count exits that never arrive.
|
|
929
|
+
break if process_id == :watchdog
|
|
873
930
|
next if exited_process_ids.key?(process_id)
|
|
874
931
|
|
|
875
932
|
exited_process_ids[process_id] = true
|
data/lib/turbo_tests/version.rb
CHANGED
|
@@ -4,7 +4,7 @@ module TurboTests
|
|
|
4
4
|
# Version namespace for this gem.
|
|
5
5
|
module Version
|
|
6
6
|
# Current gem version.
|
|
7
|
-
VERSION = "3.2.
|
|
7
|
+
VERSION = "3.2.17"
|
|
8
8
|
end
|
|
9
9
|
# Current gem version exposed at the traditional constant location.
|
|
10
10
|
VERSION = Version::VERSION # Traditional Constant Location
|
data.tar.gz.sig
CHANGED
|
Binary file
|
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.2.
|
|
4
|
+
version: 3.2.17
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Illia
|
|
@@ -111,7 +111,7 @@ dependencies:
|
|
|
111
111
|
version: '3.1'
|
|
112
112
|
- - ">="
|
|
113
113
|
- !ruby/object:Gem::Version
|
|
114
|
-
version: 3.1.
|
|
114
|
+
version: 3.1.12
|
|
115
115
|
type: :development
|
|
116
116
|
prerelease: false
|
|
117
117
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -121,7 +121,7 @@ dependencies:
|
|
|
121
121
|
version: '3.1'
|
|
122
122
|
- - ">="
|
|
123
123
|
- !ruby/object:Gem::Version
|
|
124
|
-
version: 3.1.
|
|
124
|
+
version: 3.1.12
|
|
125
125
|
- !ruby/object:Gem::Dependency
|
|
126
126
|
name: bundler-audit
|
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -219,7 +219,7 @@ dependencies:
|
|
|
219
219
|
version: '2.0'
|
|
220
220
|
- - ">="
|
|
221
221
|
- !ruby/object:Gem::Version
|
|
222
|
-
version: 2.0.
|
|
222
|
+
version: 2.0.25
|
|
223
223
|
type: :development
|
|
224
224
|
prerelease: false
|
|
225
225
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -229,7 +229,7 @@ dependencies:
|
|
|
229
229
|
version: '2.0'
|
|
230
230
|
- - ">="
|
|
231
231
|
- !ruby/object:Gem::Version
|
|
232
|
-
version: 2.0.
|
|
232
|
+
version: 2.0.25
|
|
233
233
|
- !ruby/object:Gem::Dependency
|
|
234
234
|
name: ruby-progressbar
|
|
235
235
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -316,10 +316,10 @@ licenses:
|
|
|
316
316
|
- MIT
|
|
317
317
|
metadata:
|
|
318
318
|
homepage_uri: https://turbo-tests2.galtzo.com
|
|
319
|
-
source_code_uri: https://github.com/galtzo-floss/turbo_tests2/tree/v3.2.
|
|
320
|
-
changelog_uri: https://github.com/galtzo-floss/turbo_tests2/blob/v3.2.
|
|
319
|
+
source_code_uri: https://github.com/galtzo-floss/turbo_tests2/tree/v3.2.17
|
|
320
|
+
changelog_uri: https://github.com/galtzo-floss/turbo_tests2/blob/v3.2.17/CHANGELOG.md
|
|
321
321
|
bug_tracker_uri: https://github.com/galtzo-floss/turbo_tests2/issues
|
|
322
|
-
documentation_uri: https://www.rubydoc.info/gems/turbo_tests2/3.2.
|
|
322
|
+
documentation_uri: https://www.rubydoc.info/gems/turbo_tests2/3.2.17
|
|
323
323
|
funding_uri: https://github.com/sponsors/pboling
|
|
324
324
|
wiki_uri: https://github.com/galtzo-floss/turbo_tests2/wiki
|
|
325
325
|
news_uri: https://www.railsbling.com/tags/turbo_tests2
|
metadata.gz.sig
CHANGED
|
Binary file
|