knapsack_pro 6.0.4 → 7.0.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.
Files changed (41) 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 +87 -0
  6. data/Gemfile +9 -0
  7. data/README.md +0 -4
  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 +16 -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 +92 -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 +124 -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 +2232 -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 +2 -24
  30. data/spec/knapsack_pro/config/env_spec.rb +1 -35
  31. data/spec/knapsack_pro/formatters/time_tracker_specs.rb +8 -37
  32. data/spec/knapsack_pro/hooks/queue_spec.rb +2 -2
  33. data/spec/knapsack_pro/presenter_spec.rb +1 -1
  34. data/spec/knapsack_pro/pure/queue/rspec_pure_spec.rb +224 -0
  35. data/spec/knapsack_pro/runners/queue/cucumber_runner_spec.rb +16 -16
  36. data/spec/knapsack_pro/runners/queue/minitest_runner_spec.rb +14 -14
  37. data/spec/knapsack_pro_spec.rb +3 -3
  38. metadata +17 -12
  39. data/lib/knapsack_pro/formatters/rspec_queue_profile_formatter_extension.rb +0 -58
  40. data/lib/knapsack_pro/formatters/rspec_queue_summary_formatter.rb +0 -145
  41. 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: 3f27ac674f611af638b9d0ea3dd1d3441a9e680e70296738ff5b93d5d18f9741
4
+ data.tar.gz: 79bdc380a1c882178b4a3cde626de7e2db1d30ae64ae1a301f023a5ff5d71623
5
5
  SHA512:
6
- metadata.gz: 3ee99fbf40d75acbaf3af791947a87a2e7d547638e99dd04666133e3f4c7addc33f8e91f610fb055b3fd8d47bfadb8e9257dfa0ef65ec16042b0ac7dfb51b727
7
- data.tar.gz: 3adfda6f4cfb3761b497da0d2aeb688fe70efc65334da29b70fb0af3ff0a480dcf83714d11c3b126bcdc1218fa46c1b3f88264090bf204f310dc332512b077b8
6
+ metadata.gz: 75bf722c575fce515b8a1a79f7e05ad5ed8ce6f69c05f4ff7cff8fdd570e5eb3e170cbf83765c66b2d1a187a5c076235637188ef9e7bd9d3d703fa37d1bf989c
7
+ data.tar.gz: 1a355724b69bd0d62b23dd32b6e995dbdd882d0fcb0299d5cddb42c3b4c0635a588839c7194cfb2af83504d91ba4db192a68cc393a8380713450b44971c682bf
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/time_tracker*_spec.rb
40
+ spec_integration/
data/CHANGELOG.md CHANGED
@@ -1,5 +1,92 @@
1
1
  # Changelog
2
2
 
