knapsack_pro 3.8.0 → 7.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +377 -23
  3. data/.github/dependabot.yml +11 -0
  4. data/.github/pull_request_template.md +22 -0
  5. data/.gitignore +4 -0
  6. data/CHANGELOG.md +325 -1
  7. data/Gemfile +9 -0
  8. data/README.md +3 -10
  9. data/bin/test +15 -0
  10. data/knapsack_pro.gemspec +7 -6
  11. data/lib/knapsack_pro/adapters/base_adapter.rb +17 -2
  12. data/lib/knapsack_pro/adapters/cucumber_adapter.rb +3 -3
  13. data/lib/knapsack_pro/adapters/minitest_adapter.rb +2 -0
  14. data/lib/knapsack_pro/adapters/rspec_adapter.rb +88 -49
  15. data/lib/knapsack_pro/adapters/spinach_adapter.rb +2 -0
  16. data/lib/knapsack_pro/adapters/test_unit_adapter.rb +2 -0
  17. data/lib/knapsack_pro/allocator.rb +2 -0
  18. data/lib/knapsack_pro/allocator_builder.rb +2 -0
  19. data/lib/knapsack_pro/base_allocator_builder.rb +8 -25
  20. data/lib/knapsack_pro/build_distribution_fetcher.rb +2 -0
  21. data/lib/knapsack_pro/client/api/action.rb +2 -0
  22. data/lib/knapsack_pro/client/api/v1/base.rb +2 -0
  23. data/lib/knapsack_pro/client/api/v1/build_distributions.rb +5 -0
  24. data/lib/knapsack_pro/client/api/v1/build_subsets.rb +2 -0
  25. data/lib/knapsack_pro/client/api/v1/queues.rb +6 -1
  26. data/lib/knapsack_pro/client/connection.rb +5 -6
  27. data/lib/knapsack_pro/config/ci/app_veyor.rb +18 -0
  28. data/lib/knapsack_pro/config/ci/base.rb +27 -0
  29. data/lib/knapsack_pro/config/ci/buildkite.rb +18 -0
  30. data/lib/knapsack_pro/config/ci/circle.rb +18 -0
  31. data/lib/knapsack_pro/config/ci/cirrus_ci.rb +18 -0
  32. data/lib/knapsack_pro/config/ci/codefresh.rb +18 -0
  33. data/lib/knapsack_pro/config/ci/codeship.rb +18 -0
  34. data/lib/knapsack_pro/config/ci/github_actions.rb +26 -0
  35. data/lib/knapsack_pro/config/ci/gitlab_ci.rb +20 -1
  36. data/lib/knapsack_pro/config/ci/heroku.rb +18 -0
  37. data/lib/knapsack_pro/config/ci/semaphore.rb +16 -0
  38. data/lib/knapsack_pro/config/ci/semaphore2.rb +19 -0
  39. data/lib/knapsack_pro/config/ci/travis.rb +18 -0
  40. data/lib/knapsack_pro/config/env.rb +46 -22
  41. data/lib/knapsack_pro/config/env_generator.rb +2 -0
  42. data/lib/knapsack_pro/config/temp_files.rb +8 -4
  43. data/lib/knapsack_pro/crypto/branch_encryptor.rb +2 -0
  44. data/lib/knapsack_pro/crypto/decryptor.rb +2 -0
  45. data/lib/knapsack_pro/crypto/digestor.rb +2 -0
  46. data/lib/knapsack_pro/crypto/encryptor.rb +2 -0
  47. data/lib/knapsack_pro/extensions/rspec_extension.rb +137 -0
  48. data/lib/knapsack_pro/formatters/rspec_json_formatter.rb +2 -0
  49. data/lib/knapsack_pro/formatters/time_tracker.rb +152 -0
  50. data/lib/knapsack_pro/formatters/time_tracker_fetcher.rb +20 -0
  51. data/lib/knapsack_pro/hooks/queue.rb +2 -0
  52. data/lib/knapsack_pro/logger_wrapper.rb +2 -0
  53. data/lib/knapsack_pro/mask_string.rb +9 -0
  54. data/lib/knapsack_pro/presenter.rb +6 -3
  55. data/lib/knapsack_pro/pure/queue/rspec_pure.rb +92 -0
  56. data/lib/knapsack_pro/queue_allocator.rb +2 -0
  57. data/lib/knapsack_pro/queue_allocator_builder.rb +2 -0
  58. data/lib/knapsack_pro/railtie.rb +2 -0
  59. data/lib/knapsack_pro/report.rb +15 -9
  60. data/lib/knapsack_pro/repository_adapter_initiator.rb +2 -0
  61. data/lib/knapsack_pro/repository_adapters/base_adapter.rb +2 -0
  62. data/lib/knapsack_pro/repository_adapters/env_adapter.rb +2 -0
  63. data/lib/knapsack_pro/repository_adapters/git_adapter.rb +50 -0
  64. data/lib/knapsack_pro/runners/base_runner.rb +2 -0
  65. data/lib/knapsack_pro/runners/cucumber_runner.rb +2 -0
  66. data/lib/knapsack_pro/runners/minitest_runner.rb +2 -0
  67. data/lib/knapsack_pro/runners/queue/base_runner.rb +29 -0
  68. data/lib/knapsack_pro/runners/queue/cucumber_runner.rb +9 -6
  69. data/lib/knapsack_pro/runners/queue/minitest_runner.rb +13 -6
  70. data/lib/knapsack_pro/runners/queue/rspec_runner.rb +128 -135
  71. data/lib/knapsack_pro/runners/rspec_runner.rb +22 -3
  72. data/lib/knapsack_pro/runners/spinach_runner.rb +2 -0
  73. data/lib/knapsack_pro/runners/test_unit_runner.rb +2 -0
  74. data/lib/knapsack_pro/slow_test_file_determiner.rb +2 -0
  75. data/lib/knapsack_pro/slow_test_file_finder.rb +2 -0
  76. data/lib/knapsack_pro/task_loader.rb +2 -0
  77. data/lib/knapsack_pro/test_case_detectors/rspec_test_example_detector.rb +2 -0
  78. data/lib/knapsack_pro/test_case_mergers/base_merger.rb +2 -0
  79. data/lib/knapsack_pro/test_case_mergers/rspec_merger.rb +2 -0
  80. data/lib/knapsack_pro/test_file_cleaner.rb +2 -0
  81. data/lib/knapsack_pro/test_file_finder.rb +2 -0
  82. data/lib/knapsack_pro/test_file_pattern.rb +2 -0
  83. data/lib/knapsack_pro/test_file_presenter.rb +2 -0
  84. data/lib/knapsack_pro/test_files_with_test_cases_composer.rb +2 -0
  85. data/lib/knapsack_pro/test_flat_distributor.rb +2 -0
  86. data/lib/knapsack_pro/tracker.rb +3 -3
  87. data/lib/knapsack_pro/urls.rb +4 -0
  88. data/lib/knapsack_pro/utils.rb +2 -0
  89. data/lib/knapsack_pro/version.rb +3 -1
  90. data/lib/knapsack_pro.rb +5 -3
  91. data/lib/tasks/cucumber.rake +2 -0
  92. data/lib/tasks/encrypted_branch_names.rake +2 -0
  93. data/lib/tasks/encrypted_test_file_names.rake +2 -0
  94. data/lib/tasks/minitest.rake +2 -0
  95. data/lib/tasks/queue/cucumber.rake +13 -0
  96. data/lib/tasks/queue/minitest.rake +13 -0
  97. data/lib/tasks/queue/rspec.rake +13 -0
  98. data/lib/tasks/rspec.rake +5 -0
  99. data/lib/tasks/salt.rake +2 -0
  100. data/lib/tasks/spinach.rake +2 -0
  101. data/lib/tasks/test_unit.rake +2 -0
  102. data/spec/integration/api/build_distributions_subset_spec.rb +1 -0
  103. data/spec/integration/runners/queue/rspec_runner.rb +80 -0
  104. data/spec/integration/runners/queue/rspec_runner_spec.rb +2232 -0
  105. data/spec/knapsack_pro/adapters/base_adapter_spec.rb +30 -11
  106. data/spec/knapsack_pro/adapters/cucumber_adapter_spec.rb +2 -5
  107. data/spec/knapsack_pro/adapters/rspec_adapter_spec.rb +146 -174
  108. data/spec/knapsack_pro/base_allocator_builder_spec.rb +22 -48
  109. data/spec/knapsack_pro/client/api/v1/build_distributions_spec.rb +19 -27
  110. data/spec/knapsack_pro/client/api/v1/queues_spec.rb +23 -43
  111. data/spec/knapsack_pro/client/connection_spec.rb +59 -7
  112. data/spec/knapsack_pro/config/ci/app_veyor_spec.rb +22 -8
  113. data/spec/knapsack_pro/config/ci/base_spec.rb +1 -0
  114. data/spec/knapsack_pro/config/ci/buildkite_spec.rb +51 -16
  115. data/spec/knapsack_pro/config/ci/circle_spec.rb +48 -13
  116. data/spec/knapsack_pro/config/ci/cirrus_ci_spec.rb +12 -12
  117. data/spec/knapsack_pro/config/ci/codefresh_spec.rb +21 -6
  118. data/spec/knapsack_pro/config/ci/codeship_spec.rb +20 -6
  119. data/spec/knapsack_pro/config/ci/github_actions_spec.rb +37 -10
  120. data/spec/knapsack_pro/config/ci/gitlab_ci_spec.rb +48 -13
  121. data/spec/knapsack_pro/config/ci/heroku_spec.rb +12 -12
  122. data/spec/knapsack_pro/config/ci/semaphore2_spec.rb +11 -11
  123. data/spec/knapsack_pro/config/ci/semaphore_spec.rb +12 -12
  124. data/spec/knapsack_pro/config/ci/travis_spec.rb +8 -8
  125. data/spec/knapsack_pro/config/env_spec.rb +204 -124
  126. data/spec/knapsack_pro/formatters/time_tracker_specs.rb +424 -0
  127. data/spec/knapsack_pro/hooks/queue_spec.rb +2 -2
  128. data/spec/knapsack_pro/presenter_spec.rb +1 -1
  129. data/spec/knapsack_pro/pure/queue/rspec_pure_spec.rb +224 -0
  130. data/spec/knapsack_pro/repository_adapters/git_adapter_spec.rb +72 -0
  131. data/spec/knapsack_pro/runners/queue/cucumber_runner_spec.rb +18 -16
  132. data/spec/knapsack_pro/runners/queue/minitest_runner_spec.rb +17 -14
  133. data/spec/knapsack_pro/runners/rspec_runner_spec.rb +40 -23
  134. data/spec/knapsack_pro/test_case_detectors/rspec_test_example_detector_spec.rb +1 -0
  135. data/spec/knapsack_pro/tracker_spec.rb +0 -4
  136. data/spec/knapsack_pro_spec.rb +3 -3
  137. data/spec/spec_helper.rb +0 -1
  138. metadata +26 -23
  139. data/lib/knapsack_pro/config/ci/snap_ci.rb +0 -35
  140. data/lib/knapsack_pro/config/ci/solano_ci.rb +0 -32
  141. data/lib/knapsack_pro/extensions/time.rb +0 -7
  142. data/lib/knapsack_pro/formatters/rspec_queue_profile_formatter_extension.rb +0 -56
  143. data/lib/knapsack_pro/formatters/rspec_queue_summary_formatter.rb +0 -112
  144. data/spec/knapsack_pro/config/ci/snap_ci_spec.rb +0 -104
  145. data/spec/knapsack_pro/config/ci/solano_ci_spec.rb +0 -73
  146. data/spec/knapsack_pro/extensions/time_spec.rb +0 -5
  147. data/spec/knapsack_pro/runners/queue/rspec_runner_spec.rb +0 -342
