knapsack_pro 5.3.2 → 5.3.4

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: faf54d04d0dc54356dc2e748db408a9b05ee5d012eb0e56f57029f7341db3feb
4
- data.tar.gz: fdfc75c76af649348241cdfce8a4910e3647bb57dbd6058b013863e49f5e4640
3
+ metadata.gz: 6952ceb372cbcc2dc8c2c5514f0fe68bc4be51572199168e3d7f7992eabdfe43
4
+ data.tar.gz: '077863b80cab5c090ad84c62cbb0c2d680757ea19da59e94c92cb9ee2770ba90'
5
5
  SHA512:
6
- metadata.gz: 14bd3b971bf915d2354cb06e6450d6db587d8df36d9c042e0379f5ad77d972e78361109f6bafd9624b86edfcbe8030805eb95a20efd519c85d9bc459a68c8985
7
- data.tar.gz: 5a4128dcc5b84d38cef6cb21f3a68685c7d68e41be16088cb8d5b76c11a82679a33cc3e95a0a4fb2f7bfb576a22bd42305763b6cbd738ebc83ebb76f8c56420e
6
+ metadata.gz: 3ba6a868b796019d571c077131e1cd33016bee27e7a8cbd1b1d35cfe31532c2049734d1cf24686ac5ef63a881a82ed0c3d811d4e04ccf17ba0444a856121e363
7
+ data.tar.gz: a717af5c831cfd8984ac2c2d691b557dd7cd919e1e7a223d9347eac8d28345700bdcefdf50d0fc5ab10a23c2c9dd4811e95198c443530d83006e7baeee898dbb
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ### 5.3.4
4
+
5
+ * fix(Queue Mode): handle OS signals and RSpec internal `wants_to_quit` and `rspec_is_quitting` states to stop consuming tests from the Queue API when the CI node is terminated
6
+
7
+ https://github.com/KnapsackPro/knapsack_pro-ruby/pull/207
8
+
9
+ https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v5.3.3...v5.3.4
10
+
11
+ ### 5.3.3
12
+
13
+ * Fix hanging CI when `git fetch --shallow-since` takes too long
14
+
15
+ https://github.com/KnapsackPro/knapsack_pro-ruby/pull/213
16
+
17
+ https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v5.3.2...v5.3.3
18
+
3
19
  ### 5.3.2
4
20
 
5
21
  * On top of 5.3.1, avoid noise to stderr when git is not available when collecting the build author
@@ -41,8 +41,15 @@ module KnapsackPro
41
41
  private
42
42
 
43
43
  def git_commit_authors
44
- if KnapsackPro::Config::Env.ci?
45
- `git fetch --shallow-since "one month ago" --quiet 2>/dev/null`
44
+ if KnapsackPro::Config::Env.ci? && shallow_repository?
45
+ command = 'git fetch --shallow-since "one month ago" --quiet 2>/dev/null'
46
+ begin
47
+ Timeout.timeout(5) do
48
+ `#{command}`
49
+ end
50
+ rescue Timeout::Error
51
+ KnapsackPro.logger.debug("Skip the `#{command}` command because it took too long.")
52
+ end
46
53
  end
47
54
 
48
55
  `git log --since "one month ago" 2>/dev/null | git shortlog --summary --email 2>/dev/null`
@@ -52,6 +59,11 @@ module KnapsackPro
52
59
  `git log --format="%aN <%aE>" -1 2>/dev/null`
53
60
  end
54
61
 
62
+ def shallow_repository?
63
+ result = `git rev-parse --is-shallow-repository 2>/dev/null`
64
+ result.strip == 'true'
65
+ end
66
+
55
67
  def working_dir
56
68
  dir = KnapsackPro::Config::Env.project_dir
57
69
  File.expand_path(dir)
@@ -2,6 +2,10 @@ module KnapsackPro
2
2
  module Runners
3
3
  module Queue
4
4
  class BaseRunner
5
+ TERMINATION_SIGNALS = %w(HUP INT TERM ABRT QUIT USR1 USR2)
6
+
7
+ @@terminate_process = false
8
+
5
9
  def self.run(args)
6
10
  raise NotImplementedError
7
11
  end
@@ -13,6 +17,7 @@ module KnapsackPro
13
17
  def initialize(adapter_class)
14
18
  @allocator_builder = KnapsackPro::QueueAllocatorBuilder.new(adapter_class)
15
19
  @allocator = allocator_builder.allocator
20
+ trap_signals
16
21
  end
17
22
 
18
23
  def test_file_paths(args)
@@ -33,6 +38,23 @@ module KnapsackPro
33
38
  def self.child_status
34
39
  $?
35
40
  end
