knapsack_pro 5.3.2 → 5.3.4

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