knapsack_pro 9.2.1 → 9.2.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c214021f95c75ade998199d051fde0a287ae357174f82fb9193833a70792ae76
4
- data.tar.gz: 5987335be91251d6dba92a1656d981932172897bca175525db2e3421ad718775
3
+ metadata.gz: a3330a86d699278a67d1523c197659a2a22921efe0df740c09d384d5721ae43f
4
+ data.tar.gz: c1a7821b44628a0f3c4e5d1f54b952221a53f66a5b48b917faea5d97093ce002
5
5
  SHA512:
6
- metadata.gz: a47a53fb26eb3aba28c60045d13fda33fb00c6ea46321adb63986e662b74bc7b011097c2fbf90ec68a5be236cf06986a901b6ffef524864352d06d053dcbd962
7
- data.tar.gz: f3210244a10fbd129649586d8ed09441bbb63202bfde66ca3bd1f997c235772cdb4891681b0b8a3918d204f18b4ad3c2522a25ed445bdb830a69423c09b695c2
6
+ metadata.gz: f6d0259620d28ef1e3ff77a051464404f668ddc574a503dafa3b430fff6ecfd7414013f2973eaac2a00c189e1885693c4cb91407df11390cc83005220a22e692
7
+ data.tar.gz: 37c7dd08524763b60e8ba9e401a7092e3d4c0bf11979e499915da8756fbbafcd7c03765469c079aca33af09ee34566478e672c47846e117e9f5379178aca2864
@@ -30,10 +30,8 @@ module KnapsackPro
30
30
  if File.exist?(adapter_bind_method_called_file)
31
31
  File.delete(adapter_bind_method_called_file)
32
32
  else
33
- puts "\n\n"
34
- KnapsackPro.logger.error('-'*10 + ' Configuration error ' + '-'*50)
35
- KnapsackPro.logger.error("You forgot to call #{self}.bind method in your test runner configuration file. It is needed to record test files time execution. Please follow the installation guide to configure your project properly #{KnapsackPro::Urls::INSTALLATION_GUIDE}")
36
- KnapsackPro.logger.error("If you already have #{self}.bind method added and you still see this error then one of your tests must have deleted the .knapsack_pro directory from the disk accidentally. Please ensure you do not remove the .knapsack_pro directory: #{KnapsackPro::Urls::DASHBOARD__ZEROISH_TEST_EXECUTION_TIMES}")
33
+ KnapsackPro.logger.error("The `#{self}.bind` method was not called in the test runner configuration. See: #{KnapsackPro::Urls::INSTALLATION_GUIDE}")
34
+ KnapsackPro.logger.error("If `#{self}.bind` was called and you still see this error, ensure the `.knapsack_pro` directory (or its contents) were not removed during the run: #{KnapsackPro::Urls::DASHBOARD__ZEROISH_TEST_EXECUTION_TIMES}")
37
35
  Kernel.exit(1)
38
36
  end
39
37
  end
@@ -11,6 +11,10 @@ module KnapsackPro
11
11
  response.fetch('test_files')
12
12
  end
13
13
 
14
+ def test_queue_url # Can be present only when using the initialize command
15
+ response.fetch('test_queue_url', nil)
16
+ end
17
+
14
18
  private
15
19
 
16
20
  attr_reader :response
@@ -63,6 +63,32 @@ module KnapsackPro
63
63
  request_hash: request_hash
64
64
  )
65
65
  end
66
+
67
+ def connect
68
+ git_adapter = KnapsackPro::RepositoryAdapters::GitAdapter.new
69
+ repository_adapter = KnapsackPro::RepositoryAdapterInitiator.call
70
+
71
+ request_hash = {
72
+ attempt_connect_to_queue: true,
73
+ branch: KnapsackPro::Crypto::BranchEncryptor.call(repository_adapter.branch),
74
+ build_author: git_adapter.build_author,
75
+ can_initialize_queue: true,
76
+ commit_authors: git_adapter.commit_authors,
77
+ commit_hash: repository_adapter.commit_hash,
78
+ fixed_queue_split: KnapsackPro::Config::Env.fixed_queue_split,
79
+ node_build_id: KnapsackPro::Config::Env.ci_node_build_id,
80
+ node_index: KnapsackPro::Config::Env.ci_node_index,
81
+ node_total: KnapsackPro::Config::Env.ci_node_total,
82
+ skip_pull: true,
83
+ user_seat: KnapsackPro::Config::Env.masked_user_seat,
84
+ }
85
+
86
+ action_class.new(
87
+ endpoint_path: '/v1/queues/queue',
88
+ http_method: :post,
89
+ request_hash: request_hash
90
+ )
91
+ end
66
92
  end