41
+
42
+ def self.handle_signal!
43
+ raise 'Knapsack Pro process was terminated!' if @@terminate_process
44
+ end
45
+
46
+ def self.set_terminate_process
47
+ @@terminate_process = true
48
+ end
49
+
50
+ def trap_signals
51
+ TERMINATION_SIGNALS.each do |signal|
52
+ Signal.trap(signal) {
53
+ puts "#{signal} signal has been received. Terminating Knapsack Pro..."
54
+ @@terminate_process = true
55
+ }
56
+ end
57
+ end
36
58
  end
37
59
  end
38
60
  end
@@ -22,6 +22,7 @@ module KnapsackPro
22
22
  all_test_file_paths: [],
23
23
  }
24
24
  while accumulator[:status] == :next
25
+ handle_signal!
25
26
  accumulator = run_tests(accumulator)
26
27
  end
27
28
 
@@ -29,6 +29,7 @@ module KnapsackPro
29
29
  all_test_file_paths: [],
30
30
  }
31
31
  while accumulator[:status] == :next
32
+ handle_signal!
32
33
  accumulator = run_tests(accumulator)
33
34
  end
34
35
 
@@ -37,6 +37,7 @@ module KnapsackPro
37
37
  all_test_file_paths: [],
38
38
  }
39
39
  while accumulator[:status] == :next
40
+ handle_signal!
40
41
  accumulator = run_tests(accumulator)
41
42
  end
42
43
 
@@ -94,6 +95,15 @@ module KnapsackPro
94
95
  exit_code = rspec_runner.run($stderr, $stdout)
95
96
  exitstatus = exit_code if exit_code != 0
96
97
 
98
+ if rspec_runner.world.wants_to_quit
99
+ KnapsackPro.logger.warn('RSpec wants to quit.')
100
+ set_terminate_process
101
+ end
102
+ if rspec_runner.world.rspec_is_quitting
103
+ KnapsackPro.logger.warn('RSpec is quitting.')
104
+ set_terminate_process
105
+ end
106
+
97
107
  printable_args = args_with_seed_option_added_when_viable(args, rspec_runner)
98
108
  log_rspec_command(printable_args, test_file_paths, :subset_queue)
99
109
 
@@ -1,3 +1,3 @@
1
1
  module KnapsackPro
2
- VERSION = '5.3.2'
2
+ VERSION = '5.3.4'
3
3
  end
data/lib/knapsack_pro.rb CHANGED
@@ -6,6 +6,7 @@ require 'uri'
6
6
  require 'rake/testtask'
7
7
  require 'digest'
8
8
  require 'securerandom'
9
+ require 'timeout'
9
10
  require_relative 'knapsack_pro/urls'
10
11
  require_relative 'knapsack_pro/version'
11
12
  require_relative 'knapsack_pro/extensions/time'
@@ -4,7 +4,13 @@ namespace :knapsack_pro do
4
4
  namespace :queue do
5
5
  task :cucumber, [:cucumber_args] do |_, args|
6
6
  Kernel.system("RAILS_ENV=test RACK_ENV=test #{$PROGRAM_NAME} 'knapsack_pro:queue:cucumber_go[#{args[:cucumber_args]}]'")
7
- Kernel.exit($?.exitstatus)
7
+ exitstatus = $?.exitstatus
8
+ if exitstatus.nil?
9
+ puts 'Something went wrong. Most likely, the process has been killed. Knapsack Pro has been terminated.'
10
+ Kernel.exit(1)
11
+ else
12
+ Kernel.exit(exitstatus)
13
+ end
8
14
  end
9
15
 
10
16
  task :cucumber_go, [:cucumber_args] do |_, args|
@@ -4,7 +4,13 @@ namespace :knapsack_pro do
4
4
  namespace :queue do
5
5
  task :minitest, [:minitest_args] do |_, args|
6
6
  Kernel.system("RAILS_ENV=test RACK_ENV=test #{$PROGRAM_NAME} 'knapsack_pro:queue:minitest_go[#{args[:minitest_args]}]'")
7
- Kernel.exit($?.exitstatus)
7
+ exitstatus = $?.exitstatus
8
+ if exitstatus.nil?
9
+ puts 'Something went wrong. Most likely, the process has been killed. Knapsack Pro has been terminated.'
10
+ Kernel.exit(1)
11
+ else
12
+ Kernel.exit(exitstatus)
13
+ end
8
14
  end
9
15
 
10
16
  task :minitest_go, [:minitest_args] do |_, args|
@@ -4,7 +4,13 @@ namespace :knapsack_pro do
4
4
  namespace :queue do
5
5
  task :rspec, [:rspec_args] do |_, args|
6
6
  Kernel.system("RAILS_ENV=test RACK_ENV=test #{$PROGRAM_NAME} 'knapsack_pro:queue:rspec_go[#{args[:rspec_args]}]'")