@@ -1,184 +1,177 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KnapsackPro
2
4
  module Runners
3
5
  module Queue
4
6
  class RSpecRunner < BaseRunner
5
- @@used_seed = nil
6
-
7
- def self.run(args)
7
+ def self.run(args, stream_error = $stderr, stream_out = $stdout)
8
8
  require 'rspec/core'
9
- require_relative '../../formatters/rspec_queue_summary_formatter'
10
- require_relative '../../formatters/rspec_queue_profile_formatter_extension'
9
+ require_relative '../../extensions/rspec_extension'
10
+ require_relative '../../formatters/time_tracker'
11
+ require_relative '../../formatters/time_tracker_fetcher'
12
+
13
+ KnapsackPro::Extensions::RSpecExtension.setup!
11
14
 
12
15
  ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN'] = KnapsackPro::Config::Env.test_suite_token_rspec
13
- ENV['KNAPSACK_PRO_QUEUE_RECORDING_ENABLED'] = 'true'
14
- ENV['KNAPSACK_PRO_QUEUE_ID'] = KnapsackPro::Config::EnvGenerator.set_queue_id
15
16
 
16
- KnapsackPro::Config::Env.set_test_runner_adapter(adapter_class)
17
- runner = new(adapter_class)
18
-
19
- cli_args = (args || '').split
20
- adapter_class.ensure_no_tag_option_when_rspec_split_by_test_examples_enabled!(cli_args)
21
-
22
- # when format option is not defined by user then use progress formatter to show tests execution progress
23
- cli_args += ['--format', 'progress'] unless adapter_class.has_format_option?(cli_args)
24
-
25
- cli_args += [
26
- # shows summary of all tests executed in Queue Mode at the very end
27
- '--format', KnapsackPro::Formatters::RSpecQueueSummaryFormatter.to_s,
28
- '--default-path', runner.test_dir,
29
- ]
30
-
31
- accumulator = {
32
- status: :next,
33
- runner: runner,
34
- can_initialize_queue: true,
35
- args: cli_args,
36
- exitstatus: 0,
37
- all_test_file_paths: [],
38
- }
39
- while accumulator[:status] == :next
40
- accumulator = run_tests(accumulator)
41
- end
17
+ rspec_pure = KnapsackPro::Pure::Queue::RSpecPure.new
42
18
 