67
93
  end
68
94
  end
@@ -51,10 +51,10 @@ module KnapsackPro
51
51
  .select { |time_execution| time_execution != KnapsackPro::Tracker::DEFAULT_TEST_FILE_TIME }
52
52
 
53
53
  if test_files.size > 0 && measured_test_files.size == 0
54
- KnapsackPro.logger.warn("#{test_files.size} test files were executed on this CI node but the recorded time was lost due to:")
55
- KnapsackPro.logger.warn("1. Please ensure you do not remove the contents of the .knapsack_pro directory between tests run.")
56
- KnapsackPro.logger.warn("2. Ensure you've added Knapsack::Adapters::RSpecAdapter.bind in your rails_helper.rb or spec_helper.rb. Please follow the installation guide again: #{KnapsackPro::Urls::INSTALLATION_GUIDE}")
57
- KnapsackPro.logger.warn("3. Another potential reason for this warning is that all your tests are empty test files, pending tests, or they have syntax errors, and the time execution was not recorded for them.")
54
+ KnapsackPro.logger.warn("#{test_files.size} test files were executed, but their execution time could not be recorded. This usually happens when one of the following is true:")
55
+ KnapsackPro.logger.warn('- The `.knapsack_pro` directory (or its contents) were removed during the run.')
56
+ KnapsackPro.logger.warn("- The `bind` method was not called in the test runner configuration. See: #{KnapsackPro::Urls::INSTALLATION_GUIDE}")
57
+ KnapsackPro.logger.warn('- The test files did not run any tests because they are empty, contain only pending tests, or have syntax errors.')
58
58
  end
59
59
 
60
60
  create_build_subset(test_files)
@@ -43,18 +43,39 @@ module KnapsackPro
43
43
  private
44
44
 
45
45
  def git_commit_authors
46
- if KnapsackPro::Config::Env.ci? && shallow_repository?
47
- command = 'git fetch --shallow-since "one month ago" --quiet 2>/dev/null'
48
- begin
49
- Timeout.timeout(5) do
50
- `#{command}`
51
- end
52
- rescue Timeout::Error
53
- KnapsackPro.logger.debug("Skip the `#{command}` command because it took too long.")
54
- end
46
+ git_unshallow if KnapsackPro::Config::Env.ci? && shallow_repository?
47
+ `git log --since "one month ago" 2>/dev/null | git shortlog --summary --email 2>/dev/null`
48
+ end
49
+
50
+ def git_unshallow
51
+ args = ['git', 'fetch', '--quiet', '--shallow-since', 'one month ago']
52
+
53
+ begin
54
+ pid = Process.spawn(*args, [:out, :err] => File::NULL)
55
+ rescue StandardError => e
56
+ KnapsackPro.logger.debug("Failed to unshallow (#{args.join(' ')}): #{e.message}")
57
+ return
55
58
  end
56
59
 
57
- `git log --since "one month ago" 2>/dev/null | git shortlog --summary --email 2>/dev/null`
60
+ begin
61
+ Timeout.timeout(5) { safe_waitpid(pid) }
62
+ rescue Timeout::Error
63
+ safe_kill(pid)
64
+ Timeout.timeout(1) { safe_waitpid(pid) } rescue Timeout::Error
65
+ KnapsackPro.logger.debug("Failed to unshallow (#{args.join(' ')}) in 5 seconds")
66
+ end
67
+ end
68
+
69
+ def safe_waitpid(pid)
70
+ Process.waitpid(pid)
71
+ rescue Errno::ECHILD
72
+ nil
73
+ end
74
+
75
+ def safe_kill(pid)
76
+ Process.kill('KILL', pid)
77
+ rescue Errno::ESRCH
78
+ nil
58
79
  end
59
80
 
