turbo_tests2 3.0.0 → 3.1.0
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 +54 -1
- data/CONTRIBUTING.md +21 -0
- data/LICENSE.md +22 -0
- data/README.md +11 -20
- data/lib/turbo_tests/cli.rb +47 -1
- data/lib/turbo_tests/json_rows_formatter.rb +48 -2
- data/lib/turbo_tests/reporter.rb +21 -0
- data/lib/turbo_tests/runner.rb +45 -1
- data/lib/turbo_tests/shim.rb +10 -1
- data/lib/turbo_tests/version.rb +1 -1
- data/lib/turbo_tests.rb +2 -0
- data/lib/turbo_tests2/rspec/shared_contexts/simplecov_spawn.rb +6 -2
- data/sig/turbo_tests/version.rbs +0 -1
- data.tar.gz.sig +0 -0
- metadata +19 -11
- 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: d311bffe032ad5025cceb6e487460d7e1c0d1e87cc07134eafb4f41bdc63d515
|
|
4
|
+
data.tar.gz: 0a07a421cad5fadb52d3c417fd0626f80159e4757d8a393fe3ac4912c343dba5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f9745db1b03fd8ef015807cab9518079449ffa6d033d898141eec7f815edbd1dcb1a95f9bf7fd361d6e429d8573fa0668ef7b4ca295c2ad116d72bbb63d35c53
|
|
7
|
+
data.tar.gz: fe28b347bae32babcdfc80fcf1523b43f54c17dd3726eaeae5e6c4101127685a967e80ef4789c13b47bb16e682282ab5318f9a89b6cce0a16984235128143450
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,57 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [3.1.0] - 2026-05-28
|
|
34
|
+
|
|
35
|
+
- TAG: [v3.1.0][3.1.0t]
|
|
36
|
+
- COVERAGE: 95.01% -- 609/641 lines in 16 files
|
|
37
|
+
- BRANCH COVERAGE: 77.54% -- 107/138 branches in 16 files
|
|
38
|
+
- 36.78% documented
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- `-w` / `--workers` aliases for `-n`, matching the worker-count terminology used by other
|
|
43
|
+
parallel test runners.
|
|
44
|
+
- `turbo_tests2 fan`, a generic worker fan-out command that runs an arbitrary command once per
|
|
45
|
+
worker with `TEST_ENV_NUMBER` and `PARALLEL_TEST_GROUPS` set.
|
|
46
|
+
- `--example-status-log FILE`, which converts RSpec example-status persistence data into a
|
|
47
|
+
`parallel_tests`-compatible runtime log so grouping can use example-level timing history.
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
|
|
51
|
+
- Worker subprocess JSON now forwards RSpec deprecation notifications to the parent reporter.
|
|
52
|
+
- Worker subprocess JSON now forwards RSpec profile output to the parent reporter.
|
|
53
|
+
- Fail-fast runs now report spec groups that were stopped before execution.
|
|
54
|
+
- Interrupted runs now report spec groups that had not finished before shutdown.
|
|
55
|
+
|
|
56
|
+
### Fixed
|
|
57
|
+
|
|
58
|
+
- Reconstructed failure backtraces now filter internal `turbo_tests2` frames.
|
|
59
|
+
- Coverage was refreshed by adding focused specs for the new CLI, reporting, formatter, and
|
|
60
|
+
grouping behaviors.
|
|
61
|
+
|
|
62
|
+
- RSpec deprecation notification reconstruction now uses the public `from_hash` API so CI passes
|
|
63
|
+
with RSpec versions where `.new` is private.
|
|
64
|
+
- The shim command result object no longer depends on `Struct#keyword_init`, restoring Ruby 2.4
|
|
65
|
+
compatibility.
|
|
66
|
+
- Backtrace output specs now accept JRuby 9.2's legacy `block in <main>` frame wording.
|
|
67
|
+
- GitHub Actions test jobs now force `kettle-test` to use its direct RSpec runner so coverage
|
|
68
|
+
aggregation remains stable while testing `turbo_tests2` itself.
|
|
69
|
+
- GitHub Actions appraisal jobs now pass explicit parent-directory RSpec paths so direct RSpec
|
|
70
|
+
runs execute the real suite instead of finding zero examples from `gemfiles/`.
|
|
71
|
+
- Spawned-process coverage setup now locates `.simplecov_spawn.rb` from the working directory
|
|
72
|
+
instead of `Bundler.root`, so appraisal gemfiles do not point it at `gemfiles/`.
|
|
73
|
+
- The coverage workflow now uses the same hard coverage thresholds as local development.
|
|
74
|
+
- The dedicated coverage workflow now runs RSpec directly so coverage artifacts are written under
|
|
75
|
+
the repository root for upload steps.
|
|
76
|
+
- Removed the advanced CodeQL workflow because GitHub CodeQL default setup is enabled and rejects
|
|
77
|
+
SARIF uploads from advanced configurations.
|
|
78
|
+
|
|
79
|
+
### Security
|
|
80
|
+
|
|
81
|
+
- Refreshed pinned GitHub Action SHAs.
|
|
82
|
+
- Added checksums for the `v3.0.0` release artifacts.
|
|
83
|
+
|
|
33
84
|
## [3.0.0] - 2026-05-22
|
|
34
85
|
|
|
35
86
|
- TAG: [v3.0.0][3.0.0t]
|
|
@@ -41,6 +92,8 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
41
92
|
|
|
42
93
|
- Initial release
|
|
43
94
|
|
|
44
|
-
[Unreleased]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.
|
|
95
|
+
[Unreleased]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.1.0...HEAD
|
|
96
|
+
[3.1.0]: https://github.com/galtzo-floss/turbo_tests2/compare/v3.0.0...v3.1.0
|
|
97
|
+
[3.1.0t]: https://github.com/galtzo-floss/turbo_tests2/releases/tag/v3.1.0
|
|
45
98
|
[3.0.0]: https://github.com/galtzo-floss/turbo_tests2/compare/7d4064e5b8acc2f53929fccf7be3eb63f8a9f140...v3.0.0
|
|
46
99
|
[3.0.0t]: https://github.com/galtzo-floss/turbo_tests2/releases/tag/v3.0.0
|
data/CONTRIBUTING.md
CHANGED
|
@@ -50,6 +50,22 @@ There are many Rake tasks available as well. You can see them by running:
|
|
|
50
50
|
bin/rake -T
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
+
## Code quality checks
|
|
54
|
+
|
|
55
|
+
Run the Reek task when you want a smell check that fails on current findings:
|
|
56
|
+
|
|
57
|
+
```shell
|
|
58
|
+
bin/rake reek
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Refresh the checked-in `REEK` backlog through the rake task, not by redirecting
|
|
62
|
+
the raw `reek` executable output. The rake task uses the project bundle and
|
|
63
|
+
avoids stale generated binstubs shadowing the Reek gem executable:
|
|
64
|
+
|
|
65
|
+
```shell
|
|
66
|
+
bin/rake reek:update
|
|
67
|
+
```
|
|
68
|
+
|
|
53
69
|
## Environment Variables for Local Development
|
|
54
70
|
|
|
55
71
|
Below are the primary environment variables recognized by stone_checksums (and its integrated tools). Unless otherwise noted, set boolean values to the string "true" to enable.
|
|
@@ -91,6 +107,11 @@ For a quick starting point, this repository’s `mise.toml` defines the shared d
|
|
|
91
107
|
## Appraisals
|
|
92
108
|
|
|
93
109
|
From time to time the [appraisal2][🚎appraisal2] gemfiles in `gemfiles/` will need to be updated.
|
|
110
|
+
Generated appraisal and CI workflow floors are controlled by `ruby.test_minimum`
|
|
111
|
+
in `.kettle-jem.yml`; this project was templated with `ruby.test_minimum: 2.4`.
|
|
112
|
+
That value describes the lowest Ruby version expected to run the test/development
|
|
113
|
+
toolchain, and it may be higher than the gemspec runtime floor.
|
|
114
|
+
|
|
94
115
|
They are created and updated with the commands:
|
|
95
116
|
|
|
96
117
|
```console
|
data/LICENSE.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# License
|
|
2
|
+
|
|
3
|
+
This project is made available under the following license.
|
|
4
|
+
Choose the option that best fits your use case:
|
|
5
|
+
|
|
6
|
+
- [MIT](MIT.md)
|
|
7
|
+
|
|
8
|
+
## Copyright Notice
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2020-2023 Illia
|
|
11
|
+
Copyright (c) 2020 Ilya Zub
|
|
12
|
+
Copyright (c) 2021 AMHOL
|
|
13
|
+
Copyright (c) 2021 Serge Bedzhyk
|
|
14
|
+
Copyright (c) 2023 Bo Anderson
|
|
15
|
+
Copyright (c) 2023 Dmitiry Zub☀️
|
|
16
|
+
Copyright (c) 2023-2024 Illia
|
|
17
|
+
Copyright (c) 2023 mrudzki
|
|
18
|
+
Copyright (c) 2023-2024 Sebastien Savater
|
|
19
|
+
Copyright (c) 2024 David Rodriguez
|
|
20
|
+
Copyright (c) 2024 Hiroshi SHIBATA
|
|
21
|
+
Copyright (c) 2025 Gareth Jones
|
|
22
|
+
Copyright (c) 2025-2026 Peter H. Boling
|
data/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
# 🚀 TurboTests
|
|
11
11
|
|
|
12
|
-
[![Version][👽versioni]][👽version] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: MIT][📄license-img]][📄license] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![CodeCov Test Coverage][🏀codecovi]][🏀codecov] [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls] [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov] [![QLTY Maintainability][🏀qlty-mnti]][🏀qlty-mnt] [![CI Heads][🚎3-hd-wfi]][🚎3-hd-wf] [![CI Runtime Dependencies @ HEAD][🚎12-crh-wfi]][🚎12-crh-wf] [![CI Current][🚎11-c-wfi]][🚎11-c-wf] [![CI Truffle Ruby][🚎9-t-wfi]][🚎9-t-wf] [![CI JRuby][🚎10-j-wfi]][🚎10-j-wf] [![Deps Locked][🚎13-🔒️-wfi]][🚎13-🔒️-wf] [![Deps Unlocked][🚎14-🔓️-wfi]][🚎14-🔓️-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf] [![
|
|
12
|
+
[![Version][👽versioni]][👽version] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: MIT][📄license-img]][📄license] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![CodeCov Test Coverage][🏀codecovi]][🏀codecov] [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls] [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov] [![QLTY Maintainability][🏀qlty-mnti]][🏀qlty-mnt] [![CI Heads][🚎3-hd-wfi]][🚎3-hd-wf] [![CI Runtime Dependencies @ HEAD][🚎12-crh-wfi]][🚎12-crh-wf] [![CI Current][🚎11-c-wfi]][🚎11-c-wf] [![CI Truffle Ruby][🚎9-t-wfi]][🚎9-t-wf] [![CI JRuby][🚎10-j-wfi]][🚎10-j-wf] [![Deps Locked][🚎13-🔒️-wfi]][🚎13-🔒️-wf] [![Deps Unlocked][🚎14-🔓️-wfi]][🚎14-🔓️-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf] [![Apache SkyWalking Eyes License Compatibility Check][🚎15-🪪-wfi]][🚎15-🪪-wf]
|
|
13
13
|
|
|
14
14
|
`if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know][🖼️galtzo-floss], as I may have missed the [discord notification][🖼️galtzo-floss].
|
|
15
15
|
|
|
@@ -89,24 +89,16 @@ Finished in 2 minute 25.15 seconds (files took 0 seconds to load)
|
|
|
89
89
|
### Compatibility
|
|
90
90
|
|
|
91
91
|
Compatible with MRI Ruby 2.4.0+, and concordant releases of JRuby, and TruffleRuby.
|
|
92
|
+
CI workflows and Appraisals are generated for MRI Ruby 2.4+.
|
|
93
|
+
This test floor is configured by `ruby.test_minimum` in `.kettle-jem.yml` and
|
|
94
|
+
may be higher than the gem's runtime compatibility floor when legacy Rubies are
|
|
95
|
+
not practical for the current toolchain.
|
|
92
96
|
|
|
93
97
|
| 🚚 _Amazing_ test matrix was brought to you by | 🔎 appraisal2 🔎 and the color 💚 green 💚 |
|
|
94
98
|
|------------------------------------------------|--------------------------------------------------------|
|
|
95
99
|
| 👟 Check it out! | ✨ [github.com/appraisal-rb/appraisal2][💎appraisal2] ✨ |
|
|
96
100
|
|
|
97
|
-
<details markdown="1">
|
|
98
|
-
<summary>StructuredMerge package family</summary>
|
|
99
|
-
|
|
100
|
-
This gem is part of the StructuredMerge Ruby package family. The implementation inventory, layering model, and backend notes live in the [root package-family guide][sm-family-guide]. Shared behavior is defined by the [StructuredMerge fixtures][sm-family-fixtures] and implemented by the [Go][sm-family-go], [Ruby][sm-family-ruby], [Rust][sm-family-rust], and [TypeScript][sm-family-typescript] repositories.
|
|
101
101
|
|
|
102
|
-
</details>
|
|
103
|
-
|
|
104
|
-
[sm-family-guide]: https://github.com/structuredmerge/structuredmerge-ruby#package-family
|
|
105
|
-
[sm-family-fixtures]: https://github.com/structuredmerge/structuredmerge-fixtures
|
|
106
|
-
[sm-family-go]: https://github.com/structuredmerge/structuredmerge-go
|
|
107
|
-
[sm-family-ruby]: https://github.com/structuredmerge/structuredmerge-ruby
|
|
108
|
-
[sm-family-rust]: https://github.com/structuredmerge/structuredmerge-rust
|
|
109
|
-
[sm-family-typescript]: https://github.com/structuredmerge/structuredmerge-typescript
|
|
110
102
|
|
|
111
103
|
### Federated DVCS
|
|
112
104
|
|
|
@@ -406,7 +398,7 @@ For most applications, prefer the [Pessimistic Version Constraint][📌pvc] with
|
|
|
406
398
|
For example:
|
|
407
399
|
|
|
408
400
|
```ruby
|
|
409
|
-
spec.add_dependency("turbo_tests2", "~>
|
|
401
|
+
spec.add_dependency("turbo_tests2", "~> 3.0")
|
|
410
402
|
```
|
|
411
403
|
|
|
412
404
|
<details markdown="1">
|
|
@@ -436,7 +428,7 @@ See [LICENSE.md][📄license] for the official copyright notice.
|
|
|
436
428
|
<details markdown="1">
|
|
437
429
|
<summary>Copyright holders</summary>
|
|
438
430
|
|
|
439
|
-
- Copyright (c) 2020-2023
|
|
431
|
+
- Copyright (c) 2020-2023 Illia
|
|
440
432
|
- Copyright (c) 2020 Ilya Zub
|
|
441
433
|
- Copyright (c) 2021 AMHOL
|
|
442
434
|
- Copyright (c) 2021 Serge Bedzhyk
|
|
@@ -573,8 +565,6 @@ Thanks for RTFM. ☺️
|
|
|
573
565
|
[🏀codecovi]: https://codecov.io/gh/galtzo-floss/turbo_tests2/graph/badge.svg
|
|
574
566
|
[🏀coveralls]: https://coveralls.io/github/galtzo-floss/turbo_tests2?branch=main
|
|
575
567
|
[🏀coveralls-img]: https://coveralls.io/repos/github/galtzo-floss/turbo_tests2/badge.svg?branch=main
|
|
576
|
-
[🖐codeQL]: https://github.com/galtzo-floss/turbo_tests2/security/code-scanning
|
|
577
|
-
[🖐codeQL-img]: https://github.com/galtzo-floss/turbo_tests2/actions/workflows/codeql-analysis.yml/badge.svg
|
|
578
568
|
[🚎ruby-2.4-wf]: https://github.com/galtzo-floss/turbo_tests2/actions/workflows/ruby-2.4.yml
|
|
579
569
|
[🚎ruby-2.5-wf]: https://github.com/galtzo-floss/turbo_tests2/actions/workflows/ruby-2.5.yml
|
|
580
570
|
[🚎ruby-2.6-wf]: https://github.com/galtzo-floss/turbo_tests2/actions/workflows/ruby-2.6.yml
|
|
@@ -643,7 +633,7 @@ Thanks for RTFM. ☺️
|
|
|
643
633
|
[🤝cb-pulls]: https://codeberg.org/galtzo-floss/turbo_tests2/pulls
|
|
644
634
|
[🤝cb-donate]: https://donate.codeberg.org/
|
|
645
635
|
[🤝contributing]: https://github.com/galtzo-floss/turbo_tests2/blob/main/CONTRIBUTING.md
|
|
646
|
-
[🏀codecov-g]: https://codecov.io/gh/galtzo-floss/turbo_tests2/
|
|
636
|
+
[🏀codecov-g]: https://codecov.io/gh/galtzo-floss/turbo_tests2/graph/badge.svg
|
|
647
637
|
[🖐contrib-rocks]: https://contrib.rocks
|
|
648
638
|
[🖐contributors]: https://github.com/galtzo-floss/turbo_tests2/graphs/contributors
|
|
649
639
|
[🖐contributors-img]: https://contrib.rocks/image?repo=galtzo-floss/turbo_tests2
|
|
@@ -661,7 +651,7 @@ Thanks for RTFM. ☺️
|
|
|
661
651
|
[📌gitmoji]: https://gitmoji.dev
|
|
662
652
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
663
653
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
664
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.
|
|
654
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.641-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
665
655
|
[🔐security]: https://github.com/galtzo-floss/turbo_tests2/blob/main/SECURITY.md
|
|
666
656
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
667
657
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
|
@@ -670,6 +660,7 @@ Thanks for RTFM. ☺️
|
|
|
670
660
|
[📄license-img]: https://img.shields.io/badge/License-MIT-259D6C.svg
|
|
671
661
|
[📄license-compat]: https://www.apache.org/legal/resolved.html#category-a
|
|
672
662
|
[📄license-compat-img]: https://img.shields.io/badge/Apache_Compatible:_Category_A-✓-259D6C.svg?style=flat&logo=Apache
|
|
663
|
+
|
|
673
664
|
[📄ilo-declaration]: https://www.ilo.org/declaration/lang--en/index.htm
|
|
674
665
|
[📄ilo-declaration-img]: https://img.shields.io/badge/ILO_Fundamental_Principles-✓-259D6C.svg?style=flat
|
|
675
666
|
[🚎yard-current]: http://rubydoc.info/gems/turbo_tests2
|
|
@@ -688,7 +679,7 @@ Thanks for RTFM. ☺️
|
|
|
688
679
|
| Package | turbo_tests2 |
|
|
689
680
|
| Description | 🚀 `turbo_tests2` is a drop-in replacement for `serpapi/turbo_tests` and `grosser/parallel_tests` with incremental summarized output. Source code of `turbo_test2` gem is based on Discourse and Rubygems work in this area (see README file of the source repository). |
|
|
690
681
|
| Homepage | https://github.com/galtzo-floss/turbo_tests2 |
|
|
691
|
-
| Source | https://github.com/galtzo-floss/turbo_tests2 |
|
|
682
|
+
| Source | https://github.com/galtzo-floss/turbo_tests2/tree/v3.0.0 |
|
|
692
683
|
| License | `MIT` |
|
|
693
684
|
| Funding | https://github.com/sponsors/pboling, https://issuehunt.io/u/pboling, https://ko-fi.com/pboling, https://liberapay.com/pboling/donate, https://opencollective.com/galtzo-floss, https://patreon.com/galtzo, https://polar.sh/pboling, https://thanks.dev/u/gh/pboling, https://tidelift.com/funding/github/rubygems/turbo_tests2, https://www.buymeacoffee.com/pboling |
|
|
694
685
|
<!-- kettle-jem:metadata:end -->
|
data/lib/turbo_tests/cli.rb
CHANGED
|
@@ -10,12 +10,14 @@ module TurboTests
|
|
|
10
10
|
|
|
11
11
|
def run
|
|
12
12
|
handle_shim_command if shim_command?
|
|
13
|
+
handle_fan_command if fan_command?
|
|
13
14
|
|
|
14
15
|
requires = []
|
|
15
16
|
formatters = []
|
|
16
17
|
tags = []
|
|
17
18
|
count = nil
|
|
18
19
|
runtime_log = nil
|
|
20
|
+
example_status_log = nil
|
|
19
21
|
verbose = false
|
|
20
22
|
fail_fast = nil
|
|
21
23
|
seed = nil
|
|
@@ -39,7 +41,9 @@ module TurboTests
|
|
|
39
41
|
Options:
|
|
40
42
|
BANNER
|
|
41
43
|
|
|
42
|
-
opts.on("-n [PROCESSES]", Integer, "How many processes to use, default: available CPUs")
|
|
44
|
+
opts.on("-n [PROCESSES]", "-w [PROCESSES]", "--workers [PROCESSES]", Integer, "How many processes to use, default: available CPUs") do |n|
|
|
45
|
+
count = n
|
|
46
|
+
end
|
|
43
47
|
|
|
44
48
|
opts.on("-r", "--require PATH", "Require a file.") do |filename|
|
|
45
49
|
requires << filename
|
|
@@ -74,6 +78,10 @@ module TurboTests
|
|
|
74
78
|
runtime_log = filename
|
|
75
79
|
end
|
|
76
80
|
|
|
81
|
+
opts.on("--example-status-log FILE", "Use RSpec example status persistence timings for grouping") do |filename|
|
|
82
|
+
example_status_log = filename
|
|
83
|
+
end
|
|
84
|
+
|
|
77
85
|
opts.on("-v", "--verbose", "More output") do
|
|
78
86
|
verbose = true
|
|
79
87
|
end
|
|
@@ -133,6 +141,7 @@ module TurboTests
|
|
|
133
141
|
tags: tags,
|
|
134
142
|
files: files,
|
|
135
143
|
runtime_log: runtime_log,
|
|
144
|
+
example_status_log: example_status_log,
|
|
136
145
|
verbose: verbose,
|
|
137
146
|
fail_fast: fail_fast,
|
|
138
147
|
count: count,
|
|
@@ -154,6 +163,43 @@ module TurboTests
|
|
|
154
163
|
@argv.first == "shim"
|
|
155
164
|
end
|
|
156
165
|
|
|
166
|
+
def fan_command?
|
|
167
|
+
@argv.first == "fan"
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def handle_fan_command
|
|
171
|
+
args = @argv.drop(1)
|
|
172
|
+
count = nil
|
|
173
|
+
parser = OptionParser.new do |opts|
|
|
174
|
+
opts.banner = "Usage: turbo_tests2 fan [options] COMMAND [ARGS]"
|
|
175
|
+
opts.on("-n [PROCESSES]", "-w [PROCESSES]", "--workers [PROCESSES]", Integer, "How many processes to use, default: available CPUs") do |n|
|
|
176
|
+
count = n
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
parser.order!(args)
|
|
180
|
+
|
|
181
|
+
if args.empty?
|
|
182
|
+
warn(parser)
|
|
183
|
+
exit(1)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
processes = ParallelTests.determine_number_of_processes(count)
|
|
187
|
+
pids = (1..processes).map do |process_id|
|
|
188
|
+
env = {
|
|
189
|
+
"TEST_ENV_NUMBER" => process_id.to_s,
|
|
190
|
+
"PARALLEL_TEST_GROUPS" => processes.to_s,
|
|
191
|
+
}
|
|
192
|
+
Process.spawn(env, *args)
|
|
193
|
+
end
|
|
194
|
+
statuses = pids.map { |pid| Process.wait2(pid).last }
|
|
195
|
+
|
|
196
|
+
exit(statuses.all?(&:success?) ? 0 : 1)
|
|
197
|
+
rescue OptionParser::ParseError => e
|
|
198
|
+
warn(e.message)
|
|
199
|
+
warn(parser)
|
|
200
|
+
exit(1)
|
|
201
|
+
end
|
|
202
|
+
|
|
157
203
|
def handle_shim_command
|
|
158
204
|
command = @argv[1]
|
|
159
205
|
args = @argv.drop(2)
|
|
@@ -20,6 +20,12 @@ RSpec::Core::Runner.singleton_class.prepend(RSpecExt)
|
|
|
20
20
|
module TurboTests
|
|
21
21
|
# An RSpec formatter used for each subprocess during parallel test execution
|
|
22
22
|
class JsonRowsFormatter
|
|
23
|
+
INTERNAL_BACKTRACE_PATTERNS = [
|
|
24
|
+
%r{/bin/turbo_tests2\b},
|
|
25
|
+
%r{/exe/turbo_tests2\b},
|
|
26
|
+
%r{/lib/turbo_tests(?:\.rb|/)},
|
|
27
|
+
].freeze
|
|
28
|
+
|
|
23
29
|
RSpec::Core::Formatters.register(
|
|
24
30
|
self,
|
|
25
31
|
:start,
|
|
@@ -31,6 +37,8 @@ module TurboTests
|
|
|
31
37
|
:example_group_finished,
|
|
32
38
|
:message,
|
|
33
39
|
:seed,
|
|
40
|
+
:deprecation,
|
|
41
|
+
:dump_profile,
|
|
34
42
|
)
|
|
35
43
|
|
|
36
44
|
attr_reader :output
|
|
@@ -101,19 +109,56 @@ module TurboTests
|
|
|
101
109
|
)
|
|
102
110
|
end
|
|
103
111
|
|
|
112
|
+
def deprecation(notification)
|
|
113
|
+
output_row(
|
|
114
|
+
type: :deprecation,
|
|
115
|
+
deprecation: deprecation_to_json(notification),
|
|
116
|
+
)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def dump_profile(notification)
|
|
120
|
+
output_row(
|
|
121
|
+
type: :profile,
|
|
122
|
+
profile: profile_to_json(notification),
|
|
123
|
+
)
|
|
124
|
+
end
|
|
125
|
+
|
|
104
126
|
private
|
|
105
127
|
|
|
128
|
+
def profile_to_json(notification)
|
|
129
|
+
{
|
|
130
|
+
duration: notification.duration,
|
|
131
|
+
number_of_examples: notification.number_of_examples,
|
|
132
|
+
examples: notification.examples.map { |example| example_to_json(example) },
|
|
133
|
+
}
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def deprecation_to_json(notification)
|
|
137
|
+
{
|
|
138
|
+
deprecated: notification.deprecated,
|
|
139
|
+
message: notification.message,
|
|
140
|
+
replacement: notification.replacement,
|
|
141
|
+
call_site: notification.call_site,
|
|
142
|
+
}
|
|
143
|
+
end
|
|
144
|
+
|
|
106
145
|
def exception_to_json(exception)
|
|
107
146
|
return unless exception
|
|
108
147
|
|
|
109
148
|
{
|
|
110
149
|
class_name: exception.class.name.to_s,
|
|
111
|
-
backtrace: exception.backtrace,
|
|
150
|
+
backtrace: filtered_backtrace(exception.backtrace),
|
|
112
151
|
message: exception.message,
|
|
113
152
|
cause: exception_to_json(exception.cause),
|
|
114
153
|
}
|
|
115
154
|
end
|
|
116
155
|
|
|
156
|
+
def filtered_backtrace(backtrace)
|
|
157
|
+
Array(backtrace).reject do |line|
|
|
158
|
+
INTERNAL_BACKTRACE_PATTERNS.any? { |pattern| line.match?(pattern) }
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
117
162
|
def execution_result_to_json(result)
|
|
118
163
|
{
|
|
119
164
|
example_skipped?: result.example_skipped?,
|
|
@@ -121,6 +166,7 @@ module TurboTests
|
|
|
121
166
|
status: result.status,
|
|
122
167
|
pending_fixed?: result.pending_fixed?,
|
|
123
168
|
exception: exception_to_json(result.exception || result.pending_exception),
|
|
169
|
+
run_time: result.respond_to?(:run_time) ? result.run_time : nil,
|
|
124
170
|
}
|
|
125
171
|
end
|
|
126
172
|
|
|
@@ -164,7 +210,7 @@ module TurboTests
|
|
|
164
210
|
end
|
|
165
211
|
|
|
166
212
|
def output_row(obj)
|
|
167
|
-
output.puts ENV
|
|
213
|
+
output.puts "#{ENV.fetch("RSPEC_FORMATTER_OUTPUT_ID", "")}#{obj.to_json}"
|
|
168
214
|
output.flush
|
|
169
215
|
end
|
|
170
216
|
end
|
data/lib/turbo_tests/reporter.rb
CHANGED
|
@@ -127,6 +127,27 @@ module TurboTests
|
|
|
127
127
|
message(error_message)
|
|
128
128
|
end
|
|
129
129
|
|
|
130
|
+
def deprecation(deprecation)
|
|
131
|
+
notification = RSpec::Core::Notifications::DeprecationNotification.from_hash(
|
|
132
|
+
deprecated: deprecation[:deprecated],
|
|
133
|
+
message: deprecation[:message],
|
|
134
|
+
replacement: deprecation[:replacement],
|
|
135
|
+
call_site: deprecation[:call_site],
|
|
136
|
+
)
|
|
137
|
+
delegate_to_formatters(:deprecation, notification)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def profile(profile)
|
|
141
|
+
examples = profile[:examples].map { |example| FakeExample.from_obj(example) }
|
|
142
|
+
notification = RSpec::Core::Notifications::ProfileNotification.new(
|
|
143
|
+
profile[:duration],
|
|
144
|
+
examples,
|
|
145
|
+
profile[:number_of_examples],
|
|
146
|
+
{},
|
|
147
|
+
)
|
|
148
|
+
delegate_to_formatters(:dump_profile, notification)
|
|
149
|
+
end
|
|
150
|
+
|
|
130
151
|
def finish
|
|
131
152
|
end_time = RSpec::Core::Time.now
|
|
132
153
|
|
data/lib/turbo_tests/runner.rb
CHANGED
|
@@ -29,6 +29,7 @@ module TurboTests
|
|
|
29
29
|
|
|
30
30
|
start_time = opts.fetch(:start_time) { RSpec::Core::Time.now }
|
|
31
31
|
runtime_log = opts.fetch(:runtime_log, nil)
|
|
32
|
+
example_status_log = opts.fetch(:example_status_log, nil)
|
|
32
33
|
verbose = opts.fetch(:verbose, false)
|
|
33
34
|
fail_fast = opts.fetch(:fail_fast, nil)
|
|
34
35
|
count = opts.fetch(:count, nil)
|
|
@@ -39,7 +40,10 @@ module TurboTests
|
|
|
39
40
|
|
|
40
41
|
use_runtime_info = files == ["spec"]
|
|
41
42
|
|
|
42
|
-
if
|
|
43
|
+
if example_status_log
|
|
44
|
+
runtime_log = runtime_log_from_example_status(example_status_log)
|
|
45
|
+
parallel_options[:runtime_log] = runtime_log
|
|
46
|
+
elsif use_runtime_info
|
|
43
47
|
parallel_options[:runtime_log] = runtime_log
|
|
44
48
|
else
|
|
45
49
|
parallel_options[:group_by] = :filesize
|
|
@@ -56,6 +60,7 @@ module TurboTests
|
|
|
56
60
|
files: files,
|
|
57
61
|
tags: tags,
|
|
58
62
|
runtime_log: runtime_log,
|
|
63
|
+
example_status_log: example_status_log,
|
|
59
64
|
verbose: verbose,
|
|
60
65
|
fail_fast: fail_fast,
|
|
61
66
|
count: count,
|
|
@@ -67,6 +72,21 @@ module TurboTests
|
|
|
67
72
|
nice: nice,
|
|
68
73
|
).run
|
|
69
74
|
end
|
|
75
|
+
|
|
76
|
+
def runtime_log_from_example_status(example_status_log)
|
|
77
|
+
statuses = RSpec::Core::ExampleStatusPersister.load_from(example_status_log)
|
|
78
|
+
runtimes = statuses.each_with_object(Hash.new(0.0)) do |status, sums|
|
|
79
|
+
next unless status.fetch(:status).match?(/pass/i)
|
|
80
|
+
|
|
81
|
+
file_name = RSpec::Core::Example.parse_id(status.fetch(:example_id)).first
|
|
82
|
+
sums[file_name] += status.fetch(:run_time).to_s[/\d+(\.\d+)?/].to_f
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
path = File.join("tmp", "turbo_tests2_example_status_runtime.log")
|
|
86
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
87
|
+
File.write(path, runtimes.sort.map { |file, runtime| "#{file}:#{runtime}" }.join("\n"))
|
|
88
|
+
path
|
|
89
|
+
end
|
|
70
90
|
end
|
|
71
91
|
|
|
72
92
|
def initialize(**opts)
|
|
@@ -97,6 +117,7 @@ module TurboTests
|
|
|
97
117
|
@messages = Thread::Queue.new
|
|
98
118
|
@threads = []
|
|
99
119
|
@wait_threads = []
|
|
120
|
+
@exited_process_ids = []
|
|
100
121
|
@error = false
|
|
101
122
|
@print_failed_group = opts[:print_failed_group]
|
|
102
123
|
end
|
|
@@ -113,6 +134,7 @@ module TurboTests
|
|
|
113
134
|
@num_processes,
|
|
114
135
|
**@parallel_options,
|
|
115
136
|
)
|
|
137
|
+
@tests_in_groups = tests_in_groups
|
|
116
138
|
|
|
117
139
|
subprocess_opts = {
|
|
118
140
|
record_runtime: @record_runtime,
|
|
@@ -150,6 +172,7 @@ module TurboTests
|
|
|
150
172
|
Kernel.exit
|
|
151
173
|
else
|
|
152
174
|
puts "\nShutting down subprocesses..."
|
|
175
|
+
report_unfinished_groups("Groups not finished")
|
|
153
176
|
@wait_threads.each do |wait_thr|
|
|
154
177
|
begin
|
|
155
178
|
child_pid = wait_thr.pid
|
|
@@ -318,6 +341,7 @@ module TurboTests
|
|
|
318
341
|
@reporter.example_failed(example)
|
|
319
342
|
@failure_count += 1
|
|
320
343
|
if fail_fast_met
|
|
344
|
+
report_unfinished_groups("Groups stopped by fail-fast")
|
|
321
345
|
@threads.each(&:kill)
|
|
322
346
|
break
|
|
323
347
|
end
|
|
@@ -328,6 +352,10 @@ module TurboTests
|
|
|
328
352
|
else
|
|
329
353
|
@reporter.message(message[:message])
|
|
330
354
|
end
|
|
355
|
+
when "deprecation"
|
|
356
|
+
@reporter.deprecation(message[:deprecation])
|
|
357
|
+
when "profile"
|
|
358
|
+
@reporter.profile(message[:profile])
|
|
331
359
|
when "seed"
|
|
332
360
|
when "close"
|
|
333
361
|
when "error"
|
|
@@ -335,6 +363,7 @@ module TurboTests
|
|
|
335
363
|
nil
|
|
336
364
|
when "exit"
|
|
337
365
|
exited += 1
|
|
366
|
+
@exited_process_ids << message[:process_id]
|
|
338
367
|
break if exited == @num_processes
|
|
339
368
|
else
|
|
340
369
|
warn("Unhandled message in main process: #{message}")
|
|
@@ -357,5 +386,20 @@ module TurboTests
|
|
|
357
386
|
puts "Group that failed: #{failing_group}"
|
|
358
387
|
end
|
|
359
388
|
end
|
|
389
|
+
|
|
390
|
+
def report_unfinished_groups(label)
|
|
391
|
+
groups = Array(@tests_in_groups)
|
|
392
|
+
unfinished_groups = groups.each_with_index.with_object([]) do |(tests, index), unfinished|
|
|
393
|
+
process_id = index + 1
|
|
394
|
+
unfinished << tests unless @exited_process_ids.include?(process_id)
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
return if unfinished_groups.empty?
|
|
398
|
+
|
|
399
|
+
puts "#{label}:"
|
|
400
|
+
unfinished_groups.each_with_index do |tests, index|
|
|
401
|
+
puts " #{index + 1}) #{tests.join(" ")}"
|
|
402
|
+
end
|
|
403
|
+
end
|
|
360
404
|
end
|
|
361
405
|
end
|
data/lib/turbo_tests/shim.rb
CHANGED
|
@@ -2,7 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
module TurboTests
|
|
4
4
|
class Shim
|
|
5
|
-
Result
|
|
5
|
+
class Result
|
|
6
|
+
attr_reader :status, :path, :message, :exit_code
|
|
7
|
+
|
|
8
|
+
def initialize(status:, path:, message:, exit_code:)
|
|
9
|
+
@status = status
|
|
10
|
+
@path = path
|
|
11
|
+
@message = message
|
|
12
|
+
@exit_code = exit_code
|
|
13
|
+
end
|
|
14
|
+
end
|
|
6
15
|
|
|
7
16
|
DEFAULT_RELATIVE_PATH = File.join("bin", "turbo_tests")
|
|
8
17
|
MANAGED_MARKER = "Generated by turbo_tests2 shim install"
|
data/lib/turbo_tests/version.rb
CHANGED
data/lib/turbo_tests.rb
CHANGED
|
@@ -52,6 +52,7 @@ module TurboTests
|
|
|
52
52
|
:pending_fixed?,
|
|
53
53
|
:exception,
|
|
54
54
|
:pending_exception,
|
|
55
|
+
:run_time,
|
|
55
56
|
)
|
|
56
57
|
class FakeExecutionResult
|
|
57
58
|
class << self
|
|
@@ -63,6 +64,7 @@ module TurboTests
|
|
|
63
64
|
obj[:pending_fixed?],
|
|
64
65
|
FakeException.from_obj(obj[:exception]),
|
|
65
66
|
FakeException.from_obj(obj[:exception]),
|
|
67
|
+
obj[:run_time],
|
|
66
68
|
)
|
|
67
69
|
end
|
|
68
70
|
end
|
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "bundler"
|
|
4
3
|
require "rspec/core"
|
|
5
4
|
|
|
6
5
|
RSpec.shared_context("with simplecov spawn coverage") do
|
|
7
6
|
let(:simplecov_spawn_path) do
|
|
8
|
-
File.expand_path("
|
|
7
|
+
[Dir.pwd, File.expand_path("..", Dir.pwd)]
|
|
8
|
+
.map { |dir| File.expand_path(".simplecov_spawn.rb", dir) }
|
|
9
|
+
.find { |path| File.file?(path) }
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
around do |example|
|
|
12
13
|
original_rubyopt = ENV.fetch("RUBYOPT", nil)
|
|
14
|
+
original_cov_min_hard = ENV.fetch("K_SOUP_COV_MIN_HARD", nil)
|
|
13
15
|
begin
|
|
14
16
|
if defined?(SimpleCov) && SimpleCov.running
|
|
15
17
|
spawn_path = simplecov_spawn_path
|
|
16
18
|
raise ArgumentError, "Expected SimpleCov spawn shim at #{spawn_path}" unless File.file?(spawn_path)
|
|
17
19
|
|
|
20
|
+
ENV["K_SOUP_COV_MIN_HARD"] = "false"
|
|
18
21
|
ENV["RUBYOPT"] = ["-r#{spawn_path}", original_rubyopt].compact.join(" ").strip
|
|
19
22
|
end
|
|
20
23
|
|
|
21
24
|
example.run
|
|
22
25
|
ensure
|
|
23
26
|
ENV["RUBYOPT"] = original_rubyopt
|
|
27
|
+
ENV["K_SOUP_COV_MIN_HARD"] = original_cov_min_hard
|
|
24
28
|
end
|
|
25
29
|
end
|
|
26
30
|
end
|
data/sig/turbo_tests/version.rbs
CHANGED
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.
|
|
4
|
+
version: 3.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Illia
|
|
@@ -110,6 +110,9 @@ dependencies:
|
|
|
110
110
|
- - "~>"
|
|
111
111
|
- !ruby/object:Gem::Version
|
|
112
112
|
version: '2.0'
|
|
113
|
+
- - ">="
|
|
114
|
+
- !ruby/object:Gem::Version
|
|
115
|
+
version: 2.0.5
|
|
113
116
|
type: :development
|
|
114
117
|
prerelease: false
|
|
115
118
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -117,6 +120,9 @@ dependencies:
|
|
|
117
120
|
- - "~>"
|
|
118
121
|
- !ruby/object:Gem::Version
|
|
119
122
|
version: '2.0'
|
|
123
|
+
- - ">="
|
|
124
|
+
- !ruby/object:Gem::Version
|
|
125
|
+
version: 2.0.5
|
|
120
126
|
- !ruby/object:Gem::Dependency
|
|
121
127
|
name: bundler-audit
|
|
122
128
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -194,7 +200,7 @@ dependencies:
|
|
|
194
200
|
version: '2.0'
|
|
195
201
|
- - ">="
|
|
196
202
|
- !ruby/object:Gem::Version
|
|
197
|
-
version: 2.0.
|
|
203
|
+
version: 2.0.1
|
|
198
204
|
type: :development
|
|
199
205
|
prerelease: false
|
|
200
206
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -204,7 +210,7 @@ dependencies:
|
|
|
204
210
|
version: '2.0'
|
|
205
211
|
- - ">="
|
|
206
212
|
- !ruby/object:Gem::Version
|
|
207
|
-
version: 2.0.
|
|
213
|
+
version: 2.0.1
|
|
208
214
|
- !ruby/object:Gem::Dependency
|
|
209
215
|
name: ruby-progressbar
|
|
210
216
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -245,20 +251,20 @@ dependencies:
|
|
|
245
251
|
requirements:
|
|
246
252
|
- - "~>"
|
|
247
253
|
- !ruby/object:Gem::Version
|
|
248
|
-
version: '
|
|
254
|
+
version: '2.0'
|
|
249
255
|
- - ">="
|
|
250
256
|
- !ruby/object:Gem::Version
|
|
251
|
-
version:
|
|
257
|
+
version: 2.0.0
|
|
252
258
|
type: :development
|
|
253
259
|
prerelease: false
|
|
254
260
|
version_requirements: !ruby/object:Gem::Requirement
|
|
255
261
|
requirements:
|
|
256
262
|
- - "~>"
|
|
257
263
|
- !ruby/object:Gem::Version
|
|
258
|
-
version: '
|
|
264
|
+
version: '2.0'
|
|
259
265
|
- - ">="
|
|
260
266
|
- !ruby/object:Gem::Version
|
|
261
|
-
version:
|
|
267
|
+
version: 2.0.0
|
|
262
268
|
description: "\U0001F680 `turbo_tests2` is a drop-in replacement for `serpapi/turbo_tests`
|
|
263
269
|
and `grosser/parallel_tests` with incremental summarized output. Source code of
|
|
264
270
|
`turbo_test2` gem is based on Discourse and Rubygems work in this area (see README
|
|
@@ -274,6 +280,7 @@ extra_rdoc_files:
|
|
|
274
280
|
- CODE_OF_CONDUCT.md
|
|
275
281
|
- CONTRIBUTING.md
|
|
276
282
|
- FUNDING.md
|
|
283
|
+
- LICENSE.md
|
|
277
284
|
- README.md
|
|
278
285
|
- RUBOCOP.md
|
|
279
286
|
- SECURITY.md
|
|
@@ -283,6 +290,7 @@ files:
|
|
|
283
290
|
- CODE_OF_CONDUCT.md
|
|
284
291
|
- CONTRIBUTING.md
|
|
285
292
|
- FUNDING.md
|
|
293
|
+
- LICENSE.md
|
|
286
294
|
- README.md
|
|
287
295
|
- RUBOCOP.md
|
|
288
296
|
- SECURITY.md
|
|
@@ -304,10 +312,10 @@ licenses:
|
|
|
304
312
|
- MIT
|
|
305
313
|
metadata:
|
|
306
314
|
homepage_uri: https://turbo-tests2.galtzo.com
|
|
307
|
-
source_code_uri: https://github.com/galtzo-floss/turbo_tests2/tree/v3.
|
|
308
|
-
changelog_uri: https://github.com/galtzo-floss/turbo_tests2/blob/v3.
|
|
315
|
+
source_code_uri: https://github.com/galtzo-floss/turbo_tests2/tree/v3.1.0
|
|
316
|
+
changelog_uri: https://github.com/galtzo-floss/turbo_tests2/blob/v3.1.0/CHANGELOG.md
|
|
309
317
|
bug_tracker_uri: https://github.com/galtzo-floss/turbo_tests2/issues
|
|
310
|
-
documentation_uri: https://www.rubydoc.info/gems/turbo_tests2/3.
|
|
318
|
+
documentation_uri: https://www.rubydoc.info/gems/turbo_tests2/3.1.0
|
|
311
319
|
funding_uri: https://github.com/sponsors/pboling
|
|
312
320
|
wiki_uri: https://github.com/galtzo-floss/turbo_tests2/wiki
|
|
313
321
|
news_uri: https://www.railsbling.com/tags/turbo_tests2
|
|
@@ -337,7 +345,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
337
345
|
- !ruby/object:Gem::Version
|
|
338
346
|
version: '0'
|
|
339
347
|
requirements: []
|
|
340
|
-
rubygems_version: 4.0.
|
|
348
|
+
rubygems_version: 4.0.10
|
|
341
349
|
specification_version: 4
|
|
342
350
|
summary: "\U0001F680 `turbo_tests2` is a drop-in replacement for `serpapi/turbo_tests`
|
|
343
351
|
and `grosser/parallel_tests` with incremental summarized output"
|
metadata.gz.sig
CHANGED
|
Binary file
|