43
- Kernel.exit(accumulator[:exitstatus])
19
+ queue_runner = new(KnapsackPro::Adapters::RSpecAdapter, rspec_pure, args, stream_error, stream_out)
20
+ queue_runner.run
44
21
  end
45
22
 
46
- def self.run_tests(accumulator)
47
- runner = accumulator.fetch(:runner)
48
- can_initialize_queue = accumulator.fetch(:can_initialize_queue)
49
- args = accumulator.fetch(:args)
50
- exitstatus = accumulator.fetch(:exitstatus)
51
- all_test_file_paths = accumulator.fetch(:all_test_file_paths)
23
+ def initialize(adapter_class, rspec_pure, args, stream_error, stream_out)
24
+ super(adapter_class)
25
+ @adapter_class = adapter_class
26
+ @rspec_pure = rspec_pure
27
+ has_format_option = @adapter_class.has_format_option?((args || '').split)
28
+ @cli_args = rspec_pure.prepare_cli_args(args, has_format_option, test_dir)
29
+ @stream_error = stream_error
30
+ @stream_out = stream_out
31
+ @node_test_file_paths = []
32
+ @rspec_runner = nil # RSpec::Core::Runner is lazy initialized
33
+ end
52
34
 
53
- test_file_paths = runner.test_file_paths(
54
- can_initialize_queue: can_initialize_queue,
55
- executed_test_files: all_test_file_paths
56
- )
35
+ # Based on:
36
+ # https://github.com/rspec/rspec-core/blob/f8c8880dabd8f0544a6f91d8d4c857c1bd8df903/lib/rspec/core/runner.rb#L85
37
+ #
38
+ # @return [Fixnum] exit status code.
39
+ # 0 if all specs passed,
40
+ # or the configured failure exit code (1 by default) if specs failed.
41
+ def run
42
+ pre_run_setup
43
+
44
+ if @rspec_runner.knapsack__wants_to_quit?
45
+ exit_code = @rspec_runner.knapsack__exit_early
46
+ Kernel.exit(exit_code)
47
+ end
48
+
49
+ begin
50
+ exit_code = @rspec_runner.knapsack__run_specs(self)
51
+ rescue KnapsackPro::Runners::Queue::BaseRunner::TerminationError
52
+ exit_code = @rspec_pure.error_exit_code(@rspec_runner.knapsack__error_exit_code)
53
+ Kernel.exit(exit_code)
54
+ rescue Exception => exception
55
+ KnapsackPro.logger.error("An unexpected exception happened. RSpec cannot handle it. The exception: #{exception.inspect}")
57
56
 