7
- Kernel.exit($?.exitstatus)
7
+ exitstatus = $?.exitstatus
8
+ if exitstatus.nil?
9
+ puts 'Something went wrong. Most likely, the process has been killed. Knapsack Pro has been terminated.'
10
+ Kernel.exit(1)
11
+ else
12
+ Kernel.exit(exitstatus)
13
+ end
8
14
  end
9
15
 
10
16
  task :rspec_go, [:rspec_args] do |_, args|
@@ -41,6 +41,7 @@ describe KnapsackPro::Runners::Queue::CucumberRunner do
41
41
  exitstatus: 0,
42
42
  all_test_file_paths: [],
43
43
  }
44
+ expect(described_class).to receive(:handle_signal!)
44
45
  expect(described_class).to receive(:run_tests).with(accumulator).and_return(expected_accumulator)
45
46
 
46
47
  expect(Kernel).to receive(:exit).with(expected_exitstatus)
@@ -66,6 +67,7 @@ describe KnapsackPro::Runners::Queue::CucumberRunner do
66
67
  exitstatus: 0,
67
68
  all_test_file_paths: [],
68
69
  }
70
+ expect(described_class).to receive(:handle_signal!)
69
71
  expect(described_class).to receive(:run_tests).with(accumulator).and_return(expected_accumulator)
70
72
 
71
73
  expect(Kernel).to receive(:exit).with(expected_exitstatus)
@@ -43,6 +43,7 @@ describe KnapsackPro::Runners::Queue::MinitestRunner do
43
43
  exitstatus: 0,
44
44
  all_test_file_paths: [],
45
45
  }
46
+ expect(described_class).to receive(:handle_signal!)
46
47
  expect(described_class).to receive(:run_tests).with(accumulator).and_return(expected_accumulator)
47
48
 
48
49
  expect(Kernel).to receive(:exit).with(expected_exitstatus)
@@ -68,6 +69,7 @@ describe KnapsackPro::Runners::Queue::MinitestRunner do
68
69
  exitstatus: 0,
69
70
  all_test_file_paths: [],
70
71
  }
72
+ expect(described_class).to receive(:handle_signal!)
71
73
  expect(described_class).to receive(:run_tests).with(accumulator).and_return(expected_accumulator)
72
74
 
73
75
  expect(Kernel).to receive(:exit).with(expected_exitstatus)
@@ -49,6 +49,7 @@ describe KnapsackPro::Runners::Queue::RSpecRunner do
49
49
  exitstatus: 0,
50
50
  all_test_file_paths: [],
51
51
  }
52
+ expect(described_class).to receive(:handle_signal!)
52
53
  expect(described_class).to receive(:run_tests).with(accumulator).and_return(expected_accumulator)
53
54
 
54
55
  expect(Kernel).to receive(:exit).with(expected_exitstatus)
@@ -74,6 +75,7 @@ describe KnapsackPro::Runners::Queue::RSpecRunner do
74
75
  exitstatus: 0,
75
76
  all_test_file_paths: [],
76
77
  }
78
+ expect(described_class).to receive(:handle_signal!)
77
79
  expect(described_class).to receive(:run_tests).with(accumulator).and_return(expected_accumulator)
78
80
 
79
81
  expect(Kernel).to receive(:exit).with(expected_exitstatus)
@@ -99,6 +101,7 @@ describe KnapsackPro::Runners::Queue::RSpecRunner do
99
101
  exitstatus: 0,
100
102
  all_test_file_paths: [],
101
103
  }
104
+ expect(described_class).to receive(:handle_signal!)
102
105
  expect(described_class).to receive(:run_tests).with(accumulator).and_return(expected_accumulator)
103
106
 
104
107
  expect(Kernel).to receive(:exit).with(expected_exitstatus)
@@ -124,6 +127,7 @@ describe KnapsackPro::Runners::Queue::RSpecRunner do
124
127
  exitstatus: 0,
125
128
  all_test_file_paths: [],
126
129
  }
130
+ expect(described_class).to receive(:handle_signal!)
127
131
  expect(described_class).to receive(:run_tests).with(accumulator).and_return(expected_accumulator)
128
132
 
129
133
  expect(Kernel).to receive(:exit).with(expected_exitstatus)
@@ -165,6 +169,7 @@ describe KnapsackPro::Runners::Queue::RSpecRunner do
165
169
  exitstatus: 0,
166
170
  all_test_file_paths: [],
167
171
  }
172
+ expect(described_class).to receive(:handle_signal!)
168
173
  expect(described_class).to receive(:run_tests).with(accumulator).and_return(expected_accumulator)
169
174
 
