knapsack_pro 6.0.4 → 7.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +80 -19
  3. data/.github/pull_request_template.md +22 -0
  4. data/.gitignore +4 -0
  5. data/CHANGELOG.md +95 -0
  6. data/Gemfile +9 -0
  7. data/README.md +7 -9
  8. data/knapsack_pro.gemspec +2 -1
  9. data/lib/knapsack_pro/adapters/base_adapter.rb +7 -2
  10. data/lib/knapsack_pro/adapters/cucumber_adapter.rb +1 -3
  11. data/lib/knapsack_pro/adapters/rspec_adapter.rb +24 -9
  12. data/lib/knapsack_pro/config/env.rb +1 -9
  13. data/lib/knapsack_pro/extensions/rspec_extension.rb +137 -0
  14. data/lib/knapsack_pro/formatters/time_tracker.rb +10 -26
  15. data/lib/knapsack_pro/formatters/time_tracker_fetcher.rb +6 -0
  16. data/lib/knapsack_pro/presenter.rb +1 -1
  17. data/lib/knapsack_pro/pure/queue/rspec_pure.rb +100 -0
  18. data/lib/knapsack_pro/runners/queue/base_runner.rb +6 -1
  19. data/lib/knapsack_pro/runners/queue/cucumber_runner.rb +6 -6
  20. data/lib/knapsack_pro/runners/queue/minitest_runner.rb +6 -6
  21. data/lib/knapsack_pro/runners/queue/rspec_runner.rb +127 -173
  22. data/lib/knapsack_pro/urls.rb +2 -0
  23. data/lib/knapsack_pro/version.rb +1 -1
  24. data/lib/knapsack_pro.rb +1 -0
  25. data/spec/integration/runners/queue/rspec_runner.rb +80 -0
  26. data/spec/integration/runners/queue/rspec_runner_spec.rb +2405 -0
  27. data/spec/knapsack_pro/adapters/base_adapter_spec.rb +17 -11
  28. data/spec/knapsack_pro/adapters/cucumber_adapter_spec.rb +2 -5
  29. data/spec/knapsack_pro/adapters/rspec_adapter_spec.rb +56 -24
  30. data/spec/knapsack_pro/config/env_spec.rb +1 -35
  31. data/spec/knapsack_pro/formatters/time_tracker_fetcher_spec.rb +30 -0
  32. data/spec/knapsack_pro/formatters/time_tracker_specs.rb +8 -37
  33. data/spec/knapsack_pro/hooks/queue_spec.rb +2 -2
  34. data/spec/knapsack_pro/presenter_spec.rb +1 -1
  35. data/spec/knapsack_pro/pure/queue/rspec_pure_spec.rb +248 -0
  36. data/spec/knapsack_pro/runners/queue/cucumber_runner_spec.rb +16 -16
  37. data/spec/knapsack_pro/runners/queue/minitest_runner_spec.rb +14 -14
  38. data/spec/knapsack_pro_spec.rb +3 -3
  39. metadata +19 -12
  40. data/lib/knapsack_pro/formatters/rspec_queue_profile_formatter_extension.rb +0 -58
  41. data/lib/knapsack_pro/formatters/rspec_queue_summary_formatter.rb +0 -145
  42. data/spec/knapsack_pro/runners/queue/rspec_runner_spec.rb +0 -536
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5e14f8999c37f913f26b9d52a4c5968f25d9c3f7d3a6f91442e140619d5eb986
4
- data.tar.gz: 58350583c0545e48f7deb7b2bf78f951124f87b35f734627400794479c3a53b2
3
+ metadata.gz: cd0d61c51dbf5b1db810f1249e058149831a3e502af11158bcb112ca02f83bf8
4
+ data.tar.gz: 8c281aa9ed386c01f857f60212f469fdb1364ff3ffc3111e60cdcb0a1557dc35
5
5
  SHA512:
6
- metadata.gz: 3ee99fbf40d75acbaf3af791947a87a2e7d547638e99dd04666133e3f4c7addc33f8e91f610fb055b3fd8d47bfadb8e9257dfa0ef65ec16042b0ac7dfb51b727
7
- data.tar.gz: 3adfda6f4cfb3761b497da0d2aeb688fe70efc65334da29b70fb0af3ff0a480dcf83714d11c3b126bcdc1218fa46c1b3f88264090bf204f310dc332512b077b8
6
+ metadata.gz: b3f306e986304db8084259385b375681b4bf7bad16351fbe15bf3c5d624ab31648a42e2efafb8cc3bdd3eef7ce2ea49df91d9fa87b1a812830aaf6d3e489cb89
7
+ data.tar.gz: 867302738082653b366f08265224463186ea19069e147d281020ef1a76c6c480398922913fdf92d3ad1971fe792be69e204b4087e589eeac66b705fabc6a7879
data/.circleci/config.yml CHANGED
@@ -37,7 +37,8 @@ commands:
37
37
  fi
