knapsack_pro 6.0.4 → 7.0.0

Sign up to get free protection for your applications and to get access to all the features.
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