3
+ ### 7.0.0
4
+
5
+ * __(breaking change)__ RSpec in Queue Mode:
6
+ * The default for `KNAPSACK_PRO_LOG_LEVEL` is `info` instead of `debug`.
7
+ * The RSpec `before(:suite)` and `after(:suite)` hooks changed:
8
+
9
+ __Before:__<br>
10
+ The `before(:suite)` and `after(:suite)` hooks were executed multiple times. Each time for a batch of tests fetched from Knapsack Pro Queue API.
11
+
12
+ __After:__<br>
13
+ 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).
14
+
15
+ * The `KnapsackPro::Hooks::Queue.after_queue` hook change:
16
+
17
+ __Before:__<br>
18
+ The `KnapsackPro::Hooks::Queue.after_queue` hook is executed outside of the `after(:suite)` hook.
19
+
20
+ __After:__<br>
21
+ The `KnapsackPro::Hooks::Queue.after_queue` hook is executed __inside__ of the `after(:suite)` hook.
22
+
23
+ * Recommended RSpec changes in your project:
24
+ * Remove the following code if you use Queue Mode and the `rspec_junit_formatter` gem to generate JUnit XML or JSON reports:
25
+
26
+ ```ruby
27
+ # REMOVE THE FOLLOWING CODE
28
+
29
+ # spec_helper.rb or rails_helper.rb
30
+ TMP_REPORT = "tmp/rspec_#{ENV['KNAPSACK_PRO_CI_NODE_INDEX']}.xml"
31
+ FINAL_REPORT = "tmp/final_rspec_#{ENV['KNAPSACK_PRO_CI_NODE_INDEX']}.xml"
32
+
33
+ KnapsackPro::Hooks::Queue.after_subset_queue do |queue_id, subset_queue_id|
34
+ if File.exist?(TMP_REPORT)
35
+ FileUtils.mv(TMP_REPORT, FINAL_REPORT)
36
+ end
37
+ end
38
+ ```
39
+
40
+ 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.
41
+
42
+ * Replace the following code if you are using Queue Mode and the `percy-capybara` gem on a version older than 4:
43
+
44
+ Before:
45
+
46
+ ```ruby
47
+ KnapsackPro::Hooks::Queue.before_queue { |queue_id| Percy::Capybara.initialize_build }
48
+ KnapsackPro::Hooks::Queue.after_queue { |queue_id| Percy::Capybara.finalize_build }
49
+ ```
50
+
51
+ After:
52
+
53
+ ```ruby
54
+ # recommended
55
+ before(:suite) { Percy::Capybara.initialize_build }
56
+ after(:suite) { Percy::Capybara.finalize_build }
57
+ ```
58
+
59
+ Learn more about [using Knapsack Pro with Percy](https://docs.knapsackpro.com/ruby/hooks/#percy-capybara) in the docs.
60
+
61
+ * 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.
62
+
63
+ * RSpec improvements in Queue Mode:
64
+ * 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.
65
+
66
+ * 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).
67
+
68
+ ```bash
69
+ bundle exec rake "knapsack_pro:queue:rspec[--error-exit-code 3]"
70
+ ```
71
+
72
+ * Respect the `--failure-exit-code` option. It sets a custom exit code for when any examples fail.
73
+
74
+ ```bash
75
+ bundle exec rake "knapsack_pro:queue:rspec[--failure-exit-code 2]"
76
+ ```
77
+
78
+ * Respect the `--fail-fast` option and show a warning in the Knapsack Pro log.
79
+
80
+ * Ignore the `fail_if_no_examples` option 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
+ * 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.
85
+
86
+ PR with the above changes: https://github.com/KnapsackPro/knapsack_pro-ruby/pull/237
87
+
88
+ https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v6.0.4...v7.0.0
89
+
3
90
  ### 6.0.4
4
91
 
5
92
  * 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:
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
@@ -87,7 +87,7 @@ module KnapsackPro
87
87
 
88
88
  def bind_time_tracker
89
89
  ensure_no_focus!
90
- log_batch_duration
90
+ log_tests_duration
91
91
  end
92
92
 
93
93
  def ensure_no_focus!
@@ -105,12 +105,14 @@ module KnapsackPro
105
105
  end
106
106
  end
107
107
 
108
- def log_batch_duration
108
+ def log_tests_duration
109
109
  ::RSpec.configure do |config|
110
- config.after(:suite) do
110
+ config.append_after(:suite) do
111
111
  time_tracker = KnapsackPro::Formatters::TimeTrackerFetcher.call
112
- formatted = KnapsackPro::Presenter.global_time(time_tracker.batch_duration)
113
- KnapsackPro.logger.debug(formatted)
112
+ if time_tracker
113
+ formatted = KnapsackPro::Presenter.global_time(time_tracker.duration)
114
+ KnapsackPro.logger.debug(formatted)
115
+ end
114
116
  end
115
117
  end
116
118
  end
@@ -127,10 +129,15 @@ module KnapsackPro
127
129
  def bind_before_queue_hook
128
130
  ::RSpec.configure do |config|
129
131
  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
132
+ KnapsackPro::Hooks::Queue.call_before_queue
133
+ end
134
+ end
135
+ end
136
+
137
+ def bind_after_queue_hook
138
+ ::RSpec.configure do |config|
139
+ config.after(:suite) do
140
+ KnapsackPro::Hooks::Queue.call_after_queue
134
141
  end
135
142
  end
136
143
  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