58
- if test_file_paths.empty?
59
- unless all_test_file_paths.empty?
60
- KnapsackPro::Adapters::RSpecAdapter.verify_bind_method_called
57
+ message = @rspec_pure.exit_summary(unexecuted_test_files)
58
+ KnapsackPro.logger.warn(message) if message
61
59
 
62
- KnapsackPro::Formatters::RSpecQueueSummaryFormatter.print_summary
63
- KnapsackPro::Formatters::RSpecQueueProfileFormatterExtension.print_summary
60
+ exit_code = @rspec_pure.error_exit_code(@rspec_runner.knapsack__error_exit_code)
61
+ Kernel.exit(exit_code)
62
+ end
64
63
 
65
- args += ['--seed', @@used_seed] if @@used_seed
64
+ post_run_tasks(exit_code)
65
+ end
66
66
 
67
- log_rspec_command(args, all_test_file_paths, :end_of_queue)
68
- end
67
+ def with_batch
68
+ can_initialize_queue = true
69
69
 
70
- KnapsackPro::Hooks::Queue.call_after_queue
70
+ loop do
71
+ handle_signal!
72
+ test_file_paths = pull_tests_from_queue(can_initialize_queue: can_initialize_queue)
73
+ can_initialize_queue = false
71
74
 
72
- KnapsackPro::Report.save_node_queue_to_api
75
+ break if test_file_paths.empty?
73
76
 
74
- return {
75
- status: :completed,
76
- exitstatus: exitstatus,
77
- }
78
- else
79
77
  subset_queue_id = KnapsackPro::Config::EnvGenerator.set_subset_queue_id
80
78
  ENV['KNAPSACK_PRO_SUBSET_QUEUE_ID'] = subset_queue_id
81
79
 
82
- KnapsackPro.tracker.reset!
83
- KnapsackPro.tracker.set_prerun_tests(test_file_paths)
84
-
85
80
  KnapsackPro::Hooks::Queue.call_before_subset_queue
86
81
 
87
- all_test_file_paths += test_file_paths
88
- cli_args = args + test_file_paths
89
-
90
- options = ::RSpec::Core::ConfigurationOptions.new(cli_args)
91
- rspec_runner = ::RSpec::Core::Runner.new(options)
92
-
93
- exit_code = rspec_runner.run($stderr, $stdout)
94
- exitstatus = exit_code if exit_code != 0
95
-
96
- printable_args = args_with_seed_option_added_when_viable(args, rspec_runner)
97
- log_rspec_command(printable_args, test_file_paths, :subset_queue)
98
-
99
- rspec_clear_examples
82
+ yield test_file_paths
100
83
 
101
84
  KnapsackPro::Hooks::Queue.call_after_subset_queue
102
85
 
103
- KnapsackPro::Report.save_subset_queue_to_file
86
+ if @rspec_runner.knapsack__wants_to_quit?
87
+ KnapsackPro.logger.warn('RSpec wants to quit.')
88
+ set_terminate_process
89
+ end
90
+ if @rspec_runner.knapsack__rspec_is_quitting?
91
+ KnapsackPro.logger.warn('RSpec is quitting.')
92
+ set_terminate_process
93
+ end
104
94
 