38
38
  - restore_cache:
39
39
  keys:
40
- - v1-bundler-rails-{{ checksum "Gemfile.lock" }}-<< parameters.ruby >>
40
+ - v1-bundler-rails-{{ checksum "Gemfile.lock" }}-ruby-<< parameters.ruby >>-rspec-<< parameters.rspec >>
41
+ - v1-bundler-rails-{{ checksum "Gemfile.lock" }}-ruby-<< parameters.ruby >>-
41
42
  - v1-bundler-rails-{{ checksum "Gemfile.lock" }}-
42
43
  - v1-bundler-rails-
43
44
  - run:
@@ -48,14 +49,15 @@ commands:
48
49
  - save_cache:
49
50
  paths:
50
51
  - << parameters.path >>/vendor/bundle
51
- key: v1-bundler-rails-{{ checksum "Gemfile.lock" }}-<< parameters.ruby >>
52
+ key: v1-bundler-rails-{{ checksum "Gemfile.lock" }}-ruby-<< parameters.ruby >>-rspec-<< parameters.rspec >>
52
53
 
53
54
  jobs:
54
55
  unit:
55
56
  parallelism: 1
56
57
  working_directory: ~/knapsack_pro-ruby
58
+ resource_class: small
57
59
  docker:
58
- - image: cimg/ruby:3.2
60
+ - image: cimg/ruby:3.3
59
61
  steps:
60
62
  - setup_knapsack_pro_ruby
61
63
  - run: gem install rubocop
@@ -63,9 +65,51 @@ jobs:
63
65
  - run: bundle exec rspec spec
64
66
  - run: bundle exec ruby spec/knapsack_pro/formatters/time_tracker_specs.rb
65
67
 
66
- integration-regular-rspec:
68
+ integration-rspec:
69
+ parallelism: 1
70
+ working_directory: ~/knapsack_pro-ruby
71
+ resource_class: small
72
+ parameters:
73
+ ruby:
74
+ type: string
75
+ rspec:
76
+ type: string
77
+ docker:
78
+ - image: cimg/ruby:<< parameters.ruby >>
79
+ steps:
80
+ - checkout
81
+ - run:
82
+ command: |
83
+ if [[ "<< parameters.rspec >>" != "" ]]; then
84
+ sed -i 's/.*gem.*rspec-core.*/gem "rspec-core", "<< parameters.rspec >>"/g' ./Gemfile
85
+ echo "Updated RSpec version in Gemfile"
86
+ fi
87
+ - restore_cache:
88
+ keys:
89
+ - v1-bundler-gem-{{ checksum "knapsack_pro.gemspec" }}-ruby-<< parameters.ruby >>-rspec-<< parameters.rspec >>
90
+ - v1-bundler-gem-{{ checksum "knapsack_pro.gemspec" }}-ruby-<< parameters.ruby >>-
91
+ - v1-bundler-gem-{{ checksum "knapsack_pro.gemspec" }}-
92
+ - v1-bundler-gem-
93
+ - run:
94
+ command: |
95
+ bundle config set --local path './vendor/bundle'
96
+ bundle install --jobs=4 --retry=3
97
+ - save_cache:
98
+ paths:
99
+ - ./vendor/bundle
100
+ key: v1-bundler-gem-{{ checksum "knapsack_pro.gemspec" }}-ruby-<< parameters.ruby >>-rspec-<< parameters.rspec >>
101
+ - run:
102
+ command: |
103
+ ruby --version
104
+ bundle exec rspec --version
105
+ RSPEC=$(bundle exec rspec --version | grep rspec-core | head -n1 | cut -d " " -f5)
106
+ [ $RSPEC != << parameters.rspec >> ] && exit 1 || echo "Correct version of RSpec installed: $RSPEC"
107
+ - run: bundle exec rspec spec/integration/runners/queue/rspec_runner_spec.rb
108
+
109
+ e2e-regular-rspec:
67
110
  parallelism: 2
68
111
  working_directory: ~/knapsack_pro-ruby
112
+ resource_class: small
69
113
  parameters:
70
114
  ruby:
71
115
  type: string
@@ -122,8 +166,16 @@ jobs:
122
166
  export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--$CIRCLE_BUILD_NUM--regular--split"
123
167
  export KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true
124
168
  bundle exec rake knapsack_pro:rspec