60
81
  def git_build_author
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KnapsackPro
4
+ module RSpec
5
+ class TestQueueInitializer
6
+ def call(args)
7
+ test_queue_url, slow_id_paths = KnapsackPro::TestCaseDetectors::RSpecTestExampleDetector
8
+ .new
9
+ .calculate_slow_id_paths(args.to_s)
10
+ .values_at(:test_queue_url, :slow_id_paths)
11
+
12
+ unless test_queue_url.nil? # The test queue already existed when calculating the slow id paths.
13
+ KnapsackPro.logger.info "Test Queue URL: #{test_queue_url}"
14
+ exit 0
15
+ end
16
+
17
+ # The test queue was created by another node while this one calculated the slow id paths via the RSpec dry-run.
18
+ exit 0 if test_queue_exists?
19
+
20
+ initialize_test_queue(slow_id_paths)
21
+ end
22
+
23
+ private
24
+
25
+ def test_queue_exists?
26
+ action = KnapsackPro::Client::API::V1::Queues.connect
27
+ connection = KnapsackPro::Client::Connection.new(action)
28
+ response = connection.call
29
+
30
+ unless connection.success?
31
+ KnapsackPro.logger.error "Failed to initialize the test queue."
32
+ exit 1
33
+ end
34
+
35
+ if connection.errors?
36
+ KnapsackPro.logger.error "Failed to initialize the test queue."
37
+ KnapsackPro.logger.error response.inspect
38
+ exit 1
39
+ end
40
+
41
+ return false unless response.key?('url')
42
+
43
+ KnapsackPro.logger.info "Test Queue URL: #{response.fetch('url')}"
44
+ true
45
+ end
46
+
47
+ def initialize_test_queue(slow_id_paths)
48
+ all_test_files_to_run = KnapsackPro::TestSuite.new(KnapsackPro::Adapters::RSpecAdapter).all_test_files_to_run
49
+ paths = KnapsackPro::Adapters::RSpecAdapter.concat_paths(all_test_files_to_run, slow_id_paths)
50
+
51
+ if paths.empty?
52
+ KnapsackPro.logger.error "No paths to run."
53
+ exit 1
54
+ end
55
+
56
+ action = KnapsackPro::Client::API::V1::Queues.initialize(paths)
57
+ connection = KnapsackPro::Client::Connection.new(action)
58
+ response = connection.call
59
+
60
+ unless connection.success?
61
+ KnapsackPro.logger.error "Failed to initialize the test queue."
62
+ exit 1
63
+ end
64
+
65
+ if connection.errors?
66
+ KnapsackPro.logger.error "Failed to initialize the test queue."
67
+ KnapsackPro.logger.error response.inspect
68
+ exit 1
69
+ end
70
+
71
+ if response.key?('url')
72
+ KnapsackPro.logger.info "Test Queue URL: #{response.fetch('url')}"
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -3,7 +3,7 @@
3
3
  module KnapsackPro
4
4
  module TestCaseDetectors
5
5
  class RSpecTestExampleDetector
6
- def dry_run_to_file(rspec_args, slow_test_files = slow_test_files(KnapsackPro::BuildDistributionFetcher.new))
6
+ def dry_run_to_file(rspec_args, slow_test_files = fetch_slow_file_paths.fetch(:slow_file_paths))
7
7
  KnapsackPro::Config::TempFiles.ensure_temp_directory_exists!
8
8
  FileUtils.mkdir_p(File.dirname(report_path))
9
9
  File.delete(report_path) if File.exist?(report_path)
@@ -27,8 +27,11 @@ module KnapsackPro
27
27
  end
28
28
 
29
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!
30
+ result = fetch_slow_file_paths(KnapsackPro::OptimizedBuildDistributionFetcher.new)
31
+ return { slow_id_paths: [], test_queue_url: result.fetch(:test_queue_url) } unless result.fetch(:test_queue_url).nil?
32
+
33
+ dry_run_to_file(rspec_args, result.fetch(:slow_file_paths))
34
+ { slow_id_paths: slow_id_paths!, test_queue_url: nil }
32
35
  end
33
36
 
34
37
  def slow_id_paths!
@@ -66,12 +69,27 @@ module KnapsackPro
66
69
  "#{KnapsackPro::Config::TempFiles::TEMP_DIRECTORY_PATH}/test_case_detectors/rspec/rspec_dry_run_json_report_node_#{KnapsackPro::Config::Env.ci_node_index}.json"
67
70
  end
68
71
 
69
- def slow_test_files(build_distribution_fetcher)
72
+ def fetch_slow_file_paths(build_distribution_fetcher = KnapsackPro::BuildDistributionFetcher.new)
70
73
  if KnapsackPro::Config::Env.slow_test_file_pattern
71
- KnapsackPro::TestFileFinder.slow_test_files_by_pattern(adapter_class)
74
+ slow_file_paths = KnapsackPro::TestFileFinder.slow_test_files_by_pattern(adapter_class)
75
+ { slow_file_paths: slow_file_paths, test_queue_url: nil }
72
76
  else