105
- return {
106
- status: :next,
107
- runner: runner,
108
- can_initialize_queue: false,
109
- args: args,
110
- exitstatus: exitstatus,
111
- all_test_file_paths: all_test_file_paths,
112
- }
95
+ log_rspec_batch_command(test_file_paths)
113
96
  end
114
97
  end
115
98
 
99
+ def handle_signal!
100
+ self.class.handle_signal!
101
+ end
102
+
103
+ def log_fail_fast_limit_met
104
+ KnapsackPro.logger.warn('Test execution has been canceled because the RSpec --fail-fast option is enabled. It will cause other CI nodes to run tests longer because they need to consume more tests from the Knapsack Pro Queue API.')
105
+ end
106
+
116
107
  private
117
108
 
118
- def self.adapter_class
119
- KnapsackPro::Adapters::RSpecAdapter
109
+ def pre_run_setup
110
+ ENV['KNAPSACK_PRO_QUEUE_RECORDING_ENABLED'] = 'true'
111
+ ENV['KNAPSACK_PRO_QUEUE_ID'] = KnapsackPro::Config::EnvGenerator.set_queue_id
112
+
113
+ KnapsackPro::Config::Env.set_test_runner_adapter(@adapter_class)
114
+
115
+ ENV['SPEC_OPTS'] = @rspec_pure.add_knapsack_pro_formatters_to(ENV['SPEC_OPTS'])
116
+ @adapter_class.ensure_no_tag_option_when_rspec_split_by_test_examples_enabled!(@cli_args)
117
+
118
+ rspec_configuration_options = ::RSpec::Core::ConfigurationOptions.new(@cli_args)
119
+ @rspec_runner = ::RSpec::Core::Runner.new(rspec_configuration_options)
120
+ @rspec_runner.knapsack__setup(@stream_error, @stream_out)
121
+
122
+ ensure_no_deprecated_run_all_when_everything_filtered_option!
120
123
  end
121
124
 
122
- def self.log_rspec_command(cli_args, test_file_paths, type)
123
- case type
124
- when :subset_queue
125
- KnapsackPro.logger.info("To retry the last batch of tests fetched from the API Queue, please run the following command on your machine:")
126
- when :end_of_queue
127
- KnapsackPro.logger.info("To retry all the tests assigned to this CI node, please run the following command on your machine:")
128
- end
125
+ def post_run_tasks(exit_code)
126
+ @adapter_class.verify_bind_method_called
129
127
 
130
- stringified_cli_args = cli_args.join(' ').sub(" --format #{KnapsackPro::Formatters::RSpecQueueSummaryFormatter}", '')
128
+ log_rspec_queue_command
131
129
 
132
- KnapsackPro.logger.info(
133
- "bundle exec rspec #{stringified_cli_args} " +
134
- KnapsackPro::TestFilePresenter.stringify_paths(test_file_paths)
135
- )
130
+ time_tracker = KnapsackPro::Formatters::TimeTrackerFetcher.call
131
+ KnapsackPro::Report.save_node_queue_to_api(time_tracker&.queue(@node_test_file_paths))
132
+
133
+ Kernel.exit(exit_code)
136
134
  end
137
135
 
138
- # Clear rspec examples without the shared examples:
139
- # https://github.com/rspec/rspec-core/pull/2379
140
- #
141
- # Keep formatters and report to accumulate info about failed/pending tests
142
- def self.rspec_clear_examples
143
- if ::RSpec::ExampleGroups.respond_to?(:remove_all_constants)
144
- ::RSpec::ExampleGroups.remove_all_constants
145
- else
146
- ::RSpec::ExampleGroups.constants.each do |constant|
147
- ::RSpec::ExampleGroups.__send__(:remove_const, constant)
148
- end
149
- end
150
- ::RSpec.world.example_groups.clear
151
- ::RSpec.configuration.start_time = ::RSpec::Core::Time.now
152
-
153
- if KnapsackPro::Config::Env.rspec_split_by_test_examples?
154
- # Reset example group counts to ensure scoped example ids in metadata
155
- # have correct index (not increased by each subsequent run).
156
- # Solves this problem: https://github.com/rspec/rspec-core/issues/2721
157
- ::RSpec.world.instance_variable_set(:@example_group_counts_by_spec_file, Hash.new(0))
158
- end
136
+ def ensure_no_deprecated_run_all_when_everything_filtered_option!
137
+ return unless @rspec_runner.knapsack__deprecated_run_all_when_everything_filtered_enabled?
159
138
 
160
- # skip reset filters for old RSpec versions
161
- if ::RSpec.configuration.respond_to?(:reset_filters)
162
- ::RSpec.configuration.reset_filters
163
- end
139
+ error_message = "The run_all_when_everything_filtered option is deprecated. See: #{KnapsackPro::Urls::RSPEC__DEPRECATED_RUN_ALL_WHEN_EVERYTHING_FILTERED}"
140
+ KnapsackPro.logger.error(error_message)
141
+ raise error_message
164
142
  end