169
+ - run:
170
+ working_directory: ~/rails-app-with-knapsack_pro
171
+ command: |
172
+ # split custom files by test examples ||
173
+ export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--$CIRCLE_BUILD_NUM--regular--split-custom-files"
174
+ export KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES=true
175
+ export KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN="spec/features/calculator_spec.rb"
176
+ bundle exec rake knapsack_pro:rspec
125
177
 
126
- integration-queue-rspec:
178
+ e2e-queue-rspec:
127
179
  parameters:
128
180
  ruby:
129
181
  type: string
@@ -131,6 +183,7 @@ jobs:
131
183
  type: string
132
184
  parallelism: 2
133
185
  working_directory: ~/knapsack_pro-ruby
186
+ resource_class: small
134
187
  docker:
135
188
  - image: cimg/ruby:<< parameters.ruby >>-browsers
136
189
  environment:
@@ -216,9 +269,10 @@ jobs:
216
269
  export KNAPSACK_PRO_TEST_FILE_PATTERN="turnip/**/*.feature"
217
270
  bundle exec rake "knapsack_pro:queue:rspec[-r turnip/rspec]"
218
271
 
219
- integration-regular-minitest:
272
+ e2e-regular-minitest:
220
273
  parallelism: 2
221
274
  working_directory: ~/knapsack_pro-ruby
275
+ resource_class: small
222
276
  parameters:
223
277
  ruby:
224
278
  type: string
@@ -255,12 +309,13 @@ jobs:
255
309
  export KNAPSACK_PRO_BRANCH="$CIRCLE_BRANCH--$CIRCLE_BUILD_NUM--regular"
256
310
  bundle exec rake knapsack_pro:minitest[--verbose]
257
311
 
258
- integration-queue-minitest:
312
+ e2e-queue-minitest:
259
313
  parameters:
260
314
  ruby:
261
315
  type: string
262
316
  parallelism: 2
263
317
  working_directory: ~/knapsack_pro-ruby
318
+ resource_class: small
264
319
  docker:
265
320
  - image: cimg/ruby:<< parameters.ruby >>-browsers
266
321
  environment:
@@ -307,25 +362,31 @@ workflows:
307
362
  tests:
308
363
  jobs:
309
364
  - unit
310
- - integration-regular-rspec:
311
- name: integration-regular__ruby-<< matrix.ruby >>__rspec-<< matrix.rspec >>
365
+ - integration-rspec:
366
+ name: integration__ruby-<< matrix.ruby >>__rspec-<< matrix.rspec >>
367
+ matrix:
368
+ parameters:
369
+ ruby: ["3.0", "3.1", "3.2", "3.3"]
370
+ rspec: ["3.10.2", "3.11.0", "3.12.2"]
371
+ - e2e-regular-rspec:
372
+ name: e2e-regular__ruby-<< matrix.ruby >>__rspec-<< matrix.rspec >>
312
373
  matrix:
313
374
  parameters:
314
- ruby: ["3.0", "3.1", "3.2"]
375
+ ruby: ["3.0", "3.1", "3.2", "3.3"]
315
376
  rspec: ["3.10.2", "3.11.0", "3.12.2"]
316
- - integration-queue-rspec:
317
- name: integration-queue__ruby-<< matrix.ruby >>__rspec-<< matrix.rspec >>
377
+ - e2e-queue-rspec:
378
+ name: e2e-queue__ruby-<< matrix.ruby >>__rspec-<< matrix.rspec >>
318
379
  matrix:
319
380
  parameters:
320
- ruby: ["3.0", "3.1", "3.2"]
381
+ ruby: ["3.0", "3.1", "3.2", "3.3"]
321
382
  rspec: ["3.10.2", "3.11.0", "3.12.2"]
322
- - integration-regular-minitest:
323
- name: integration-regular__ruby-<< matrix.ruby >>__minitest
383
+ - e2e-regular-minitest:
384
+ name: e2e-regular__ruby-<< matrix.ruby >>__minitest
324
385
  matrix:
325
386
  parameters:
326
- ruby: ["3.0", "3.1", "3.2"]
327
- - integration-queue-minitest:
328
- name: integration-queue__ruby-<< matrix.ruby >>__minitest
387
+ ruby: ["3.0", "3.1", "3.2", "3.3"]
388
+ - e2e-queue-minitest:
389
+ name: e2e-queue__ruby-<< matrix.ruby >>__minitest
329
390
  matrix:
330
391
  parameters:
331
- ruby: ["3.0", "3.1", "3.2"]
392
+ ruby: ["3.0", "3.1", "3.2", "3.3"]
@@ -0,0 +1,22 @@
1
+ # Story
2
+
3
+ TODO: link to the internal story
4
+
5
+ ## Related
6
+
7
+ TODO: links to related PRs or issues
8
+
9
+ # Description
10
+
11
+ TODO
12
+
13
+ # Changes
14
+
15
+ TODO: changes introduced by this PR
16
+
17
+ # Checklist reminder
18
+
19
+ - [ ] You follow the architecture outlined below for RSpec in Queue Mode, which is a work in progress (feel free to propose changes):
20
+ - Pure: `lib/knapsack_pro/pure/queue/rspec_pure.rb` contains pure functions that are unit tested.
21
+ - Extension: `lib/knapsack_pro/extensions/rspec_extension.rb` encapsulates calls to RSpec internals and is integration and e2e tested.
22
+ - Runner: `lib/knapsack_pro/runners/queue/rspec_runner.rb` invokes the pure code and the extension to produce side effects, which are integration and e2e tested.
data/.gitignore CHANGED
@@ -34,3 +34,7 @@ Gemfile.lock
34
34
 
35
35
  # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
36
36
  .rvmrc
37
+
38
+ # dynamically generated specs
39
+ spec/knapsack_pro/formatters/tmp_time_tracker*_spec.rb
40
+ spec_integration/
data/CHANGELOG.md CHANGED
@@ -1,5 +1,100 @@
1
1
  # Changelog
2
2
 