170
175
  expect(Kernel).to receive(:exit).with(expected_exitstatus)
@@ -200,6 +205,12 @@ describe KnapsackPro::Runners::Queue::RSpecRunner do
200
205
  let(:test_file_paths) { ['a_spec.rb', 'b_spec.rb'] }
201
206
  let(:logger) { double }
202
207
  let(:rspec_seed) { 7771 }
208
+ let(:exit_code) { [0, 1].sample }
209
+ let(:rspec_wants_to_quit) { false }
210
+ let(:rspec_is_quitting) { false }
211
+ let(:rspec_core_runner) do
212
+ double(world: double(wants_to_quit: rspec_wants_to_quit, rspec_is_quitting: rspec_is_quitting))
213
+ end
203
214
 
204
215
  before do
205
216
  subset_queue_id = 'fake-subset-queue-id'
@@ -220,7 +231,6 @@ describe KnapsackPro::Runners::Queue::RSpecRunner do
220
231
  'a_spec.rb', 'b_spec.rb',
221
232
  ]).and_return(options)
222
233
 
223
- rspec_core_runner = double
224
234
  expect(RSpec::Core::Runner).to receive(:new).with(options).and_return(rspec_core_runner)
225
235
  expect(rspec_core_runner).to receive(:run).with($stderr, $stdout).and_return(exit_code)
226
236
 
@@ -237,13 +247,13 @@ describe KnapsackPro::Runners::Queue::RSpecRunner do
237
247
  expect(configuration).to receive(:seed_used?).and_return(true)
238
248
  expect(configuration).to receive(:seed).and_return(rspec_seed)
239
249
 
240
- expect(KnapsackPro).to receive(:logger).twice.and_return(logger)
250
+ expect(KnapsackPro).to receive(:logger).at_least(2).and_return(logger)
241
251
  expect(logger).to receive(:info)
242
252
  .with("To retry the last batch of tests fetched from the API Queue, please run the following command on your machine:")
243
253
  expect(logger).to receive(:info).with(/#{args.join(' ')} --seed #{rspec_seed}/)
244
254
  end
245
255
 
246
- context 'when exit code is zero' do
256
+ context 'when the exit code is zero' do
247
257
  let(:exit_code) { 0 }
248
258
 
249
259
  it do
@@ -258,7 +268,7 @@ describe KnapsackPro::Runners::Queue::RSpecRunner do
258
268
  end
259
269
  end
260
270
 
261
- context 'when exit code is not zero' do
271
+ context 'when the exit code is not zero' do
262
272
  let(:exit_code) { double }
263
273
 
264
274
  it do
@@ -272,6 +282,58 @@ describe KnapsackPro::Runners::Queue::RSpecRunner do
272
282
  })
273
283
  end
274
284
  end
285
+
286
+ context 'when RSpec wants to quit' do
287
+ let(:exit_code) { 0 }
288
+ let(:rspec_wants_to_quit) { true }
289
+
290
+ after do
291
+ described_class.class_variable_set(:@@terminate_process, false)
292
+ end
293
+
294
+ it 'terminates the process' do
295
+ expect(logger).to receive(:warn).with('RSpec wants to quit.')
296
+
297
+ expect(described_class.class_variable_get(:@@terminate_process)).to be false
298
+
299
+ expect(subject).to eq({
300
+ status: :next,
301
+ runner: runner,
302
+ can_initialize_queue: false,
303
+ args: args,
304
+ exitstatus: exitstatus,
305
+ all_test_file_paths: test_file_paths,
306
+ })
307
+
308
+ expect(described_class.class_variable_get(:@@terminate_process)).to be true
309
+ end
310
+ end
311
+
312
+ context 'when RSpec is quitting' do
313
+ let(:exit_code) { 0 }
314
+ let(:rspec_is_quitting) { true }
315
+
316
+ after do
317
+ described_class.class_variable_set(:@@terminate_process, false)
318
+ end
319
+
320
+ it 'terminates the process' do
321
+ expect(logger).to receive(:warn).with('RSpec is quitting.')
322
+
323
+ expect(described_class.class_variable_get(:@@terminate_process)).to be false
324
+
325
+ expect(subject).to eq({
326
+ status: :next,
327
+ runner: runner,
328
+ can_initialize_queue: false,
329
+ args: args,
330
+ exitstatus: exitstatus,
331
+ all_test_file_paths: test_file_paths,
332
+ })
333
+
334
+ expect(described_class.class_variable_get(:@@terminate_process)).to be true
335
+ end
336
+ end
275
337
  end
276
338
 
277
339
  context "when test files don't exist" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knapsack_pro
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.3.2
4
+ version: 5.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - ArturT
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-20 00:00:00.000000000 Z
11
+ date: 2023-07-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake