parallel_cucumber 0.2.19 → 0.2.24
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/parallel_cucumber/cli.rb +0 -12
- data/lib/parallel_cucumber/dsl.rb +8 -0
- data/lib/parallel_cucumber/helper/command.rb +50 -37
- data/lib/parallel_cucumber/helper/cucumber/cucumber.rb +7 -0
- data/lib/parallel_cucumber/helper/cucumber/json_status_formatter.rb +1 -0
- data/lib/parallel_cucumber/helper/processes.rb +2 -2
- data/lib/parallel_cucumber/hooks.rb +29 -5
- data/lib/parallel_cucumber/main.rb +6 -2
- data/lib/parallel_cucumber/version.rb +1 -1
- data/lib/parallel_cucumber/worker.rb +7 -25
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3c5786a5361ff67156526199fce9a686256fa49e33dc6c5af590c5f2ea17adce
|
4
|
+
data.tar.gz: 49d1792f94978bbfe9ea954e13dc9e0ebfe0742dad6aef966395e2885a462bdf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fc9332b43d59d80cedd19f8c2fd63cb231624e318a81a40fc378bd212e1dffb90aeb0ba7c359f6dae8cccec524d5f5828eb42d7f8e976a404ea5f7dba92ed283
|
7
|
+
data.tar.gz: 8f57b2ba36db0f161cfdf7db981411b365d8fc5d03b4369b388898c0e21b5e064331f4f91d154340a62075d16de4571e27ce406ee2eb84523a7156661dc45f77
|
@@ -8,7 +8,6 @@ module ParallelCucumber
|
|
8
8
|
batch_size: 1,
|
9
9
|
batch_timeout: 600,
|
10
10
|
setup_timeout: 30,
|
11
|
-
precheck_timeout: 30,
|
12
11
|
batch_error_timeout: 30,
|
13
12
|
cucumber_options: '',
|
14
13
|
debug: false,
|
@@ -90,10 +89,6 @@ module ParallelCucumber
|
|
90
89
|
options[:test_command] = test_command
|
91
90
|
end
|
92
91
|
|
93
|
-
opts.on('--pre-batch-check COMMAND', 'Command causing worker to quit on exit failure') do |pre_check|
|
94
|
-
options[:pre_check] = pre_check
|
95
|
-
end
|
96
|
-
|
97
92
|
opts.on('--log-dir DIR', 'Directory for worker logfiles') do |log_dir|
|
98
93
|
options[:log_dir] = log_dir
|
99
94
|
end
|
@@ -173,13 +168,6 @@ module ParallelCucumber
|
|
173
168
|
options[:batch_timeout] = batch_timeout
|
174
169
|
end
|
175
170
|
|
176
|
-
help_message = <<-TEXT.gsub(/\s+/, ' ').strip
|
177
|
-
Timeout for each test precheck. Default is #{DEFAULTS[:batch_timeout]}
|
178
|
-
TEXT
|
179
|
-
opts.on('--precheck-timeout SECONDS', Float, help_message) do |timeout|
|
180
|
-
options[:precheck_timeout] = timeout
|
181
|
-
end
|
182
|
-
|
183
171
|
help_message = <<-TEXT.gsub(/\s+/, ' ').strip
|
184
172
|
Timeout for each batch_error script. Default is #{DEFAULTS[:batch_error_timeout]}
|
185
173
|
TEXT
|
@@ -23,6 +23,10 @@ module ParallelCucumber
|
|
23
23
|
Hooks.register_after_batch(proc)
|
24
24
|
end
|
25
25
|
|
26
|
+
def worker_health_check(&proc)
|
27
|
+
Hooks.register_worker_health_check(proc)
|
28
|
+
end
|
29
|
+
|
26
30
|
def before_workers(&proc)
|
27
31
|
Hooks.register_before_workers(proc)
|
28
32
|
end
|
@@ -34,6 +38,10 @@ module ParallelCucumber
|
|
34
38
|
def on_batch_error(&proc)
|
35
39
|
Hooks.register_on_batch_error(proc)
|
36
40
|
end
|
41
|
+
|
42
|
+
def on_dry_run_error(&proc)
|
43
|
+
Hooks.register_on_dry_run_error(proc)
|
44
|
+
end
|
37
45
|
end
|
38
46
|
end
|
39
47
|
end
|
@@ -15,8 +15,13 @@ module ParallelCucumber
|
|
15
15
|
end
|
16
16
|
|
17
17
|
ONE_SECOND = 1
|
18
|
+
STACKTRACE_COLLECTION_TIMEOUT = 10
|
18
19
|
|
19
|
-
|
20
|
+
# rubocop:disable Metrics/ParameterLists, Metrics/LineLength
|
21
|
+
def exec_command(env, desc, script, logger, log_decoration = {},
|
22
|
+
timeout: 30, capture: false, return_script_error: false,
|
23
|
+
return_on_timeout: false, collect_stacktrace: false
|
24
|
+
)
|
20
25
|
block_name = ''
|
21
26
|
if log_decoration['worker_block']
|
22
27
|
if log_decoration['start'] || log_decoration['end']
|
@@ -28,42 +33,48 @@ module ParallelCucumber
|
|
28
33
|
full_script = "#{script} 2>&1"
|
29
34
|
env_string = env.map { |k, v| "#{k}=#{v}" }.sort.join(' ')
|
30
35
|
logger << "== Running command `#{full_script}` at #{Time.now}\n== with environment variables: #{env_string}\n"
|
31
|
-
|
36
|
+
wait_thread = nil
|
32
37
|
pout = nil
|
33
38
|
capture &&= [''] # Pass by reference
|
34
39
|
exception = nil
|
40
|
+
command_pid = nil
|
35
41
|
|
36
42
|
begin
|
37
43
|
completed = begin
|
38
|
-
pin, pout,
|
39
|
-
|
44
|
+
pin, pout, wait_thread = Open3.popen2e(env, full_script)
|
45
|
+
command_pid = wait_thread[:pid].to_s
|
46
|
+
logger << "Command has pid #{command_pid}\n"
|
40
47
|
pin.close
|
41
48
|
out_reader = Thread.new do
|
42
|
-
output_reader(pout,
|
49
|
+
output_reader(pout, wait_thread, logger, capture)
|
43
50
|
end
|
44
51
|
|
45
52
|
unless out_reader.join(timeout)
|
46
53
|
raise TimedOutError
|
47
54
|
end
|
48
55
|
|
49
|
-
graceful_process_shutdown(out_reader,
|
56
|
+
graceful_process_shutdown(out_reader, wait_thread, pout, logger)
|
50
57
|
|
51
|
-
|
52
|
-
"Command completed #{
|
58
|
+
wait_thread.value # reap already-terminated child.
|
59
|
+
"Command completed #{wait_thread.value} at #{Time.now}"
|
53
60
|
end
|
54
61
|
|
55
62
|
logger << "#{completed}\n"
|
56
63
|
|
57
|
-
raise "Script returned #{
|
64
|
+
raise "Script returned #{wait_thread.value.exitstatus}" unless wait_thread.value.success? || return_script_error
|
58
65
|
|
59
66
|
capture_or_empty = capture ? capture.first : '' # Even '' is truthy
|
60
|
-
return
|
67
|
+
return wait_thread.value.success? ? capture_or_empty : nil
|
61
68
|
rescue TimedOutError => e
|
62
|
-
|
69
|
+
process_tree = Helper::Processes.ps_tree
|
70
|
+
send_usr1_to_process_with_tree(command_pid, full_script, logger, process_tree) if collect_stacktrace
|
71
|
+
force_kill_process_with_tree(out_reader, wait_thread, pout, full_script, logger, timeout, process_tree, command_pid)
|
72
|
+
|
73
|
+
return capture.first if return_on_timeout
|
63
74
|
|
64
75
|
exception = e
|
65
76
|
rescue => e
|
66
|
-
logger.debug("Exception #{
|
77
|
+
logger.debug("Exception #{wait_thread ? wait_thread[:pid] : "wait_thread=#{wait_thread}=nil"}")
|
67
78
|
trace = e.backtrace.join("\n\t").sub("\n\t", ": #{$ERROR_INFO}#{e.class ? " (#{e.class})" : ''}\n\t")
|
68
79
|
logger.error("Threw for #{full_script}, caused #{trace}")
|
69
80
|
|
@@ -75,6 +86,7 @@ module ParallelCucumber
|
|
75
86
|
|
76
87
|
raise exception
|
77
88
|
end
|
89
|
+
# rubocop:enable Metrics/ParameterLists, Metrics/LineLength
|
78
90
|
|
79
91
|
def log_until_incomplete_line(logger, out_string)
|
80
92
|
loop do
|
@@ -87,13 +99,13 @@ module ParallelCucumber
|
|
87
99
|
|
88
100
|
private
|
89
101
|
|
90
|
-
def output_reader(pout,
|
102
|
+
def output_reader(pout, wait_thread, logger, capture)
|
91
103
|
out_string = ''
|
92
104
|
|
93
105
|
loop do
|
94
106
|
io_select = IO.select([pout], [], [], ONE_SECOND)
|
95
|
-
unless io_select ||
|
96
|
-
logger << "\n== Terminating because io_select=#{io_select} when
|
107
|
+
unless io_select || wait_thread.alive?
|
108
|
+
logger << "\n== Terminating because io_select=#{io_select} when wait_thread.alive?=#{wait_thread.alive?}\n"
|
97
109
|
break
|
98
110
|
end
|
99
111
|
next unless io_select
|
@@ -103,44 +115,45 @@ module ParallelCucumber
|
|
103
115
|
out_string = log_until_incomplete_line(logger, out_string + partial)
|
104
116
|
end
|
105
117
|
rescue EOFError
|
106
|
-
logger << "\n== EOF is normal exit, #{
|
118
|
+
logger << "\n== EOF is normal exit, #{wait_thread.inspect}\n"
|
107
119
|
rescue => e
|
108
120
|
logger << "\n== Exception in out_reader due to #{e.inspect} #{e.backtrace}\n"
|
109
121
|
ensure
|
110
122
|
logger << out_string
|
111
123
|
logger << ["\n== Left out_reader at #{Time.now}; ",
|
112
|
-
"pipe=#{
|
124
|
+
"pipe=#{wait_thread.status}+#{wait_thread.status ? '≤no value≥' : wait_thread.value}\n"].join
|
113
125
|
end
|
114
126
|
|
115
|
-
def graceful_process_shutdown(out_reader,
|
116
|
-
out_reader.value # Should terminate with
|
127
|
+
def graceful_process_shutdown(out_reader, wait_thread, pout, logger)
|
128
|
+
out_reader.value # Should terminate with wait_thread
|
117
129
|
pout.close
|
118
|
-
if
|
119
|
-
logger << "== Thread #{
|
130
|
+
if wait_thread.status
|
131
|
+
logger << "== Thread #{wait_thread.inspect} is not dead"
|
120
132
|
|
121
|
-
if
|
122
|
-
logger << "== Thread #{
|
133
|
+
if wait_thread.join(3)
|
134
|
+
logger << "== Thread #{wait_thread.inspect} joined late"
|
123
135
|
else
|
124
|
-
|
125
|
-
logger << "== Thread #{
|
136
|
+
wait_thread.terminate # Just in case
|
137
|
+
logger << "== Thread #{wait_thread.inspect} terminated"
|
126
138
|
end # Make an effort to reap
|
127
139
|
end
|
128
140
|
|
129
|
-
|
130
|
-
"Command completed #{
|
141
|
+
wait_thread.value # reap already-terminated child.
|
142
|
+
"Command completed #{wait_thread.value} at #{Time.now}"
|
131
143
|
end
|
132
144
|
|
133
|
-
def
|
145
|
+
def send_usr1_to_process_with_tree(command_pid, full_script, logger, tree)
|
146
|
+
return if Helper::Processes.ms_windows?
|
147
|
+
|
148
|
+
logger << "Timeout, so trying SIGUSR1 to trigger watchdog stacktrace #{command_pid}=#{full_script}"
|
149
|
+
Helper::Processes.kill_tree('SIGUSR1', command_pid, logger, tree)
|
150
|
+
sleep(STACKTRACE_COLLECTION_TIMEOUT) # Wait enough time for child processes to act on SIGUSR1
|
151
|
+
end
|
152
|
+
|
153
|
+
def force_kill_process_with_tree(out_reader, wait_thread, pout, full_script, logger, timeout, tree, pid) # rubocop:disable Metrics/ParameterLists, Metrics/LineLength
|
134
154
|
out_reader.exit
|
135
|
-
tree = Helper::Processes.ps_tree
|
136
|
-
pid = pstat[:pid].to_s
|
137
|
-
unless Helper::Processes.ms_windows?
|
138
|
-
logger << "Timeout, so trying SIGUSR1 to trigger watchdog stacktrace #{pstat[:pid]}=#{full_script}"
|
139
|
-
Helper::Processes.kill_tree('SIGUSR1', pid, logger, tree)
|
140
|
-
sleep 2
|
141
|
-
end
|
142
155
|
|
143
|
-
logger << "Timeout, so trying SIGINT at #{
|
156
|
+
logger << "Timeout, so trying SIGINT at #{wait_thread[:pid]}=#{full_script}"
|
144
157
|
|
145
158
|
log_copy = Thread.new do
|
146
159
|
pout.each_line { |l| logger << l }
|
@@ -167,7 +180,7 @@ module ParallelCucumber
|
|
167
180
|
end
|
168
181
|
|
169
182
|
logger << "About to reap root #{pid}"
|
170
|
-
|
183
|
+
wait_thread.value # reap root - everything else should be reaped by init.
|
171
184
|
logger << "Reaped root #{pid}"
|
172
185
|
end
|
173
186
|
end
|
@@ -47,6 +47,13 @@ module ParallelCucumber
|
|
47
47
|
report
|
48
48
|
end
|
49
49
|
|
50
|
+
def unknown_result(tests)
|
51
|
+
res = tests.map do |test|
|
52
|
+
[test.to_sym, {status: ::ParallelCucumber::Status::UNKNOWN}]
|
53
|
+
end
|
54
|
+
res.to_h
|
55
|
+
end
|
56
|
+
|
50
57
|
private
|
51
58
|
|
52
59
|
def dry_run_report(options, args_string)
|
@@ -20,6 +20,7 @@ module ParallelCucumber
|
|
20
20
|
details[:exception_classname] = event.result.exception.class.to_s
|
21
21
|
details[:exception_message] = event.result.exception.message
|
22
22
|
end
|
23
|
+
details[:name] = "#{event.test_case.feature}: #{event.test_case.name}"
|
23
24
|
details[:finish_time] = Time.now.to_i
|
24
25
|
@result[event.test_case.location.to_s] = details
|
25
26
|
end
|
@@ -35,7 +35,7 @@ module ParallelCucumber
|
|
35
35
|
else
|
36
36
|
descendants(root, logger, tree, old_tree, 'kill') do |pid, node|
|
37
37
|
begin
|
38
|
-
logger.warn "
|
38
|
+
logger.warn "Sending signal #{sig} to #{node}"
|
39
39
|
Process.kill(sig, pid.to_i)
|
40
40
|
rescue Errno::ESRCH
|
41
41
|
nil # It's gone already? Hurrah!
|
@@ -44,7 +44,7 @@ module ParallelCucumber
|
|
44
44
|
end
|
45
45
|
# Let's kill pid unconditionally: descendants will go astray once reparented.
|
46
46
|
begin
|
47
|
-
logger.warn "
|
47
|
+
logger.warn "Sending signal #{sig} to root process #{root} just in case"
|
48
48
|
Process.kill(sig, root.to_i)
|
49
49
|
rescue Errno::ESRCH
|
50
50
|
nil # It's gone already? Hurrah!
|
@@ -1,12 +1,19 @@
|
|
1
1
|
module ParallelCucumber
|
2
2
|
class Hooks
|
3
|
-
@
|
4
|
-
@
|
5
|
-
@
|
6
|
-
@
|
7
|
-
@
|
3
|
+
@worker_health_check ||= []
|
4
|
+
@before_batch_hooks ||= []
|
5
|
+
@after_batch_hooks ||= []
|
6
|
+
@before_workers ||= []
|
7
|
+
@after_workers ||= []
|
8
|
+
@on_batch_error ||= []
|
9
|
+
@on_dry_run_error ||= []
|
8
10
|
|
9
11
|
class << self
|
12
|
+
def register_worker_health_check(proc)
|
13
|
+
raise(ArgumentError, 'Please provide a valid callback') unless proc.respond_to?(:call)
|
14
|
+
@worker_health_check << proc
|
15
|
+
end
|
16
|
+
|
10
17
|
def register_before_batch(proc)
|
11
18
|
raise(ArgumentError, 'Please provide a valid callback') unless proc.respond_to?(:call)
|
12
19
|
@before_batch_hooks << proc
|
@@ -32,6 +39,17 @@ module ParallelCucumber
|
|
32
39
|
@on_batch_error << proc
|
33
40
|
end
|
34
41
|
|
42
|
+
def register_on_dry_run_error(proc)
|
43
|
+
raise(ArgumentError, 'Please provide a valid callback') unless proc.respond_to?(:call)
|
44
|
+
@on_dry_run_error << proc
|
45
|
+
end
|
46
|
+
|
47
|
+
def fire_worker_health_check(*args)
|
48
|
+
@worker_health_check.each do |hook|
|
49
|
+
hook.call(*args)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
35
53
|
def fire_before_batch_hooks(*args)
|
36
54
|
@before_batch_hooks.each do |hook|
|
37
55
|
hook.call(*args)
|
@@ -61,6 +79,12 @@ module ParallelCucumber
|
|
61
79
|
hook.call(*args)
|
62
80
|
end
|
63
81
|
end
|
82
|
+
|
83
|
+
def fire_on_dry_run_error(error)
|
84
|
+
@on_dry_run_error.each do |hook|
|
85
|
+
hook.call(error)
|
86
|
+
end
|
87
|
+
end
|
64
88
|
end
|
65
89
|
end
|
66
90
|
end
|
@@ -30,8 +30,12 @@ module ParallelCucumber
|
|
30
30
|
exit(1)
|
31
31
|
end
|
32
32
|
|
33
|
-
|
34
|
-
|
33
|
+
begin
|
34
|
+
all_tests = Helper::Cucumber.selected_tests(@options[:cucumber_options], @options[:cucumber_args])
|
35
|
+
rescue StandardError => error
|
36
|
+
Hooks.fire_on_dry_run_error(error)
|
37
|
+
raise error
|
38
|
+
end
|
35
39
|
if all_tests.empty?
|
36
40
|
@logger.info('There is no tests to run, exiting...')
|
37
41
|
exit(0)
|
@@ -10,11 +10,9 @@ module ParallelCucumber
|
|
10
10
|
@group_by = options[:group_by]
|
11
11
|
@batch_timeout = options[:batch_timeout]
|
12
12
|
@batch_error_timeout = options[:batch_error_timeout]
|
13
|
-
@precheck_timeout = options[:precheck_timeout]
|
14
13
|
@setup_timeout = options[:setup_timeout]
|
15
14
|
@cucumber_options = options[:cucumber_options]
|
16
15
|
@test_command = options[:test_command]
|
17
|
-
@pre_check = options[:pre_check]
|
18
16
|
@index = index
|
19
17
|
@name = "W#{@index}"
|
20
18
|
@setup_worker = options[:setup_worker]
|
@@ -99,12 +97,7 @@ module ParallelCucumber
|
|
99
97
|
job = @jobs_queue.pop(false)
|
100
98
|
case job.type
|
101
99
|
when Job::PRECHECK
|
102
|
-
|
103
|
-
if (m = precmd.match(/precmd:retry-after-(\d+)-seconds/))
|
104
|
-
@manager.inform_idle(@name)
|
105
|
-
sleep(1 + m[1].to_i)
|
106
|
-
next
|
107
|
-
end
|
100
|
+
Hooks.fire_worker_health_check(env)
|
108
101
|
@manager.inform_healthy(@name)
|
109
102
|
when Job::RUN_TESTS
|
110
103
|
run_batch(env, results, running_total, job.details)
|
@@ -161,18 +154,6 @@ module ParallelCucumber
|
|
161
154
|
@logger.update_into(@stdout_logger)
|
162
155
|
end
|
163
156
|
|
164
|
-
def precheck(env)
|
165
|
-
return 'default no-op pre_check' unless @pre_check
|
166
|
-
begin
|
167
|
-
return Helper::Command.exec_command(
|
168
|
-
env, 'precheck', @pre_check, @logger, @log_decoration, timeout: @precheck_timeout, capture: true
|
169
|
-
)
|
170
|
-
rescue
|
171
|
-
@logger.error('Pre-check failed: quitting immediately')
|
172
|
-
raise 'Pre-check failed: quitting immediately'
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
157
|
def running_totals(batch_results, running_total)
|
177
158
|
batch_info = Status.constants.map do |status|
|
178
159
|
status = Status.const_get(status)
|
@@ -220,7 +201,8 @@ module ParallelCucumber
|
|
220
201
|
begin
|
221
202
|
ParallelCucumber::Helper::Command.exec_command(
|
222
203
|
batch_env, 'batch', mapped_batch_cmd, @logger, @log_decoration,
|
223
|
-
timeout: @batch_timeout, return_script_error: true
|
204
|
+
timeout: @batch_timeout, capture: true, return_script_error: true,
|
205
|
+
return_on_timeout: true, collect_stacktrace: true
|
224
206
|
)
|
225
207
|
rescue => e
|
226
208
|
@logger << "ERROR #{e} #{e.backtrace.first(5)}"
|
@@ -232,7 +214,7 @@ module ParallelCucumber
|
|
232
214
|
@logger.warn("There was exception in on_batch_error hook #{exc.message} \n #{trace}")
|
233
215
|
end
|
234
216
|
|
235
|
-
return
|
217
|
+
return Helper::Cucumber.unknown_result(tests)
|
236
218
|
end
|
237
219
|
parse_results(test_state, tests)
|
238
220
|
ensure
|
@@ -291,18 +273,18 @@ module ParallelCucumber
|
|
291
273
|
def parse_results(f, tests)
|
292
274
|
unless File.file?(f)
|
293
275
|
@logger.error("Results file does not exist: #{f}")
|
294
|
-
return
|
276
|
+
return Helper::Cucumber.unknown_result(tests)
|
295
277
|
end
|
296
278
|
json_report = File.read(f)
|
297
279
|
if json_report.empty?
|
298
280
|
@logger.error("Results file is empty: #{f}")
|
299
|
-
return
|
281
|
+
return Helper::Cucumber.unknown_result(tests)
|
300
282
|
end
|
301
283
|
Helper::Cucumber.parse_json_report(json_report)
|
302
284
|
rescue => e
|
303
285
|
trace = e.backtrace.join("\n\t").sub("\n\t", ": #{$ERROR_INFO}#{e.class ? " (#{e.class})" : ''}\n\t")
|
304
286
|
@logger.error("Threw: JSON parse of results caused #{trace}")
|
305
|
-
|
287
|
+
Helper::Cucumber.unknown_result(tests)
|
306
288
|
end
|
307
289
|
end
|
308
290
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parallel_cucumber
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.24
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Bayandin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-07-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cucumber
|
@@ -72,14 +72,14 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - '='
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 0.
|
75
|
+
version: 0.73.0
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - '='
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 0.
|
82
|
+
version: 0.73.0
|
83
83
|
description: Our own parallel cucumber with queue and workers
|
84
84
|
email: a.bayandin@gmail.com
|
85
85
|
executables:
|
@@ -127,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
127
|
- !ruby/object:Gem::Version
|
128
128
|
version: '0'
|
129
129
|
requirements: []
|
130
|
-
rubygems_version: 3.0.
|
130
|
+
rubygems_version: 3.0.3
|
131
131
|
signing_key:
|
132
132
|
specification_version: 4
|
133
133
|
summary: Run cucumber in parallel
|