3
+ ### 7.0.1
4
+
5
+ * fix(RSpec): conditionally adds `--require rails_helper` to cli arguments of `KnapsackPro::Runners::Queue::RSpecRunner`. Version 7.0.0 introduced some fundamental changes, namely fetching, loading and running batches of specs **after** executing suite hooks, so that such hooks are only ran once, not before every batch. As a result, if `rails_helper` is only required in spec files, which is the RSpec default, instead of e.g. in `.rspec`, then some `before(:suite)` hooks, e.g. defined by gems, are registered after suite hooks had already been executed by the test suite. By comparison, RSpec loads all the spec files **before** executing `before(:suite)` hooks.
6
+
7
+ PR with the above changes: https://github.com/KnapsackPro/knapsack_pro-ruby/pull/243
8
+
9
+ https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v7.0.0...v7.0.1
10
+
11
+ ### 7.0.0
12
+
13
+ * __(breaking change)__ RSpec in Queue Mode:
14
+ * The default for `KNAPSACK_PRO_LOG_LEVEL` is `info` instead of `debug`.
15
+ * The RSpec `before(:suite)` and `after(:suite)` hooks changed:
16
+
17
+ __Before:__<br>
18
+ The `before(:suite)` and `after(:suite)` hooks were executed multiple times. Each time for a batch of tests fetched from Knapsack Pro Queue API.
19
+
20
+ __After:__<br>
21
+ The `before(:suite)` and `after(:suite)` hooks are executed only once: `before(:suite)` is executed before starting tests, `after(:suite)` is executed after all tests are completed. (It is what you would expect from RSpec).
22
+
23
+ * The `KnapsackPro::Hooks::Queue.after_queue` hook change:
24
+
25
+ __Before:__<br>
26
+ The `KnapsackPro::Hooks::Queue.after_queue` hook is executed outside of the `after(:suite)` hook.
27
+
28
+ __After:__<br>
29
+ The `KnapsackPro::Hooks::Queue.after_queue` hook is executed __inside__ of the `after(:suite)` hook.
30
+
31
+ * Recommended RSpec changes in your project:
32
+ * Remove the following code if you use Queue Mode and the `rspec_junit_formatter` gem to generate JUnit XML or JSON reports:
33
+
34
+ ```ruby
35
+ # REMOVE THE FOLLOWING CODE
36
+
37
+ # spec_helper.rb or rails_helper.rb
38
+ TMP_REPORT = "tmp/rspec_#{ENV['KNAPSACK_PRO_CI_NODE_INDEX']}.xml"
39
+ FINAL_REPORT = "tmp/final_rspec_#{ENV['KNAPSACK_PRO_CI_NODE_INDEX']}.xml"
40
+
41
+ KnapsackPro::Hooks::Queue.after_subset_queue do |queue_id, subset_queue_id|
42
+ if File.exist?(TMP_REPORT)
43
+ FileUtils.mv(TMP_REPORT, FINAL_REPORT)
44
+ end
45
+ end
46
+ ```
47
+
48
+ Learn more about [using Knapsack Pro with RSpec formatters](https://docs.knapsackpro.com/ruby/rspec/#formatters-rspec_junit_formatter-json) and [using Knapsack Pro with CircleCI](https://docs.knapsackpro.com/ruby/circleci/) in the docs.
49
+
50
+ * Replace the following code if you are using Queue Mode and the `percy-capybara` gem on a version older than 4:
51
+
52
+ Before:
53
+
54
+ ```ruby
55
+ KnapsackPro::Hooks::Queue.before_queue { |queue_id| Percy::Capybara.initialize_build }
56
+ KnapsackPro::Hooks::Queue.after_queue { |queue_id| Percy::Capybara.finalize_build }
57
+ ```
58
+
59
+ After:
60
+
61
+ ```ruby
62
+ # recommended
63
+ before(:suite) { Percy::Capybara.initialize_build }
64
+ after(:suite) { Percy::Capybara.finalize_build }
65
+ ```
66
+
67
+ Learn more about [using Knapsack Pro with Percy](https://docs.knapsackpro.com/ruby/hooks/#percy-capybara) in the docs.
68
+
69
+ * We are no longer modifying the default RSpec formatters in Queue Mode. You can remove the [`KNAPSACK_PRO_MODIFY_DEFAULT_RSPEC_FORMATTERS`](https://docs.knapsackpro.com/ruby/reference/#knapsack_pro_modify_default_rspec_formatters-removed-rspec) environment variable from your CI config if you are using it.
70
+
71
+ * RSpec improvements in Queue Mode:
72
+ * Termination signals (`HUP`, `INT`, `TERM`, `ABRT`, `QUIT`, `USR1`, and `USR2`) are handled earlier: the process will terminate before the next top-level example group (`describe` or `context`) instead of waiting for the next Knapsack Pro batch of tests.
73
+
74
+ * Respect the `--error-exit-code` option. It sets a custom exit code (instead of `1`) when RSpec fails outside an example (e.g. lack of memory, termination signal).
75
+
76
+ ```bash
77
+ bundle exec rake "knapsack_pro:queue:rspec[--error-exit-code 3]"
78
+ ```
79
+
80
+ * Respect the `--failure-exit-code` option. It sets a custom exit code for when any examples fail.
81
+
82
+ ```bash
83
+ bundle exec rake "knapsack_pro:queue:rspec[--failure-exit-code 2]"
84
+ ```
85
+
86
+ * Respect the `--fail-fast` option and show a warning in the Knapsack Pro log.
87
+
88
+ * Ignore the `fail_if_no_examples` option in Queue Mode:
89
+ * A late CI node, started after all tests were executed by other nodes, is expected to receive an empty batch.
90
+ * A batch could contain tests with no examples (e.g. commented out)
91
+
92
+ * Raise an exception if the [deprecated `run_all_when_everything_filtered`](https://docs.knapsackpro.com/ruby/rspec/#some-of-my-test-files-are-not-executed) option is detected.
93
+
94
+ PR with the above changes: https://github.com/KnapsackPro/knapsack_pro-ruby/pull/237
95
+
96
+ https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v6.0.4...v7.0.0
97
+
3
98
  ### 6.0.4
4
99
 
5
100
  * fix(minitest): avoid installing `at_exit` (that would result in an empty run of Minitest after Knapsack Pro is finished in Queue Mode)
data/Gemfile CHANGED
@@ -2,3 +2,12 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in knapsack.gemspec
4
4
  gemspec
5
+
6
+ group :test do
7
+ gem 'rspec_junit_formatter', require: false
8
+ gem 'nokogiri', require: false
9
+ gem 'simplecov', require: false
10
+
11
+ # This line is going to be replaced on CI to test different RSpec versions.
12
+ # gem 'rspec-core', 'x.x.x'
13
+ end
data/README.md CHANGED
@@ -42,10 +42,6 @@ The `knapsack_pro` gem supports all CIs and the following test runners:
42
42
  - Spinach
43
43
  - Turnip
44
44
 
45
- ## Requirements
46
-
47
- `>= Ruby 2.1.0`
48
-
49
45
  ## Installation
50
46
 
51
47
  The [Installation Guide](https://docs.knapsackpro.com/knapsack_pro-ruby/guide/?utm_source=github&utm_medium=readme&utm_campaign=knapsack_pro-ruby_gem&utm_content=installation_guide) will ask you a few questions and generate instruction steps for your project:
@@ -78,30 +74,32 @@ Scripted tests can be found in the [Rails App With Knapsack Pro repository](http
78
74
 
79
75
  ### Publishing
80
76
 
81
- Update the version in `lib/knapsack_pro/version.rb` and `CHANGELOG.md`:
77
+ 1. Update the `CHANGELOG.md` as part of your PR.
78
+
79
+ 2. After your PR has been merged, update the gem version in `lib/knapsack_pro/version.rb` directly on the `master` branch:
82
80
 
83
81
  ```bash
84
82
  git commit -m "Bump version X.X.X"
85
83
  git push origin master
86
84
  ```
87
85
 
88
- Create a git tag for the release:
86
+ 3. Create a git tag for the release:
89
87
 
90
88
  ```bash
91
89
  git tag -a vX.X.X -m "Release vX.X.X"
92
90
  git push --tags
93
91
  ```
94
92
 
95
- Build the gem and publish it to RubyGems:
93
+ 4. Build the gem and publish it to RubyGems:
96
94
 
97
95
  ```bash
98
96
  gem build knapsack_pro.gemspec
99
97
  gem push knapsack_pro-X.X.X.gem
100
98
  ```
101
99
 
102
- Update the latest available gem version in `TestSuiteClientVersionChecker` for the Knapsack Pro API repository.
100
+ 5. Update the latest available gem version in `TestSuiteClientVersionChecker` for the Knapsack Pro API repository.
103
101
 
104
- Update the `knapsack_pro` gem version in:
102
+ 6. Update the `knapsack_pro` gem version in:
105
103
 
106
104
  - [Rails App With Knapsack Pro repository](https://github.com/KnapsackPro/rails-app-with-knapsack_pro)
107
105
  - Knapsack Pro API internal repository
data/knapsack_pro.gemspec CHANGED
@@ -6,10 +6,11 @@ require 'knapsack_pro/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = 'knapsack_pro'
8
8
  spec.version = KnapsackPro::VERSION
9
+ spec.required_ruby_version = '>= 2.7.0'
9
10
  spec.authors = ['ArturT']
10
11
  spec.email = ['support@knapsackpro.com']
11
12
  spec.summary = %q{Knapsack Pro splits tests across parallel CI nodes and ensures each parallel job finish work at a similar time.}
12
- spec.description = %q{Run tests in parallel across CI server nodes based on tests execution time. Split tests in a dynamic way to ensure parallel jobs are done at a similar time. Thanks to that your CI build time is as fast as possible. It works with many CI providers.}
13
+ spec.description = %q{Knapsack Pro wraps your current test runner(s) and works with your existing CI infrastructure to parallelize tests optimally. It dynamically splits your tests based on up-to-date test execution data. It's designed from the ground up for CI and supports all of them.}
13
14
  spec.homepage = 'https://knapsackpro.com'
14
15
  spec.license = 'MIT'
15
16
  spec.metadata = {
@@ -60,13 +60,13 @@ module KnapsackPro
60
60
  File.write(self.class.adapter_bind_method_called_file, nil)
61
61
 
62
62
  if KnapsackPro::Config::Env.recording_enabled?
63
- KnapsackPro.logger.debug('Test suite time execution recording enabled.')
63
+ KnapsackPro.logger.debug('Regular Mode enabled.')
64
64
  bind_time_tracker
65
65
  bind_save_report
66
66
  end
67
67
 
68
68
  if KnapsackPro::Config::Env.queue_recording_enabled?
69
- KnapsackPro.logger.debug('Test suite time execution queue recording enabled.')
69
+ KnapsackPro.logger.debug('Queue Mode enabled.')
70
70
  bind_queue_mode
71
71
  end
72
72
  end
@@ -83,8 +83,13 @@ module KnapsackPro
83
83
  raise NotImplementedError
84
84
  end
85
85
 
86
+ def bind_after_queue_hook
87
+ raise NotImplementedError
88
+ end
89
+
86
90
  def bind_queue_mode
87
91
  bind_before_queue_hook
92
+ bind_after_queue_hook
88
93
  bind_time_tracker
89
94
  end
90
95
  end
@@ -65,9 +65,7 @@ module KnapsackPro
65
65
  end
66
66
  end
67
67
 
68
- def bind_queue_mode
69
- super
70
-
68
+ def bind_after_queue_hook
71
69
  ::Kernel.at_exit do
72
70
  KnapsackPro::Hooks::Queue.call_after_subset_queue
73
71
  KnapsackPro::Report.save_subset_queue_to_file
@@ -52,6 +52,10 @@ module KnapsackPro
52
52
  !!parsed_options(cli_args)&.[](:formatters)
53
53
  end
54
54
 
55
+ def self.has_require_rails_helper_option?(cli_args)
56
+ (parsed_options(cli_args)&.[](:requires) || []).include?("rails_helper")
57
+ end
58
+
55
59
  def self.order_option(cli_args)
56
60
  parsed_options(cli_args)&.[](:order)
57
61
  end
@@ -76,6 +80,10 @@ module KnapsackPro
76
80
  id.match(/\A(.*?)(?:\[([\d\s:,]+)\])?\z/).captures.first
77
81
  end
78
82
 
83
+ def self.rails_helper_exists?(test_dir)
84
+ File.exist?("#{test_dir}/rails_helper.rb")
85
+ end
86
+
79
87
  # private
80
88
  def self.top_level_group(example)
81
89
  group = example.metadata[:example_group]
@@ -87,7 +95,7 @@ module KnapsackPro
87
95
 
88
96
  def bind_time_tracker
89
97
  ensure_no_focus!
90
- log_batch_duration
98
+ log_tests_duration
91
99
  end
92
100
 
93
101
  def ensure_no_focus!
@@ -105,12 +113,14 @@ module KnapsackPro
105
113
  end
106
114
  end
107
115
 
108
- def log_batch_duration
116
+ def log_tests_duration
109
117
  ::RSpec.configure do |config|
110
- config.after(:suite) do
118
+ config.append_after(:suite) do
111
119
  time_tracker = KnapsackPro::Formatters::TimeTrackerFetcher.call
112
- formatted = KnapsackPro::Presenter.global_time(time_tracker.batch_duration)
113
- KnapsackPro.logger.debug(formatted)
120
+ if time_tracker
121
+ formatted = KnapsackPro::Presenter.global_time(time_tracker.duration)
122
+ KnapsackPro.logger.debug(formatted)
123
+ end
114
124
  end
115
125
  end
116
126
  end
@@ -127,10 +137,15 @@ module KnapsackPro
127
137
  def bind_before_queue_hook
128
138
  ::RSpec.configure do |config|
129
139
  config.before(:suite) do
130
- unless ENV['KNAPSACK_PRO_BEFORE_QUEUE_HOOK_CALLED']
131
- ENV['KNAPSACK_PRO_BEFORE_QUEUE_HOOK_CALLED'] = 'true'
132
- KnapsackPro::Hooks::Queue.call_before_queue
133
- end
140
+ KnapsackPro::Hooks::Queue.call_before_queue
141
+ end
142
+ end
143
+ end
144
+
145
+ def bind_after_queue_hook
146
+ ::RSpec.configure do |config|
147
+ config.after(:suite) do
148
+ KnapsackPro::Hooks::Queue.call_after_queue
134
149
  end
135
150
  end
136
151
  end
@@ -144,14 +144,6 @@ module KnapsackPro
144
144
  test_files_encrypted == 'true'
145
145
  end
146
146
 
147
- def modify_default_rspec_formatters
148
- ENV.fetch('KNAPSACK_PRO_MODIFY_DEFAULT_RSPEC_FORMATTERS', true)
149
- end
150
-
151
- def modify_default_rspec_formatters?
152
- modify_default_rspec_formatters.to_s == 'true'
153
- end
154
-
155
147
  def branch_encrypted
156
148
  ENV['KNAPSACK_PRO_BRANCH_ENCRYPTED']
157
149
  end
@@ -276,7 +268,7 @@ module KnapsackPro
276
268
  end
277
269
 
278
270
  def log_level
279
- LOG_LEVELS[ENV['KNAPSACK_PRO_LOG_LEVEL'].to_s.downcase] || ::Logger::DEBUG
271
+ LOG_LEVELS[ENV['KNAPSACK_PRO_LOG_LEVEL'].to_s.downcase] || ::Logger::INFO
280
272
  end
281
273
 
282
274
  def log_dir
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KnapsackPro
4
+ module Extensions
5
+ # Facade to abstract calls to internal RSpec methods.
6
+ # To allow comparing the monkey patch with the original RSpec code, keep a similar method structure and permalink to the source.
7
+ module RSpecExtension
8
+ Seed = Struct.new(:value, :used?)
9
+
10
+ def self.setup!
11
+ RSpec::Core::World.prepend(World)
12
+ RSpec::Core::Runner.prepend(Runner)
13
+ RSpec::Core::Configuration.prepend(Configuration)
14
+ end
15
+
16
+ module World
17
+ # Based on:
18
+ # https://github.com/rspec/rspec-core/blob/f8c8880dabd8f0544a6f91d8d4c857c1bd8df903/lib/rspec/core/world.rb#L171
19
+ #
20
+ # Filters are not announced because we do not load tests during setup. It would print `No examples found.` and we don't want that.
21
+ def knapsack__announce_filters
22
+ fail_if_config_and_cli_options_invalid
23
+ end
24
+ end
25
+
26
+ module Runner
27
+ # Based on:
28
+ # https://github.com/rspec/rspec-core/blob/f8c8880dabd8f0544a6f91d8d4c857c1bd8df903/lib/rspec/core/runner.rb#L98
29
+ #
30
+ # `@configuration.load_spec_files` is not called because we load tests in batches with `knapsack__load_spec_files_batch` later on.
31
+ def knapsack__setup(stream_error = $stderr, stream_out = $stdout)
32
+ configure(stream_error, stream_out)
33
+ ensure
34
+ world.knapsack__announce_filters
35
+ end
36
+
37
+ def knapsack__wants_to_quit?
38
+ world.wants_to_quit
39
+ end
40
+
41
+ def knapsack__rspec_is_quitting?
42
+ world.respond_to?(:rspec_is_quitting) && world.rspec_is_quitting
43
+ end
44
+
45
+ def knapsack__exit_early
46
+ _exit_status = configuration.reporter.exit_early(exit_code)
47
+ end
48
+
49
+ # Based on:
50
+ # https://github.com/rspec/rspec-core/blob/f8c8880dabd8f0544a6f91d8d4c857c1bd8df903/lib/rspec/core/configuration.rb#L546
51
+ def knapsack__error_exit_code
52
+ configuration.error_exit_code # nil unless `--error-exit-code` is specified
53
+ end
54
+
55
+ # must be called after `Runner#knapsack__setup` that loads the `spec_helper.rb` configuration
56
+ def knapsack__deprecated_run_all_when_everything_filtered_enabled?
57
+ configuration.respond_to?(:run_all_when_everything_filtered) && !!configuration.run_all_when_everything_filtered
58
+ end
59
+
60
+ def knapsack__seed
61
+ Seed.new(configuration.seed.to_s, configuration.seed_used?)
62
+ end
63
+
64
+ # @param test_file_paths Array[String]
65
+ # Example: ['a_spec.rb', 'b_spec.rb[1:1]']
66
+ def knapsack__load_spec_files_batch(test_file_paths)
67
+ world.reset
68
+
69
+ # Reset filters, but do not reset `configuration.static_config_filter_manager` to preserve the --tag option
70
+ filter_manager = RSpec::Core::FilterManager.new
71
+ options.configure_filter_manager(filter_manager)
72
+ configuration.filter_manager = filter_manager
73
+
74
+ configuration.knapsack__load_spec_files(test_file_paths)
75
+ end
76
+
77
+ # Based on:
78
+ # https://github.com/rspec/rspec-core/blob/f8c8880dabd8f0544a6f91d8d4c857c1bd8df903/lib/rspec/core/runner.rb#L113
79
+ #
80
+ # Ignore `configuration.fail_if_no_examples` in Queue Mode:
81
+ # * a late CI node, started after all tests were executed by other nodes, is expected to receive an empty batch
82
+ # * a batch could contain tests with no examples (e.g. commented out)
83
+ #
84
+ # @return [Fixnum] exit status code.
85
+ def knapsack__run_specs(queue_runner)
86
+ # Based on:
87
+ # https://github.com/rspec/rspec-core/blob/f8c8880dabd8f0544a6f91d8d4c857c1bd8df903/lib/rspec/core/world.rb#L53
88
+ ordering_strategy = configuration.ordering_registry.fetch(:global)
89
+ node_examples_passed = true
90
+
91
+ configuration.reporter.report(_expected_example_count = 0) do |reporter|
92
+ configuration.with_suite_hooks do
93
+ queue_runner.with_batch do |test_file_paths|
94
+ knapsack__load_spec_files_batch(test_file_paths)
95
+
96
+ examples_passed = ordering_strategy.order(world.example_groups).map do |example_group|
97
+ queue_runner.handle_signal!
98
+ example_group.run(reporter)
99
+ end.all?
100
+
101
+ node_examples_passed = false unless examples_passed
102
+
103
+ knapsack__persist_example_statuses
104
+
105
+ if reporter.fail_fast_limit_met?
106
+ queue_runner.log_fail_fast_limit_met
107
+ break
108
+ end
109
+ end
110
+ end
111
+
112
+ exit_code(node_examples_passed)
113
+ end
114
+ end
115
+
116
+ # Based on:
117
+ # https://github.com/rspec/rspec-core/blob/f8c8880dabd8f0544a6f91d8d4c857c1bd8df903/lib/rspec/core/runner.rb#L90
118
+ def knapsack__persist_example_statuses
119
+ persist_example_statuses
120
+ end
121
+ end
122
+
123
+ module Configuration
124
+ # Based on:
125
+ # https://github.com/rspec/rspec-core/blob/f8c8880dabd8f0544a6f91d8d4c857c1bd8df903/lib/rspec/core/configuration.rb#L1619
126
+ def knapsack__load_spec_files(test_file_paths)
127
+ batch_of_files_to_run = get_files_to_run(test_file_paths)
128
+ batch_of_files_to_run.each do |f|
129
+ file = File.expand_path(f)
130
+ load_file_handling_errors(:load, file)
131
+ loaded_spec_files << file
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end