knapsack_pro 9.0.0 → 9.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/knapsack_pro/adapters/base_adapter.rb +1 -17
- data/lib/knapsack_pro/adapters/minitest_adapter.rb +8 -13
- data/lib/knapsack_pro/adapters/rspec_adapter.rb +11 -9
- data/lib/knapsack_pro/build_distribution_fetcher.rb +22 -18
- data/lib/knapsack_pro/client/api/v1/build_distributions.rb +2 -7
- data/lib/knapsack_pro/client/api/v1/queues.rb +27 -0
- data/lib/knapsack_pro/client/connection.rb +1 -1
- data/lib/knapsack_pro/config/env.rb +9 -32
- data/lib/knapsack_pro/queue_allocator.rb +2 -1
- data/lib/knapsack_pro/queue_initializer.rb +21 -0
- data/lib/knapsack_pro/regular_allocator.rb +2 -1
- data/lib/knapsack_pro/rspec_slow_test_file_finder.rb +20 -0
- data/lib/knapsack_pro/slow_test_file_determiner.rb +0 -22
- data/lib/knapsack_pro/test_case_detectors/rspec_test_example_detector.rb +43 -69
- data/lib/knapsack_pro/test_case_mergers/rspec_merger.rb +19 -31
- data/lib/knapsack_pro/test_file_finder.rb +15 -42
- data/lib/knapsack_pro/test_file_presenter.rb +4 -0
- data/lib/knapsack_pro/test_suite.rb +8 -35
- data/lib/knapsack_pro/version.rb +1 -1
- data/lib/knapsack_pro.rb +1 -3
- data/lib/tasks/queue/rspec.rake +12 -0
- data/lib/tasks/rspec.rake +8 -4
- metadata +9 -204
- data/.circleci/config.yml +0 -468
- data/.github/assets/install-button.png +0 -0
- data/.github/assets/knapsack-diamonds.png +0 -0
- data/.github/dependabot.yml +0 -11
- data/.github/pull_request_template.md +0 -11
- data/.gitignore +0 -39
- data/.rspec +0 -5
- data/CHANGELOG.md +0 -1995
- data/Gemfile +0 -13
- data/LICENSE +0 -22
- data/README.md +0 -90
- data/Rakefile +0 -2
- data/knapsack_pro.gemspec +0 -43
- data/lib/knapsack_pro/slow_test_file_finder.rb +0 -29
- data/lib/knapsack_pro/test_case_mergers/base_merger.rb +0 -31
- data/lib/knapsack_pro/test_files_with_test_cases_composer.rb +0 -24
- data/spec/fixtures/test_file_list_source_file.txt +0 -6
- data/spec/fixtures/vcr_cassettes/api/v1/build_distributions/subset/invalid_test_suite_token.yml +0 -59
- data/spec/fixtures/vcr_cassettes/api/v1/build_distributions/subset/success.yml +0 -61
- data/spec/fixtures/vcr_cassettes/api/v1/build_subsets/create/invalid_test_suite_token.yml +0 -50
- data/spec/fixtures/vcr_cassettes/api/v1/build_subsets/create/success.yml +0 -50
- data/spec/integration/api/build_distributions_subset_spec.rb +0 -77
- data/spec/integration/api/build_subsets_create_spec.rb +0 -77
- data/spec/integration/runners/fallback_spec.rb +0 -131
- data/spec/integration/runners/queue/cucumber_runner_fallback_spec.rb +0 -129
- data/spec/integration/runners/queue/minitest_runner_fallback_spec.rb +0 -129
- data/spec/integration/runners/queue/rspec_runner.rb +0 -80
- data/spec/integration/runners/queue/rspec_runner_fallback_spec.rb +0 -137
- data/spec/integration/runners/queue/rspec_runner_spec.rb +0 -2672
- data/spec/knapsack_pro/adapters/base_adapter_spec.rb +0 -221
- data/spec/knapsack_pro/adapters/cucumber_adapter_spec.rb +0 -216
- data/spec/knapsack_pro/adapters/minitest_adapter_spec.rb +0 -189
- data/spec/knapsack_pro/adapters/rspec_adapter_spec.rb +0 -427
- data/spec/knapsack_pro/adapters/spinach_adapter_spec.rb +0 -61
- data/spec/knapsack_pro/adapters/test_unit_adapter_spec.rb +0 -86
- data/spec/knapsack_pro/base_allocator_builder_spec.rb +0 -102
- data/spec/knapsack_pro/build_distribution_fetcher_spec.rb +0 -89
- data/spec/knapsack_pro/client/api/action_spec.rb +0 -17
- data/spec/knapsack_pro/client/api/v1/base_spec.rb +0 -2
- data/spec/knapsack_pro/client/api/v1/build_distributions_spec.rb +0 -95
- data/spec/knapsack_pro/client/api/v1/build_subsets_spec.rb +0 -35
- data/spec/knapsack_pro/client/api/v1/queues_spec.rb +0 -83
- data/spec/knapsack_pro/client/connection_spec.rb +0 -581
- data/spec/knapsack_pro/config/ci/app_veyor_spec.rb +0 -87
- data/spec/knapsack_pro/config/ci/base_spec.rb +0 -10
- data/spec/knapsack_pro/config/ci/buildkite_spec.rb +0 -135
- data/spec/knapsack_pro/config/ci/circle_spec.rb +0 -122
- data/spec/knapsack_pro/config/ci/cirrus_ci_spec.rb +0 -87
- data/spec/knapsack_pro/config/ci/codefresh_spec.rb +0 -81
- data/spec/knapsack_pro/config/ci/codeship_spec.rb +0 -80
- data/spec/knapsack_pro/config/ci/github_actions_spec.rb +0 -140
- data/spec/knapsack_pro/config/ci/gitlab_ci_spec.rb +0 -137
- data/spec/knapsack_pro/config/ci/heroku_spec.rb +0 -87
- data/spec/knapsack_pro/config/ci/semaphore2_spec.rb +0 -133
- data/spec/knapsack_pro/config/ci/semaphore_spec.rb +0 -87
- data/spec/knapsack_pro/config/ci/travis_spec.rb +0 -73
- data/spec/knapsack_pro/config/env_generator_spec.rb +0 -52
- data/spec/knapsack_pro/config/env_spec.rb +0 -1291
- data/spec/knapsack_pro/config/temp_files_spec.rb +0 -25
- data/spec/knapsack_pro/crypto/branch_encryptor_spec.rb +0 -53
- data/spec/knapsack_pro/crypto/decryptor_spec.rb +0 -83
- data/spec/knapsack_pro/crypto/digestor_spec.rb +0 -13
- data/spec/knapsack_pro/crypto/encryptor_spec.rb +0 -58
- data/spec/knapsack_pro/formatters/time_tracker_fetcher_spec.rb +0 -27
- data/spec/knapsack_pro/formatters/time_tracker_spec.rb +0 -448
- data/spec/knapsack_pro/hooks/queue_spec.rb +0 -199
- data/spec/knapsack_pro/presenter_spec.rb +0 -57
- data/spec/knapsack_pro/pure/queue/rspec_pure_spec.rb +0 -248
- data/spec/knapsack_pro/queue_spec.rb +0 -35
- data/spec/knapsack_pro/report_spec.rb +0 -232
- data/spec/knapsack_pro/repository_adapter_initiator_spec.rb +0 -21
- data/spec/knapsack_pro/repository_adapters/base_adapter_spec.rb +0 -13
- data/spec/knapsack_pro/repository_adapters/env_adapter_spec.rb +0 -27
- data/spec/knapsack_pro/repository_adapters/git_adapter_spec.rb +0 -106
- data/spec/knapsack_pro/runners/base_runner_spec.rb +0 -87
- data/spec/knapsack_pro/runners/cucumber_runner_spec.rb +0 -92
- data/spec/knapsack_pro/runners/minitest_runner_spec.rb +0 -57
- data/spec/knapsack_pro/runners/queue/base_runner_spec.rb +0 -73
- data/spec/knapsack_pro/runners/queue/cucumber_runner_spec.rb +0 -209
- data/spec/knapsack_pro/runners/queue/minitest_runner_spec.rb +0 -203
- data/spec/knapsack_pro/runners/rspec_runner_spec.rb +0 -111
- data/spec/knapsack_pro/runners/spinach_runner_spec.rb +0 -56
- data/spec/knapsack_pro/runners/test_unit_runner_spec.rb +0 -62
- data/spec/knapsack_pro/slow_test_file_determiner_spec.rb +0 -119
- data/spec/knapsack_pro/slow_test_file_finder_spec.rb +0 -42
- data/spec/knapsack_pro/task_loader_spec.rb +0 -14
- data/spec/knapsack_pro/test_case_detectors/rspec_test_example_detector_spec.rb +0 -217
- data/spec/knapsack_pro/test_case_mergers/base_merger_spec.rb +0 -27
- data/spec/knapsack_pro/test_case_mergers/rspec_merger_spec.rb +0 -81
- data/spec/knapsack_pro/test_file_cleaner_spec.rb +0 -11
- data/spec/knapsack_pro/test_file_finder_spec.rb +0 -176
- data/spec/knapsack_pro/test_file_pattern_spec.rb +0 -49
- data/spec/knapsack_pro/test_file_presenter_spec.rb +0 -22
- data/spec/knapsack_pro/test_files_with_test_cases_composer_spec.rb +0 -41
- data/spec/knapsack_pro/test_flat_distributor_spec.rb +0 -60
- data/spec/knapsack_pro/tracker_spec.rb +0 -184
- data/spec/knapsack_pro/utils_spec.rb +0 -55
- data/spec/knapsack_pro_spec.rb +0 -116
- data/spec/spec_helper.rb +0 -47
- data/spec/support/.gitkeep +0 -0
- data/spec/support/fakes/cucumber.rb +0 -25
- data/spec/support/fakes/minitest.rb +0 -18
- data/spec/support/shared_examples/adapter.rb +0 -17
- data/spec_fake/controllers/users_controller_spec.rb +0 -0
- data/spec_fake/models/admin_spec.rb +0 -0
- data/spec_fake/models/user_spec.rb +0 -0
- data/spec_fake/spec_helper.rb +0 -0
- data/spec_time_tracker/spec_helper.rb +0 -29
- data/test_fake/a_test.rb +0 -0
- data/test_fake/b_test.rb +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 69f4cd183de10604ce425379105354fd37da56929568c6bac466d682dc893088
|
|
4
|
+
data.tar.gz: 3c9c33a0aed5050e6d6582ff66550d8497b833383b1b34c09e622dd8f57bc6b8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bac25fed3f1e309e57f21bbce67391ed2d638d8484c91ce99900aa9ab22bbebde61bf0a968e9bf208f45d9d684574cb8a0b9fd549a0f5875c036b4c0e6aeec30
|
|
7
|
+
data.tar.gz: 35f0c05d901993faa07ceeffc211e596b693aa852671e9a04aa12ca845ef78bb39e332b8011b846a93be6cab17f803197f2e7a008fe9f7d9140ba9df75240561
|
|
@@ -15,26 +15,10 @@ module KnapsackPro
|
|
|
15
15
|
false
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def self.
|
|
18
|
+
def self.calculate_slow_id_paths
|
|
19
19
|
raise NotImplementedError
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
def self.slow_test_file?(adapter_class, test_file_path)
|
|
23
|
-
@slow_test_file_paths ||=
|
|
24
|
-
begin
|
|
25
|
-
slow_test_files =
|
|
26
|
-
if KnapsackPro::Config::Env.slow_test_file_pattern
|
|
27
|
-
KnapsackPro::TestFileFinder.slow_test_files_by_pattern(adapter_class)
|
|
28
|
-
else
|
|
29
|
-
# get slow test files from JSON file based on data from API
|
|
30
|
-
KnapsackPro::SlowTestFileDeterminer.read_from_json_report
|
|
31
|
-
end
|
|
32
|
-
KnapsackPro::TestFilePresenter.paths(slow_test_files)
|
|
33
|
-
end
|
|
34
|
-
clean_path = KnapsackPro::TestFileCleaner.clean(test_file_path)
|
|
35
|
-
@slow_test_file_paths.include?(clean_path)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
22
|
def self.bind
|
|
39
23
|
adapter = new
|
|
40
24
|
adapter.bind
|
|
@@ -7,19 +7,14 @@ module KnapsackPro
|
|
|
7
7
|
@@parent_of_test_dir = nil
|
|
8
8
|
|
|
9
9
|
def self.test_path(obj)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
full_test_path = method_object.source_location.first
|
|
19
|
-
parent_of_test_dir_regexp = Regexp.new("^#{@@parent_of_test_dir}")
|
|
20
|
-
test_path = full_test_path.gsub(parent_of_test_dir_regexp, '.')
|
|
21
|
-
# test_path will look like ./test/dir/unit_test.rb
|
|
22
|
-
test_path
|
|
10
|
+
path, _line =
|
|
11
|
+
begin
|
|
12
|
+
Object.const_source_location(obj.class.to_s)
|
|
13
|
+
rescue NameError
|
|
14
|
+
test_method_name = obj.class.runnable_methods.first
|
|
15
|
+
obj.method(test_method_name).source_location
|
|
16
|
+
end
|
|
17
|
+
path.gsub(Regexp.new("^#{@@parent_of_test_dir}"), '.')
|
|
23
18
|
end
|
|
24
19
|
|
|
25
20
|
# See how to write hooks and plugins
|
|
@@ -20,22 +20,17 @@ module KnapsackPro
|
|
|
20
20
|
true
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
def self.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
# generate the RSpec JSON report in a separate process to not pollute the RSpec state
|
|
23
|
+
def self.calculate_slow_id_paths
|
|
24
|
+
# Shell out not to pollute the RSpec state
|
|
27
25
|
cmd = [
|
|
28
26
|
'RACK_ENV=test',
|
|
29
27
|
'RAILS_ENV=test',
|
|
30
28
|
KnapsackPro::Config::Env.rspec_test_example_detector_prefix,
|
|
31
29
|
'rake knapsack_pro:rspec_test_example_detector',
|
|
32
30
|
].join(' ')
|
|
33
|
-
unless Kernel.system(cmd)
|
|
34
|
-
raise "Could not generate JSON report for RSpec. Rake task failed when running #{cmd}"
|
|
35
|
-
end
|
|
31
|
+
raise "Failed to calculate Split by Test Examples: #{cmd}" unless Kernel.system(cmd)
|
|
36
32
|
|
|
37
|
-
|
|
38
|
-
KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector.new.test_file_example_paths
|
|
33
|
+
KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector.new.slow_id_paths!
|
|
39
34
|
end
|
|
40
35
|
|
|
41
36
|
def self.has_format_option?(cli_args)
|
|
@@ -86,6 +81,13 @@ module KnapsackPro
|
|
|
86
81
|
!id.nil?
|
|
87
82
|
end
|
|
88
83
|
|
|
84
|
+
def self.concat_paths(test_files, id_paths)
|
|
85
|
+
paths = KnapsackPro::TestFilePresenter.paths(test_files)
|
|
86
|
+
file_paths = id_paths.map { |id_path| parse_file_path(id_path) }
|
|
87
|
+
acc = paths + id_paths - file_paths
|
|
88
|
+
KnapsackPro::TestFilePresenter.test_files(acc)
|
|
89
|
+
end
|
|
90
|
+
|
|
89
91
|
def self.rails_helper_exists?(test_dir)
|
|
90
92
|
File.exist?("#{test_dir}/rails_helper.rb")
|
|
91
93
|
end
|
|
@@ -7,10 +7,6 @@ module KnapsackPro
|
|
|
7
7
|
@response = response
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
-
def time_execution
|
|
11
|
-
response.fetch('time_execution')
|
|
12
|
-
end
|
|
13
|
-
|
|
14
10
|
def test_files
|
|
15
11
|
response.fetch('test_files')
|
|
16
12
|
end
|
|
@@ -20,12 +16,6 @@ module KnapsackPro
|
|
|
20
16
|
attr_reader :response
|
|
21
17
|
end
|
|
22
18
|
|
|
23
|
-
def self.call
|
|
24
|
-
new.call
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# get test files and time execution for last build distribution matching:
|
|
28
|
-
# branch, node_total, node_index
|
|
29
19
|
def call
|
|
30
20
|
connection = KnapsackPro::Client::Connection.new(build_action)
|
|
31
21
|
response = connection.call
|
|
@@ -33,11 +23,8 @@ module KnapsackPro
|
|
|
33
23
|
raise ArgumentError.new(response) if connection.errors?
|
|
34
24
|
BuildDistributionEntity.new(response)
|
|
35
25
|
else
|
|
36
|
-
KnapsackPro.logger.warn("
|
|
37
|
-
BuildDistributionEntity.new({
|
|
38
|
-
'time_execution' => 0.0,
|
|
39
|
-
'test_files' => [],
|
|
40
|
-
})
|
|
26
|
+
KnapsackPro.logger.warn("Failed to fetch slow test files. Split by Test Examples disabled. See: #{KnapsackPro::Urls::SPLIT_BY_TEST_EXAMPLES}")
|
|
27
|
+
BuildDistributionEntity.new({ 'time_execution' => 0.0, 'test_files' => [] })
|
|
41
28
|
end
|
|
42
29
|
end
|
|
43
30
|
|
|
@@ -48,12 +35,29 @@ module KnapsackPro
|
|
|
48
35
|
end
|
|
49
36
|
|
|
50
37
|
def build_action
|
|
51
|
-
|
|
38
|
+
request_hash = {
|
|
52
39
|
commit_hash: repository_adapter.commit_hash,
|
|
53
40
|
branch: repository_adapter.branch,
|
|
54
41
|
node_total: KnapsackPro::Config::Env.ci_node_total,
|
|
55
|
-
node_index: KnapsackPro::Config::Env.ci_node_index
|
|
56
|
-
)
|
|
42
|
+
node_index: KnapsackPro::Config::Env.ci_node_index
|
|
43
|
+
}.merge(additional_params)
|
|
44
|
+
|
|
45
|
+
KnapsackPro::Client::API::V1::BuildDistributions.last(request_hash)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def additional_params
|
|
49
|
+
{}
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class OptimizedBuildDistributionFetcher < BuildDistributionFetcher
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def additional_params
|
|
57
|
+
{
|
|
58
|
+
node_build_id: KnapsackPro::Config::Env.ci_node_build_id,
|
|
59
|
+
none_if_queue_initialized: true
|
|
60
|
+
}
|
|
57
61
|
end
|
|
58
62
|
end
|
|
59
63
|
end
|
|
@@ -35,16 +35,11 @@ module KnapsackPro
|
|
|
35
35
|
)
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
def last(
|
|
38
|
+
def last(request_hash)
|
|
39
39
|
action_class.new(
|
|
40
40
|
endpoint_path: '/v1/build_distributions/last',
|
|
41
41
|
http_method: :get,
|
|
42
|
-
request_hash:
|
|
43
|
-
:commit_hash => args.fetch(:commit_hash),
|
|
44
|
-
:branch => args.fetch(:branch),
|
|
45
|
-
:node_total => args.fetch(:node_total),
|
|
46
|
-
:node_index => args.fetch(:node_index),
|
|
47
|
-
}
|
|
42
|
+
request_hash: request_hash
|
|
48
43
|
)
|
|
49
44
|
end
|
|
50
45
|
end
|
|
@@ -36,6 +36,33 @@ module KnapsackPro
|
|
|
36
36
|
request_hash: request_hash
|
|
37
37
|
)
|
|
38
38
|
end
|
|
39
|
+
|
|
40
|
+
def initialize(paths)
|
|
41
|
+
git_adapter = KnapsackPro::RepositoryAdapters::GitAdapter.new
|
|
42
|
+
repository_adapter = KnapsackPro::RepositoryAdapterInitiator.call
|
|
43
|
+
|
|
44
|
+
request_hash = {
|
|
45
|
+
attempt_connect_to_queue: false,
|
|
46
|
+
branch: KnapsackPro::Crypto::BranchEncryptor.call(repository_adapter.branch),
|
|
47
|
+
build_author: git_adapter.build_author,
|
|
48
|
+
can_initialize_queue: true,
|
|
49
|
+
commit_authors: git_adapter.commit_authors,
|
|
50
|
+
commit_hash: repository_adapter.commit_hash,
|
|
51
|
+
fixed_queue_split: KnapsackPro::Config::Env.fixed_queue_split,
|
|
52
|
+
node_build_id: KnapsackPro::Config::Env.ci_node_build_id,
|
|
53
|
+
node_index: KnapsackPro::Config::Env.ci_node_index,
|
|
54
|
+
node_total: KnapsackPro::Config::Env.ci_node_total,
|
|
55
|
+
skip_pull: true,
|
|
56
|
+
test_files: KnapsackPro::Crypto::Encryptor.call(paths),
|
|
57
|
+
user_seat: KnapsackPro::Config::Env.masked_user_seat,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
action_class.new(
|
|
61
|
+
endpoint_path: '/v1/queues/queue',
|
|
62
|
+
http_method: :post,
|
|
63
|
+
request_hash: request_hash
|
|
64
|
+
)
|
|
65
|
+
end
|
|
39
66
|
end
|
|
40
67
|
end
|
|
41
68
|
end
|
|
@@ -142,7 +142,7 @@ module KnapsackPro
|
|
|
142
142
|
"curl -v #{endpoint_uri.host}:#{endpoint_uri.port}",
|
|
143
143
|
"nc -vz #{endpoint_uri.host} #{endpoint_uri.port}",
|
|
144
144
|
"openssl s_client -connect #{endpoint_uri.host}:#{endpoint_uri.port} < /dev/null",
|
|
145
|
-
'env'
|
|
145
|
+
'env | grep KNAPSACK_PRO | grep -v TOKEN'
|
|
146
146
|
].each do |cmd|
|
|
147
147
|
logger.warn(cmd)
|
|
148
148
|
logger.warn('=' * cmd.size)
|
|
@@ -67,6 +67,14 @@ module KnapsackPro
|
|
|
67
67
|
ENV['KNAPSACK_PRO_SLOW_TEST_FILE_PATTERN']
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
+
def slow_test_file_threshold
|
|
71
|
+
ENV.fetch('KNAPSACK_PRO_SLOW_TEST_FILE_THRESHOLD', nil)&.to_f
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def slow_test_file_threshold?
|
|
75
|
+
!!slow_test_file_threshold
|
|
76
|
+
end
|
|
77
|
+
|
|
70
78
|
def test_file_exclude_pattern
|
|
71
79
|
ENV['KNAPSACK_PRO_TEST_FILE_EXCLUDE_PATTERN']
|
|
72
80
|
end
|
|
@@ -132,19 +140,7 @@ module KnapsackPro
|
|
|
132
140
|
end
|
|
133
141
|
|
|
134
142
|
def endpoint
|
|
135
|
-
|
|
136
|
-
return ENV[env_name] if ENV[env_name]
|
|
137
|
-
|
|
138
|
-
case mode
|
|
139
|
-
when :development
|
|
140
|
-
'http://api.knapsackpro.test:3000'
|
|
141
|
-
when :test
|
|
142
|
-
'https://api-staging.knapsackpro.com'
|
|
143
|
-
when :production
|
|
144
|
-
'https://api.knapsackpro.com'
|
|
145
|
-
else
|
|
146
|
-
required_env(env_name)
|
|
147
|
-
end
|
|
143
|
+
ENV.fetch('KNAPSACK_PRO_ENDPOINT', 'https://api.knapsackpro.com')
|
|
148
144
|
end
|
|
149
145
|
|
|
150
146
|
def fixed_test_suite_split
|
|
@@ -200,14 +196,6 @@ module KnapsackPro
|
|
|
200
196
|
ENV.fetch('KNAPSACK_PRO_RSPEC_TEST_EXAMPLE_DETECTOR_PREFIX', 'bundle exec')
|
|
201
197
|
end
|
|
202
198
|
|
|
203
|
-
def slow_test_file_threshold
|
|
204
|
-
ENV.fetch('KNAPSACK_PRO_SLOW_TEST_FILE_THRESHOLD', nil)&.to_f
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
def slow_test_file_threshold?
|
|
208
|
-
!!slow_test_file_threshold
|
|
209
|
-
end
|
|
210
|
-
|
|
211
199
|
def test_suite_token
|
|
212
200
|
env_name = 'KNAPSACK_PRO_TEST_SUITE_TOKEN'
|
|
213
201
|
ENV[env_name] || raise("Missing environment variable #{env_name}. You should set environment variable like #{env_name}_RSPEC (note there is suffix _RSPEC at the end). knapsack_pro gem will set #{env_name} based on #{env_name}_RSPEC value. If you use other test runner than RSpec then use proper suffix.")
|
|
@@ -233,17 +221,6 @@ module KnapsackPro
|
|
|
233
221
|
ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN_SPINACH']
|
|
234
222
|
end
|
|
235
223
|
|
|
236
|
-
def mode
|
|
237
|
-
mode = ENV['KNAPSACK_PRO_MODE']
|
|
238
|
-
return :production if mode.nil?
|
|
239
|
-
mode = mode.to_sym
|
|
240
|
-
if [:development, :test, :production].include?(mode)
|
|
241
|
-
mode
|
|
242
|
-
else
|
|
243
|
-
raise ArgumentError.new('Wrong mode name')
|
|
244
|
-
end
|
|
245
|
-
end
|
|
246
|
-
|
|
247
224
|
def detected_ci
|
|
248
225
|
detected = KnapsackPro::Config::CI.constants.map do |constant|
|
|
249
226
|
Object.const_get("KnapsackPro::Config::CI::#{constant}").new.detected
|
|
@@ -141,8 +141,9 @@ module KnapsackPro
|
|
|
141
141
|
end
|
|
142
142
|
end
|
|
143
143
|
|
|
144
|
+
# Run file paths to guarantee at-least-once execution across CI nodes.
|
|
144
145
|
def fallback_test_files(executed_test_files)
|
|
145
|
-
test_flat_distributor = KnapsackPro::TestFlatDistributor.new(test_suite.
|
|
146
|
+
test_flat_distributor = KnapsackPro::TestFlatDistributor.new(test_suite.all_test_files_to_run, ci_node_total)
|
|
146
147
|
test_files_for_node_index = test_flat_distributor.test_files_for_node(ci_node_index)
|
|
147
148
|
KnapsackPro::TestFilePresenter.paths(test_files_for_node_index) - executed_test_files
|
|
148
149
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module KnapsackPro
|
|
4
|
+
module RSpec
|
|
5
|
+
class QueueInitializer
|
|
6
|
+
def call(args)
|
|
7
|
+
slow_id_paths = KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector.new.calculate_slow_id_paths(args.to_s)
|
|
8
|
+
all_test_files_to_run = KnapsackPro::TestSuite.new(KnapsackPro::Adapters::RSpecAdapter).all_test_files_to_run
|
|
9
|
+
paths = KnapsackPro::Adapters::RSpecAdapter.concat_paths(all_test_files_to_run, slow_id_paths)
|
|
10
|
+
|
|
11
|
+
raise 'No paths to run' if paths.empty?
|
|
12
|
+
action = KnapsackPro::Client::API::V1::Queues.initialize(paths)
|
|
13
|
+
connection = KnapsackPro::Client::Connection.new(action)
|
|
14
|
+
response = connection.call
|
|
15
|
+
return unless response.key?('url') # Race to initialize lost to another parallel node
|
|
16
|
+
|
|
17
|
+
KnapsackPro.logger.info "Build URL: #{response.fetch('url')}"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -131,8 +131,9 @@ module KnapsackPro
|
|
|
131
131
|
end
|
|
132
132
|
end
|
|
133
133
|
|
|
134
|
+
# Run file paths to guarantee at-least-once execution across CI nodes.
|
|
134
135
|
def fallback_test_files
|
|
135
|
-
test_flat_distributor = KnapsackPro::TestFlatDistributor.new(test_suite.
|
|
136
|
+
test_flat_distributor = KnapsackPro::TestFlatDistributor.new(test_suite.all_test_files_to_run, ci_node_total)
|
|
136
137
|
test_files_for_node_index = test_flat_distributor.test_files_for_node(ci_node_index)
|
|
137
138
|
KnapsackPro::TestFilePresenter.paths(test_files_for_node_index)
|
|
138
139
|
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module KnapsackPro
|
|
4
|
+
class RSpecSlowTestFileFinder
|
|
5
|
+
def initialize(build_distribution_fetcher)
|
|
6
|
+
@build_distribution_fetcher = build_distribution_fetcher
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def call
|
|
10
|
+
if KnapsackPro::Config::Env.test_files_encrypted?
|
|
11
|
+
raise "Split by test cases is not possible when you have enabled test file names encryption ( #{KnapsackPro::Urls::ENCRYPTION} ). You need to disable encryption with KNAPSACK_PRO_TEST_FILES_ENCRYPTED=false in order to use split by test cases #{KnapsackPro::Urls::SPLIT_BY_TEST_EXAMPLES}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
test_files_from_api = @build_distribution_fetcher.call.test_files
|
|
15
|
+
merged_test_files_from_api = KnapsackPro::TestCaseMergers::RSpecMerger.new(test_files_from_api).call
|
|
16
|
+
test_files_existing_on_disk = KnapsackPro::TestFileFinder.select_test_files_that_can_be_run(KnapsackPro::Adapters::RSpecAdapter, merged_test_files_from_api)
|
|
17
|
+
KnapsackPro::SlowTestFileDeterminer.call(test_files_existing_on_disk)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -18,27 +18,5 @@ module KnapsackPro
|
|
|
18
18
|
execution_time >= KnapsackPro::Config::Env.slow_test_file_threshold
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
|
-
|
|
22
|
-
def self.save_to_json_report(test_files)
|
|
23
|
-
KnapsackPro::Config::TempFiles.ensure_temp_directory_exists!
|
|
24
|
-
FileUtils.mkdir_p(report_dir)
|
|
25
|
-
File.write(report_path, test_files.to_json)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def self.read_from_json_report
|
|
29
|
-
raise "The report with slow test files has not been generated yet. If you have enabled split by test cases #{KnapsackPro::Urls::SPLIT_BY_TEST_EXAMPLES} and you see this error it means that your tests accidentally cleaned up the .knapsack_pro directory. Please do not remove this directory during tests runtime!" unless File.exist?(report_path)
|
|
30
|
-
slow_test_files_json_report = File.read(report_path)
|
|
31
|
-
JSON.parse(slow_test_files_json_report)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
private
|
|
35
|
-
|
|
36
|
-
def self.report_path
|
|
37
|
-
"#{report_dir}/slow_test_files_node_#{KnapsackPro::Config::Env.ci_node_index}.json"
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def self.report_dir
|
|
41
|
-
"#{KnapsackPro::Config::TempFiles::TEMP_DIRECTORY_PATH}/slow_test_file_determiner"
|
|
42
|
-
end
|
|
43
21
|
end
|
|
44
22
|
end
|
|
@@ -3,87 +3,80 @@
|
|
|
3
3
|
module KnapsackPro
|
|
4
4
|
module TestCaseDetectors
|
|
5
5
|
class RSpecTestExampleDetector
|
|
6
|
-
def
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
cli_format =
|
|
12
|
-
if Gem::Version.new(::RSpec::Core::Version::STRING) < Gem::Version.new('3.6.0')
|
|
13
|
-
require_relative '../formatters/rspec_json_formatter'
|
|
14
|
-
['--format', KnapsackPro::Formatters::RSpecJsonFormatter.to_s]
|
|
15
|
-
else
|
|
16
|
-
['--format', 'json']
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
ensure_report_dir_exists
|
|
20
|
-
remove_old_json_report
|
|
21
|
-
|
|
22
|
-
test_file_entities = slow_test_files
|
|
23
|
-
|
|
24
|
-
if test_file_entities.empty?
|
|
25
|
-
no_examples_json = { examples: [] }.to_json
|
|
26
|
-
File.write(report_path, no_examples_json)
|
|
27
|
-
return
|
|
28
|
-
end
|
|
6
|
+
def dry_run_to_file(rspec_args, slow_test_files = slow_test_files(KnapsackPro::BuildDistributionFetcher.new))
|
|
7
|
+
KnapsackPro::Config::TempFiles.ensure_temp_directory_exists!
|
|
8
|
+
FileUtils.mkdir_p(File.dirname(report_path))
|
|
9
|
+
File.delete(report_path) if File.exist?(report_path)
|
|
10
|
+
return File.write(report_path, { examples: [] }.to_json) if slow_test_files.empty?
|
|
29
11
|
|
|
12
|
+
KnapsackPro.logger.info("Calculating Split by Test Examples. Analyzing #{slow_test_files.size} slow test files.")
|
|
30
13
|
args = (rspec_args || '').split
|
|
31
14
|
cli_args_without_formatters = KnapsackPro::Adapters::RSpecAdapter.remove_formatters(args)
|
|
32
|
-
|
|
33
|
-
# Apply a --format option which overrides formatters from the RSpec custom option files like `.rspec`.
|
|
34
15
|
cli_args = cli_args_without_formatters + cli_format + [
|
|
35
16
|
'--dry-run',
|
|
36
17
|
'--out', report_path,
|
|
37
18
|
'--default-path', test_dir
|
|
38
|
-
] + KnapsackPro::TestFilePresenter.paths(
|
|
39
|
-
exit_code =
|
|
40
|
-
options = ::RSpec::Core::ConfigurationOptions.new(cli_args)
|
|
41
|
-
::RSpec::Core::Runner.new(options).run($stderr, $stdout)
|
|
42
|
-
rescue SystemExit => e
|
|
43
|
-
e.status
|
|
44
|
-
end
|
|
45
|
-
|
|
19
|
+
] + KnapsackPro::TestFilePresenter.paths(slow_test_files)
|
|
20
|
+
exit_code = dry_run(cli_args)
|
|
46
21
|
return if exit_code.zero?
|
|
47
22
|
|
|
48
23
|
report.fetch('messages', []).each { |message| puts message }
|
|
49
24
|
command = (['bundle exec rspec'] + cli_args).join(' ')
|
|
50
|
-
KnapsackPro.logger.error("Failed to
|
|
25
|
+
KnapsackPro.logger.error("Failed to calculate Split by Test Examples: #{command}")
|
|
51
26
|
exit exit_code
|
|
52
27
|
end
|
|
53
28
|
|
|
54
|
-
def
|
|
29
|
+
def calculate_slow_id_paths(rspec_args)
|
|
30
|
+
dry_run_to_file(rspec_args, slow_test_files(KnapsackPro::OptimizedBuildDistributionFetcher.new))
|
|
31
|
+
slow_id_paths!
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def slow_id_paths!
|
|
55
35
|
raise "No report found at #{report_path}" unless File.exist?(report_path)
|
|
56
36
|
|
|
57
|
-
|
|
58
|
-
hash_report = JSON.parse(json_report)
|
|
59
|
-
hash_report
|
|
37
|
+
JSON.parse(File.read(report_path))
|
|
60
38
|
.fetch('examples')
|
|
61
|
-
.map { |
|
|
62
|
-
.map { |path_with_example_id| test_file_hash_for(path_with_example_id) }
|
|
39
|
+
.map { |example| TestFileCleaner.clean(example.fetch('id')) }
|
|
63
40
|
end
|
|
64
41
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# Apply a --format option which overrides formatters from the RSpec custom option files like `.rspec`.
|
|
45
|
+
def cli_format
|
|
46
|
+
require 'rspec/core'
|
|
47
|
+
|
|
48
|
+
if Gem::Version.new(::RSpec::Core::Version::STRING) < Gem::Version.new('3.6.0')
|
|
49
|
+
require_relative '../formatters/rspec_json_formatter'
|
|
50
|
+
['--format', KnapsackPro::Formatters::RSpecJsonFormatter.to_s]
|
|
68
51
|
else
|
|
69
|
-
|
|
70
|
-
# by lib/knapsack_pro/base_allocator_builder.rb
|
|
71
|
-
KnapsackPro::SlowTestFileDeterminer.read_from_json_report
|
|
52
|
+
['--format', 'json']
|
|
72
53
|
end
|
|
73
54
|
end
|
|
74
55
|
|
|
75
|
-
|
|
56
|
+
def dry_run(cli_args)
|
|
57
|
+
require 'rspec/core'
|
|
76
58
|
|
|
77
|
-
|
|
78
|
-
|
|
59
|
+
options = ::RSpec::Core::ConfigurationOptions.new(cli_args)
|
|
60
|
+
::RSpec::Core::Runner.new(options).run($stderr, $stdout)
|
|
61
|
+
rescue SystemExit => e
|
|
62
|
+
e.status
|
|
79
63
|
end
|
|
80
64
|
|
|
81
65
|
def report_path
|
|
82
|
-
"#{
|
|
66
|
+
"#{KnapsackPro::Config::TempFiles::TEMP_DIRECTORY_PATH}/test_case_detectors/rspec/rspec_dry_run_json_report_node_#{KnapsackPro::Config::Env.ci_node_index}.json"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def slow_test_files(build_distribution_fetcher)
|
|
70
|
+
if KnapsackPro::Config::Env.slow_test_file_pattern
|
|
71
|
+
KnapsackPro::TestFileFinder.slow_test_files_by_pattern(adapter_class)
|
|
72
|
+
else
|
|
73
|
+
KnapsackPro::RSpecSlowTestFileFinder.new(build_distribution_fetcher).call
|
|
74
|
+
end
|
|
83
75
|
end
|
|
84
76
|
|
|
85
77
|
def report
|
|
86
78
|
return {} unless File.exist?(report_path)
|
|
79
|
+
|
|
87
80
|
JSON.parse(File.read(report_path))
|
|
88
81
|
end
|
|
89
82
|
|
|
@@ -94,25 +87,6 @@ module KnapsackPro
|
|
|
94
87
|
def test_dir
|
|
95
88
|
KnapsackPro::Config::Env.test_dir || KnapsackPro::TestFilePattern.test_dir(adapter_class)
|
|
96
89
|
end
|
|
97
|
-
|
|
98
|
-
def test_file_pattern
|
|
99
|
-
KnapsackPro::TestFilePattern.call(adapter_class)
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def ensure_report_dir_exists
|
|
103
|
-
KnapsackPro::Config::TempFiles.ensure_temp_directory_exists!
|
|
104
|
-
FileUtils.mkdir_p(report_dir)
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def remove_old_json_report
|
|
108
|
-
File.delete(report_path) if File.exist?(report_path)
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def test_file_hash_for(test_file_path)
|
|
112
|
-
{
|
|
113
|
-
'path' => TestFileCleaner.clean(test_file_path)
|
|
114
|
-
}
|
|
115
|
-
end
|
|
116
90
|
end
|
|
117
91
|
end
|
|
118
92
|
end
|
|
@@ -2,44 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
module KnapsackPro
|
|
4
4
|
module TestCaseMergers
|
|
5
|
-
class RSpecMerger
|
|
5
|
+
class RSpecMerger
|
|
6
|
+
def initialize(test_files)
|
|
7
|
+
@test_files = test_files
|
|
8
|
+
end
|
|
9
|
+
|
|
6
10
|
def call
|
|
7
|
-
|
|
8
|
-
|
|
11
|
+
file_paths = {}
|
|
12
|
+
id_paths = {}
|
|
9
13
|
|
|
10
|
-
test_files.each do |test_file|
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
@test_files.each do |test_file|
|
|
15
|
+
raw_path = test_file.fetch('path')
|
|
16
|
+
file_path = KnapsackPro::Adapters::RSpecAdapter.parse_file_path(raw_path)
|
|
13
17
|
|
|
14
|
-
if KnapsackPro::Adapters::RSpecAdapter.id_path?(
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
if KnapsackPro::Adapters::RSpecAdapter.id_path?(raw_path)
|
|
19
|
+
id_paths[file_path] ||= 0.0
|
|
20
|
+
id_paths[file_path] += test_file.fetch('time_execution')
|
|
17
21
|
else
|
|
18
|
-
|
|
22
|
+
file_paths[file_path] = test_file.fetch('time_execution') # may be nil
|
|
19
23
|
end
|
|
20
24
|
end
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
all_test_files_hash.each do |path, time_execution|
|
|
28
|
-
merged_test_files << {
|
|
29
|
-
'path' => path,
|
|
30
|
-
'time_execution' => time_execution
|
|
31
|
-
}
|
|
32
|
-
end
|
|
33
|
-
merged_test_files
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
private
|
|
37
|
-
|
|
38
|
-
# path - can be:
|
|
39
|
-
# test file path: spec/a_spec.rb
|
|
40
|
-
# or test example path: spec/a_spec.rb[1:1]
|
|
41
|
-
def extract_test_file_path(path)
|
|
42
|
-
path.gsub(/\.rb\[.+\]$/, '.rb')
|
|
26
|
+
file_paths
|
|
27
|
+
.merge(id_paths) { |_, v1, v2| [v1, v2].compact.max }
|
|
28
|
+
.map do |file_path, time_execution|
|
|
29
|
+
{ 'path' => file_path, 'time_execution' => time_execution }
|
|
30
|
+
end
|
|
43
31
|
end
|
|
44
32
|
end
|
|
45
33
|
end
|