165
143
 
166
- def self.args_with_seed_option_added_when_viable(args, rspec_runner)
167
- order_option = adapter_class.order_option(args)
144
+ def pull_tests_from_queue(can_initialize_queue: false)
145
+ test_file_paths = test_file_paths(
146
+ can_initialize_queue: can_initialize_queue,
147
+ executed_test_files: @node_test_file_paths
148
+ )
149
+ @node_test_file_paths += test_file_paths
150
+ test_file_paths
151
+ end
168
152
 
169
- if order_option
170
- # Don't add the seed option for order other than random, e.g. `defined`
171
- return args unless order_option.include?('rand')
172
- # Don't add the seed option if the seed is already set in args, e.g. `rand:12345`
173
- return args if order_option.to_s.split(':')[1]
174
- end
153
+ def log_rspec_batch_command(test_file_paths)
154
+ order_option = @adapter_class.order_option(@cli_args)
155
+ printable_args = @rspec_pure.args_with_seed_option_added_when_viable(order_option, @rspec_runner.knapsack__seed, @cli_args)
156
+ messages = @rspec_pure.rspec_command(printable_args, test_file_paths, :batch_finished)
157
+ log_info_messages(messages)
158
+ end
175
159
 
176
- # Don't add the seed option if the seed was not used (i.e. a different order is being used, e.g. `defined`)
177
- return args unless rspec_runner.configuration.seed_used?
160
+ def log_rspec_queue_command
161
+ order_option = @adapter_class.order_option(@cli_args)
162
+ printable_args = @rspec_pure.args_with_seed_option_added_when_viable(order_option, @rspec_runner.knapsack__seed, @cli_args)
163
+ messages = @rspec_pure.rspec_command(printable_args, @node_test_file_paths, :queue_finished)
164
+ log_info_messages(messages)
165
+ end
178
166
 
179
- @@used_seed = rspec_runner.configuration.seed.to_s
167
+ def log_info_messages(messages)
168
+ messages.each do |message|
169
+ KnapsackPro.logger.info(message)
170
+ end
171
+ end
180
172
 
181
- args + ['--seed', @@used_seed]
173
+ def unexecuted_test_files
174
+ KnapsackPro::Formatters::TimeTrackerFetcher.unexecuted_test_files(@node_test_file_paths)
182
175
  end
183
176
  end
184
177
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KnapsackPro
2
4
  module Runners
3
5
  class RSpecRunner < BaseRunner
@@ -17,8 +19,6 @@ module KnapsackPro
17
19
  cli_args = (args || '').split
18
20
  adapter_class.ensure_no_tag_option_when_rspec_split_by_test_examples_enabled!(cli_args)
19
21
 
20
- KnapsackPro.tracker.set_prerun_tests(runner.test_file_paths)
21
-
22
22
  require 'rspec/core/rake_task'
23
23
 
24
24
  task_name = 'knapsack_pro:rspec_run'
@@ -31,11 +31,30 @@ module KnapsackPro
31
31
  # because pattern does not accept test example path like spec/a_spec.rb[1:2]
32
32
  # instead we pass test files and test example paths to t.rspec_opts
33
33
  t.pattern = []
34
- t.rspec_opts = "#{args} --default-path #{runner.test_dir} #{runner.stringify_test_file_paths}"
34
+ t.rspec_opts = "#{args} #{self.formatters} --default-path #{runner.test_dir} #{runner.stringify_test_file_paths}"
35
+ t.verbose = KnapsackPro::Config::Env.log_level < ::Logger::WARN
35
36
  end
36
37
  Rake::Task[task_name].invoke
37
38
  end
38
39
  end
40
+
41
+ # Use RSpec::Core::ConfigurationOptions to respect external configurations like .rspec
42
+ def self.formatters
43
+ require_relative '../formatters/time_tracker'
44
+
45
+ formatters = ::RSpec::Core::ConfigurationOptions
46
+ .new([])
47
+ .options
48
+ .fetch(:formatters, [])
49
+ .map do |formatter, output|
50
+ arg = "--format #{formatter}"
51
+ arg += " --out #{output}" if output
52
+ arg
53
+ end
54
+ formatters = ['--format progress'] if formatters.empty?
55
+ formatters += ["--format #{KnapsackPro::Formatters::TimeTracker}"]
56
+ formatters.join(' ')
57
+ end
39
58
  end
40
59
  end
41
60
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KnapsackPro
2
4
  module Runners
3
5
  class SpinachRunner < BaseRunner
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KnapsackPro
2
4
  module Runners
3
5
  class TestUnitRunner < BaseRunner
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KnapsackPro
2
4
  class SlowTestFileDeterminer
3
5
  TIME_THRESHOLD_PER_CI_NODE = 0.7 # 70%
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KnapsackPro
2
4
  class SlowTestFileFinder