73
- KnapsackPro::RSpecSlowTestFileFinder.new(build_distribution_fetcher).call
77
+ determine_slow_file_paths(build_distribution_fetcher)
78
+ end
79
+ end
80
+
81
+ def determine_slow_file_paths(build_distribution_fetcher)
82
+ if KnapsackPro::Config::Env.test_files_encrypted?
83
+ 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}"
74
84
  end
85
+
86
+ build_distribution = build_distribution_fetcher.call
87
+ return { slow_file_paths: [], test_queue_url: build_distribution.test_queue_url } unless build_distribution.test_queue_url.nil?
88
+
89
+ merged_test_files_from_api = KnapsackPro::TestCaseMergers::RSpecMerger.new(build_distribution.test_files).call
90
+ test_files_existing_on_disk = KnapsackPro::TestFileFinder.select_test_files_that_can_be_run(KnapsackPro::Adapters::RSpecAdapter, merged_test_files_from_api)
91
+ slow_file_paths = KnapsackPro::SlowTestFileDeterminer.call(test_files_existing_on_disk)
92
+ { slow_file_paths: slow_file_paths, test_queue_url: nil }
75
93
  end
76
94
 
77
95
  def report
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KnapsackPro
4
- VERSION = '9.2.1'
4
+ VERSION = '9.2.3'
5
5
  end
data/lib/knapsack_pro.rb CHANGED
@@ -61,7 +61,6 @@ require_relative 'knapsack_pro/test_suite'
61
61
  require_relative 'knapsack_pro/test_case_mergers/rspec_merger'
62
62
  require_relative 'knapsack_pro/build_distribution_fetcher'
63
63
  require_relative 'knapsack_pro/slow_test_file_determiner'
64
- require_relative 'knapsack_pro/rspec_slow_test_file_finder'
65
64
  require_relative 'knapsack_pro/base_allocator_builder'
66
65
  require_relative 'knapsack_pro/regular_allocator_builder'
67
66
  require_relative 'knapsack_pro/queue_allocator_builder'
@@ -16,12 +16,12 @@ namespace :knapsack_pro do
16
16
  namespace :rspec do
17
17
  desc 'Initialize the test queue to be consumed later.'
18
18
  task :initialize, [:rspec_args] do |_, args|
19
- require_relative '../../knapsack_pro/queue_initializer'
19
+ require_relative '../../knapsack_pro/rspec/test_queue_initializer'
20
20
 
21
21
  ENV.delete('SPEC_OPTS') # Ignore `SPEC_OPTS` to not affect the RSpec execution within this rake task
22
22
  ENV['KNAPSACK_PRO_TEST_SUITE_TOKEN'] = KnapsackPro::Config::Env.test_suite_token_rspec
23
23
 
24
- KnapsackPro::RSpec::QueueInitializer.new.call(args[:rspec_args].to_s)
24
+ KnapsackPro::RSpec::TestQueueInitializer.new.call(args[:rspec_args].to_s)
25
25
  end
26
26
  end
27
27
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knapsack_pro
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.2.1
4
+ version: 9.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - ArturT
@@ -23,6 +23,20 @@ dependencies:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
25
  version: '0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: logger
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
26
40
  - !ruby/object:Gem::Dependency
27
41
  name: bundler
28
42
  requirement: !ruby/object:Gem::Requirement
@@ -250,7 +264,6 @@ files:
250
264
  - lib/knapsack_pro/queue.rb
251
265
  - lib/knapsack_pro/queue_allocator.rb
252
266
  - lib/knapsack_pro/queue_allocator_builder.rb
253
- - lib/knapsack_pro/queue_initializer.rb
254
267
  - lib/knapsack_pro/railtie.rb
255
268
  - lib/knapsack_pro/regular_allocator.rb
256
269
  - lib/knapsack_pro/regular_allocator_builder.rb
@@ -259,7 +272,7 @@ files:
259
272
  - lib/knapsack_pro/repository_adapters/base_adapter.rb
260
273
  - lib/knapsack_pro/repository_adapters/env_adapter.rb
261
274
  - lib/knapsack_pro/repository_adapters/git_adapter.rb
262
- - lib/knapsack_pro/rspec_slow_test_file_finder.rb
275
+ - lib/knapsack_pro/rspec/test_queue_initializer.rb
263
276
  - lib/knapsack_pro/runners/base_runner.rb
264
277
  - lib/knapsack_pro/runners/cucumber_runner.rb
265
278
  - lib/knapsack_pro/runners/minitest_runner.rb
@@ -1,21 +0,0 @@
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
@@ -1,20 +0,0 @@
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