3
5
  # Get recorded test files from API.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rake'
2
4
 
3
5
  module KnapsackPro
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KnapsackPro
2
4
  module TestCaseDetectors
3
5
  class RSpecTestExampleDetector
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KnapsackPro
2
4
  module TestCaseMergers
3
5
  class BaseMerger
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KnapsackPro
2
4
  module TestCaseMergers
3
5
  class RSpecMerger < BaseMerger
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KnapsackPro
2
4
  class TestFileCleaner
3
5
  def self.clean(test_file_path)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KnapsackPro
2
4
  class TestFileFinder
3
5
  def self.call(test_file_pattern, test_file_list_enabled: true)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KnapsackPro
2
4
  class TestFilePattern
3
5
  def self.call(adapter_class)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KnapsackPro
2
4
  class TestFilePresenter
3
5
  def self.stringify_paths(test_file_paths)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KnapsackPro
2
4
  class TestFilesWithTestCasesComposer
3
5
  # Args:
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KnapsackPro
2
4
  class TestFlatDistributor
3
5
  DIR_TYPES = [
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KnapsackPro
2
4
  class Tracker
3
5
  include Singleton
@@ -6,11 +8,10 @@ module KnapsackPro
6
8
  # to better allocate it in Queue Mode for future CI build runs
7
9
  DEFAULT_TEST_FILE_TIME = 0.0 # seconds
8
10
 
9
- attr_reader :global_time_since_beginning, :global_time, :test_files_with_time, :prerun_tests_loaded
11
+ attr_reader :global_time, :test_files_with_time, :prerun_tests_loaded
10
12
  attr_writer :current_test_path
11
13
 
12
14
  def initialize
13
- @global_time_since_beginning = 0
14
15
  KnapsackPro::Config::TempFiles.ensure_temp_directory_exists!
15
16
  FileUtils.mkdir_p(tracker_dir_path)
16
17
  set_defaults
@@ -133,7 +134,6 @@ module KnapsackPro
133
134
 
134
135
  def update_global_time(execution_time)
135
136
  @global_time += execution_time
136
- @global_time_since_beginning += execution_time
137
137
  end
138
138
 
139
139
  def update_test_file_time(execution_time)
@@ -18,6 +18,8 @@ module KnapsackPro
18
18
 
19
19
  INSTALLATION_GUIDE = "#{HOST}/perma/ruby/installation-guide"
20
20
 
21
+ KNAPSACK_PRO_CI_NODE_BUILD_ID= "#{HOST}/perma/ruby/knapsack-pro-ci-node-build-id"
22
+
21
23
  QUEUE_MODE__CONNECTION_ERROR_WITH_FALLBACK_ENABLED_FALSE = "#{HOST}/perma/ruby/queue-mode-connection-error-with-fallback-enabled-false"
22
24
 
23
25
  QUEUE_MODE__CONNECTION_ERROR_WITH_FALLBACK_ENABLED_TRUE_AND_POSITIVE_RETRY_COUNT = "#{HOST}/perma/ruby/queue-mode-connection-error-with-fallback-enabled-true-and-positive-retry-count"
@@ -26,6 +28,8 @@ module KnapsackPro
26
28
 
27
29
  REGULAR_MODE__CONNECTION_ERROR_WITH_FALLBACK_ENABLED_TRUE_AND_POSITIVE_RETRY_COUNT = "#{HOST}/perma/ruby/regular-mode-connection-error-with-fallback-enabled-true-and-positive-retry-count"
28
30
 
31
+ RSPEC__DEPRECATED_RUN_ALL_WHEN_EVERYTHING_FILTERED = "#{HOST}/perma/ruby/rspec-deprecated-run-all-when-everything-filtered"
32
+
29
33
  RSPEC__SKIPS_TESTS = "#{HOST}/perma/ruby/rspec-skips-tests"
30
34
 
31
35
  RSPEC__SPLIT_BY_TEST_EXAMPLES__TAG = "#{HOST}/perma/ruby/rspec-split-by-test-examples-tag"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KnapsackPro
2
4
  class Utils
3
5
  def self.unsymbolize(obj)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KnapsackPro
2
- VERSION = '3.8.0'
4
+ VERSION = '7.0.0'
3
5
  end
data/lib/knapsack_pro.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'logger'
2
4
  require 'singleton'
3
5
  require 'net/http'
@@ -6,9 +8,9 @@ require 'uri'
6
8
  require 'rake/testtask'
7
9
  require 'digest'
8
10
  require 'securerandom'
11
+ require 'timeout'
9
12
  require_relative 'knapsack_pro/urls'
10
13
  require_relative 'knapsack_pro/version'
11
- require_relative 'knapsack_pro/extensions/time'
12
14
  require_relative 'knapsack_pro/hooks/queue'
13
15
  require_relative 'knapsack_pro/utils'
14
16
  require_relative 'knapsack_pro/config/ci/base'
@@ -21,8 +23,6 @@ require_relative 'knapsack_pro/config/ci/semaphore'
21
23
  require_relative 'knapsack_pro/config/ci/semaphore2'
22
24
  require_relative 'knapsack_pro/config/ci/buildkite'
23
25
  require_relative 'knapsack_pro/config/ci/travis'
24
- require_relative 'knapsack_pro/config/ci/snap_ci'
25
- require_relative 'knapsack_pro/config/ci/solano_ci'
26
26
  require_relative 'knapsack_pro/config/ci/codeship'
27
27
  require_relative 'knapsack_pro/config/ci/github_actions'
28
28
  require_relative 'knapsack_pro/config/ci/heroku'
@@ -57,6 +57,7 @@ require_relative 'knapsack_pro/adapters/test_unit_adapter'
57
57
  require_relative 'knapsack_pro/adapters/spinach_adapter'
58
58
  require_relative 'knapsack_pro/allocator'
59
59
  require_relative 'knapsack_pro/queue_allocator'
60
+ require_relative 'knapsack_pro/mask_string'
60
61
  require_relative 'knapsack_pro/test_case_mergers/base_merger'
61
62
  require_relative 'knapsack_pro/test_case_mergers/rspec_merger'
62
63
  require_relative 'knapsack_pro/build_distribution_fetcher'
@@ -81,6 +82,7 @@ require_relative 'knapsack_pro/crypto/encryptor'
81
82
  require_relative 'knapsack_pro/crypto/branch_encryptor'
82
83
  require_relative 'knapsack_pro/crypto/decryptor'
83
84
  require_relative 'knapsack_pro/crypto/digestor'
85
+ require_relative 'knapsack_pro/pure/queue/rspec_pure'
84
86
 
85
87
  require 'knapsack_pro/railtie' if defined?(Rails::Railtie)
86
88
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'knapsack_pro'
2
4
 
3
5
  namespace :knapsack_pro do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'knapsack_pro'
2
4
 
3
5
  namespace :knapsack_pro do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'knapsack_pro'
2
4
 
3
5
  namespace :knapsack_pro do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'knapsack_pro'
2
4
 
3
5
  namespace :knapsack_pro do
@@ -1,8 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'knapsack_pro'
2
4
 
3
5
  namespace :knapsack_pro do
4
6
  namespace :queue do
5
7
  task :cucumber, [:cucumber_args] do |_, args|
8
+ Kernel.system("RAILS_ENV=test RACK_ENV=test #{$PROGRAM_NAME} 'knapsack_pro:queue:cucumber_go[#{args[:cucumber_args]}]'")
9
+ exitstatus = $?.exitstatus
10
+ if exitstatus.nil?
11
+ puts 'Something went wrong. Most likely, the process has been killed. Knapsack Pro has been terminated.'
12
+ Kernel.exit(1)
13
+ else
14
+ Kernel.exit(exitstatus)
15
+ end
16
+ end
17
+
18
+ task :cucumber_go, [:cucumber_args] do |_, args|
6
19
  KnapsackPro::Runners::Queue::CucumberRunner.run(args[:cucumber_args])
7
20
  end
8
21
  end
@@ -1,8 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'knapsack_pro'
2
4
 
3
5
  namespace :knapsack_pro do
4
6
  namespace :queue do
5
7
  task :minitest, [:minitest_args] do |_, args|
8
+ Kernel.system("RAILS_ENV=test RACK_ENV=test #{$PROGRAM_NAME} 'knapsack_pro:queue:minitest_go[#{args[:minitest_args]}]'")
9
+ exitstatus = $?.exitstatus
10
+ if exitstatus.nil?
11
+ puts 'Something went wrong. Most likely, the process has been killed. Knapsack Pro has been terminated.'
12
+ Kernel.exit(1)
13
+ else
14
+ Kernel.exit(exitstatus)
15
+ end
16
+ end
17
+
18
+ task :minitest_go, [:minitest_args] do |_, args|
6
19
  KnapsackPro::Runners::Queue::MinitestRunner.run(args[:minitest_args])
7
20
  end
8
21
  end
@@ -1,8 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'knapsack_pro'
2
4
 
3
5
  namespace :knapsack_pro do
4
6
  namespace :queue do
5
7
  task :rspec, [:rspec_args] do |_, args|
8
+ Kernel.system("RAILS_ENV=test RACK_ENV=test #{$PROGRAM_NAME} 'knapsack_pro:queue:rspec_go[#{args[:rspec_args]}]'")
9
+ exitstatus = $?.exitstatus
10
+ if exitstatus.nil?
11
+ puts 'Something went wrong. Most likely, the process has been killed. Knapsack Pro has been terminated.'
12
+ Kernel.exit(1)
13
+ else
14
+ Kernel.exit(exitstatus)
15
+ end
16
+ end
17
+
18
+ task :rspec_go, [:rspec_args] do |_, args|
6
19
  KnapsackPro::Runners::Queue::RSpecRunner.run(args[:rspec_args])
7
20
  end
8
21
  end