capistrano_multiconfig_parallel 0.18.1 → 0.18.2

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
  SHA1:
3
- metadata.gz: 90467fb1e95571ff800390c44e68f08d7d4b9b2f
4
- data.tar.gz: a9fa1498b21325d91a363c0b15c92e9b33ad3aac
3
+ metadata.gz: 636e8807495e7cc5082a737fddaf6de9eb132d50
4
+ data.tar.gz: 77409e0a2196ce97e32fc12f9d9feffd54972bda
5
5
  SHA512:
6
- metadata.gz: 735c86753f6a6af76c9c339e5b5c14e8b655eb92216daafeba8034930e87d7ece4b9bcbb38f7ddc168ab6dc44d6ee0cb014fdda9551759edc9fbdde26f506d86
7
- data.tar.gz: 7bfd74cfa40521cb0a8bf8508624e54d9fa2f0a005f9a36470492e7f2f49f9e25f1e9f91215dc3d52008b79c480e9892576641999a14a2c921c39e76a03401c6
6
+ metadata.gz: 524ffa981d6cfc38698300d0334ec049a384002ed9b0b31eed239ca4d02047fce155a3211e53a720d533e2b911aa320fea0e789d934dd7728fb1c239c54d2f4c
7
+ data.tar.gz: d8b40b726fb03873c14d720604bbd99ee74e676d177b1778ab2cfa791d1645b86f473abd701d124f56779414ededec03c5dce0da0af7c81cb9cd61485752920f
data/.reek ADDED
@@ -0,0 +1,3 @@
1
+ ---
2
+ Attribute:
3
+ enabled: false
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- capistrano_multiconfig_parallel (0.17.0)
4
+ capistrano_multiconfig_parallel (0.18.1)
5
5
  activesupport (~> 4.0, >= 4.0)
6
6
  capistrano (~> 3.0, >= 3.0)
7
7
  celluloid-pmap (~> 0.2, >= 0.2.2)
@@ -4,7 +4,6 @@ module CapistranoMulticonfigParallel
4
4
  class Application
5
5
  include Celluloid
6
6
  include Celluloid::Logger
7
- include CapistranoMulticonfigParallel::StagesHelper
8
7
  include CapistranoMulticonfigParallel::ApplicationHelper
9
8
 
10
9
  attr_reader :stages, :stage_apps, :top_level_tasks, :jobs, :branch_backup, :condition, :manager, :dependency_tracker, :application, :stage, :name, :args, :argv, :default_stage
@@ -106,13 +105,11 @@ module CapistranoMulticonfigParallel
106
105
  backup_the_branch if multi_apps?
107
106
  deploy_multiple_apps(apps, options)
108
107
  deploy_app(options) if !custom_command? || !multi_apps?
109
- rescue => e
110
- log_error(e)
111
108
  end
112
109
 
113
110
  def process_jobs
114
111
  return unless @jobs.present?
115
- FileUtils.rm Dir["#{CapistranoMulticonfigParallel.log_directory}/worker_*.log"]
112
+ FileUtils.rm Dir["#{log_directory}/worker_*.log"]
116
113
  if app_configuration.multi_secvential.to_s.downcase == 'true'
117
114
  @jobs.each { |job| CapistranoMulticonfigParallel::StandardDeploy.new(job) }
118
115
  else
@@ -11,38 +11,22 @@ module CapistranoMulticonfigParallel
11
11
 
12
12
  def enable_logging
13
13
  enable_file_logging
14
- Celluloid.logger = logger
15
- Celluloid.task_class = Celluloid::TaskThread
16
- end
17
-
18
- def detect_root
19
- if find_env_multi_cap_root
20
- Pathname.new(find_env_multi_cap_root)
21
- elsif defined?(::Rails)
22
- ::Rails.root
23
- else
24
- try_detect_capfile
25
- end
26
- end
27
-
28
- def config_file
29
- File.join(detect_root.to_s, 'config', 'multi_cap.yml')
30
- end
31
-
32
- def log_directory
33
- File.join(detect_root.to_s, 'log')
14
+ set_celluloid_exception_handling
34
15
  end
35
16
 
36
- def main_log_file
37
- File.join(log_directory, 'multi_cap.log')
38
- end
17
+ private
39
18
 
40
- def custom_commands
41
- ['deploy_multi_stages']
19
+ def set_celluloid_exception_handling
20
+ Celluloid.logger = logger
21
+ Celluloid.task_class = Celluloid::TaskThread
22
+ Celluloid.exception_handler do |ex|
23
+ unless ex.is_a?(Interrupt)
24
+ puts format_error(ex)
25
+ log_error(ex)
26
+ end
27
+ end
42
28
  end
43
29
 
44
- private
45
-
46
30
  def enable_file_logging
47
31
  if configuration.multi_debug.to_s.downcase == 'true'
48
32
  enable_main_log_file
@@ -51,12 +35,5 @@ module CapistranoMulticonfigParallel
51
35
  self.logger ||= ::Logger.new(DevNull.new)
52
36
  end
53
37
  end
54
-
55
- def enable_main_log_file
56
- FileUtils.mkdir_p(log_directory) unless File.directory?(log_directory)
57
- FileUtils.touch(main_log_file) unless File.file?(main_log_file)
58
- log_file = File.open(main_log_file, 'w')
59
- log_file.sync = true
60
- end
61
38
  end
62
39
  end
@@ -37,8 +37,6 @@ module CapistranoMulticonfigParallel
37
37
  @worker_supervisor.supervise_as(:web_server, CapistranoMulticonfigParallel::WebServer, websocket_config)
38
38
  end
39
39
 
40
-
41
-
42
40
  def generate_job_id(job)
43
41
  @jobs[job['id']] = job
44
42
  job['id']
@@ -168,12 +166,13 @@ module CapistranoMulticonfigParallel
168
166
  until apps_symlink_confirmation.present?
169
167
  sleep(0.1) # keep current thread alive
170
168
  end
169
+ apps_symlink_confirmation
171
170
  end
172
171
 
173
172
  def confirm_task_approval(result, task, worker = nil)
174
173
  return unless result.present?
175
- print_confirm_task_approvall(result, task, worker = nil)
176
- return if fetch(:apps_symlink_confirmation).blank? || fetch(:apps_symlink_confirmation).downcase != 'y'
174
+ result = print_confirm_task_approvall(result, task, worker = nil)
175
+ return if result.blank? || result.downcase != 'y'
177
176
  @jobs.pmap do |job_id, job|
178
177
  worker = get_worker_for_job(job_id)
179
178
  worker.publish_rake_event('approved' => 'yes',
@@ -194,8 +193,8 @@ module CapistranoMulticonfigParallel
194
193
  end
195
194
  else
196
195
  return nil
197
- end
198
196
  end
197
+ end
199
198
 
200
199
  def can_tag_staging?
201
200
  @job_manager.can_tag_staging? &&
@@ -78,7 +78,7 @@ module CapistranoMulticonfigParallel
78
78
  end
79
79
 
80
80
  def cd_working_directory
81
- "cd #{CapistranoMulticonfigParallel.detect_root}"
81
+ "cd #{detect_root}"
82
82
  end
83
83
 
84
84
  # def generate_command_new
@@ -169,7 +169,7 @@ module CapistranoMulticonfigParallel
169
169
  log_to_file("worker #{@job_id} triest to transition from #{@machine.state} to #{name}")
170
170
  @machine.transitions.on(name.to_s, @machine.state => name.to_s)
171
171
  @machine.go_to_transition(name.to_s)
172
- raise(CapistranoMulticonfigParallel::CelluloidWorker::TaskFailed, "task #{@action} failed ") if name == 'deploy:failed' # force worker to rollback
172
+ abort(CapistranoMulticonfigParallel::CelluloidWorker::TaskFailed, "task #{@action} failed ") if name == 'deploy:failed' # force worker to rollback
173
173
  end
174
174
 
175
175
  def setup_command_line(*options)
@@ -235,7 +235,7 @@ module CapistranoMulticonfigParallel
235
235
  def notify_finished(exit_status)
236
236
  if exit_status.exitstatus != 0
237
237
  log_to_file("worker #{job_id} tries to terminate")
238
- raise(CapistranoMulticonfigParallel::CelluloidWorker::TaskFailed, "task failed with exit status #{exit_status.inspect} ") # force worker to rollback
238
+ abort(CapistranoMulticonfigParallel::CelluloidWorker::TaskFailed, "task failed with exit status #{exit_status.inspect} ") # force worker to rollback
239
239
  else
240
240
  update_machine_state('FINISHED')
241
241
  log_to_file("worker #{job_id} notifies manager has finished")
@@ -2,35 +2,33 @@ module CapistranoMulticonfigParallel
2
2
  # class that handles the states of the celluloid worker executing the child process in a fork process
3
3
  class StateMachine
4
4
  include ComposableStateMachine::CallbackRunner
5
- attr_accessor :state, :model, :machine, :job, :initial_state, :transitions, :output
5
+ attr_accessor :job, :actor, :initial_state, :state, :output
6
6
 
7
7
  def initialize(job, actor)
8
8
  @job = job
9
9
  @actor = actor
10
10
  @initial_state = :unstarted
11
- @model = generate_model
12
- build_machine
11
+ machine
13
12
  end
14
13
 
15
14
  def go_to_transition(action)
16
- @machine.trigger(action.to_s)
15
+ machine.trigger(action.to_s)
17
16
  end
18
17
 
19
- private
20
-
21
- def build_machine
22
- @machine = ComposableStateMachine::MachineWithExternalState.new(
23
- @model, method(:state), method(:state=), state: initial_state.to_s, callback_runner: self)
18
+ def machine
19
+ @machine ||= ComposableStateMachine::MachineWithExternalState.new(
20
+ model, method(:state), method(:state=), state: @initial_state.to_s, callback_runner: self)
21
+ @machine
24
22
  end
25
23
 
26
- def generate_transitions
27
- @transitions = ComposableStateMachine::Transitions.new
24
+ def transitions
25
+ @transitions ||= ComposableStateMachine::Transitions.new
28
26
  @transitions
29
27
  end
30
28
 
31
- def generate_model
29
+ def model
32
30
  ComposableStateMachine.model(
33
- transitions: generate_transitions,
31
+ transitions: transitions,
34
32
  behaviors: {
35
33
  enter: {
36
34
  any: proc do |current_state, event, new_state|
@@ -42,6 +40,8 @@ module CapistranoMulticonfigParallel
42
40
  )
43
41
  end
44
42
 
43
+ private
44
+
45
45
  def actor_notify_state_change(current_state, event, new_state)
46
46
  @actor.send_msg(CapistranoMulticonfigParallel::TerminalTable.topic, type: 'event', message: "Going from #{current_state} to #{new_state} due to a #{event} event")
47
47
  end
@@ -24,10 +24,8 @@ module CapistranoMulticonfigParallel
24
24
  def notify_time_change(topic, message)
25
25
  return unless topic == CapistranoMulticonfigParallel::TerminalTable.topic
26
26
  default_headings = ['Job ID', 'Job UUID', 'App/Stage', 'Action', 'ENV Variables', 'Current Task']
27
- # if CapistranoMulticonfigParallel.show_task_progress
28
27
  # default_headings << 'Total'
29
28
  # default_headings << 'Progress'
30
- # end
31
29
  table = Terminal::Table.new(title: 'Deployment Status Table', headings: default_headings)
32
30
  if @manager.jobs.present? && message_valid?(message)
33
31
  count = 0
@@ -116,7 +114,7 @@ module CapistranoMulticonfigParallel
116
114
  { value: details['env_options'] },
117
115
  { value: "#{details['state']}" }
118
116
  ]
119
- # if CapistranoMulticonfigParallel.show_task_progress
117
+
120
118
  # if worker.alive?
121
119
  # row << { value: worker.rake_tasks.size }
122
120
  # row << { value: worker_progress(details, worker) }
@@ -124,7 +122,6 @@ module CapistranoMulticonfigParallel
124
122
  # row << { value: 0 }
125
123
  # row << { value: worker_state(worker) }
126
124
  # end
127
- # end
128
125
  table.add_row(row)
129
126
  table.add_separator if @manager.jobs.keys.last.to_i != job_id.to_i
130
127
  end
@@ -14,7 +14,6 @@ module CapistranoMulticonfigParallel
14
14
  if job_id.present?
15
15
  actor_start_working
16
16
  actor.wait_execution until actor.task_approved
17
- return unless actor.task_approved
18
17
  actor_execute_block(&block)
19
18
  else
20
19
  block.call
@@ -31,15 +30,23 @@ module CapistranoMulticonfigParallel
31
30
  CapistranoMulticonfigParallel::InputStream
32
31
  end
33
32
 
34
- def actor_execute_block(&block)
33
+ def before_hooks
35
34
  stringio = StringIO.new
36
35
  output_stream.hook(stringio)
37
36
  input_stream.hook(actor, stringio)
38
- block.call
37
+ end
38
+
39
+ def after_hooks
39
40
  input_stream.unhook
40
41
  output_stream.unhook
41
42
  end
42
43
 
44
+ def actor_execute_block(&block)
45
+ before_hooks
46
+ block.call
47
+ after_hooks
48
+ end
49
+
43
50
  def actor_start_working
44
51
  if actor.blank?
45
52
  supervise_actor
@@ -8,23 +8,15 @@ module CapistranoMulticonfigParallel
8
8
 
9
9
  # method used to start
10
10
  def start
11
- verify_validation
12
- start_work
13
- rescue Interrupt
14
- rescue_interrupt
15
- rescue => error
16
- rescue_error(error)
17
- end
18
-
19
- def rescue_interrupt
20
- `stty icanon echo`
21
- $stderr.puts 'Command cancelled.'
22
- end
23
-
24
- def rescue_error(error)
25
- $stderr.puts error
26
- $stderr.puts error.backtrace if error.respond_to?(:backtrace)
27
- exit(1)
11
+ execute_with_rescue('stderr') do
12
+ verify_validation
13
+ job_manager = CapistranoMulticonfigParallel::Application.new
14
+ if job_manager.argv[CapistranoMulticonfigParallel::ENV_KEY_JOB_ID].blank?
15
+ job_manager.start
16
+ else
17
+ Capistrano::Application.new.run
18
+ end
19
+ end
28
20
  end
29
21
 
30
22
  def verify_validation
@@ -32,15 +24,6 @@ module CapistranoMulticonfigParallel
32
24
  CapistranoMulticonfigParallel.original_args = ARGV.dup
33
25
  CapistranoMulticonfigParallel.configuration_valid?
34
26
  end
35
-
36
- def start_work
37
- job_manager = CapistranoMulticonfigParallel::Application.new
38
- if job_manager.argv[CapistranoMulticonfigParallel::ENV_KEY_JOB_ID].blank?
39
- job_manager.start
40
- else
41
- Capistrano::Application.new.run
42
- end
43
- end
44
27
  end
45
28
  end
46
29
  end
@@ -1,8 +1,12 @@
1
1
  require_relative './core_helper'
2
+ require_relative './internal_helper'
3
+ require_relative './stages_helper'
2
4
  module CapistranoMulticonfigParallel
3
5
  # class that holds the options that are configurable for this gem
4
6
  module ApplicationHelper
7
+ include CapistranoMulticonfigParallel::InternalHelper
5
8
  include CapistranoMulticonfigParallel::CoreHelper
9
+ include CapistranoMulticonfigParallel::StagesHelper
6
10
 
7
11
  module_function
8
12
 
@@ -3,39 +3,10 @@ module CapistranoMulticonfigParallel
3
3
  module CoreHelper
4
4
  module_function
5
5
 
6
- def internal_config_directory
7
- File.join(root.to_s, 'capistrano_multiconfig_parallel', 'configuration')
8
- end
9
-
10
- def internal_config_file
11
- File.join(internal_config_directory, 'default.yml')
12
- end
13
-
14
- def default_internal_config
15
- @default_config ||= YAML.load_file(internal_config_file)['default_config']
16
- @default_config
17
- end
18
-
19
- def find_env_multi_cap_root
20
- ENV['MULTI_CAP_ROOT']
21
- end
22
-
23
- def root
24
- File.expand_path(File.dirname(File.dirname(__dir__)))
25
- end
26
-
27
6
  def find_config_type(type)
28
7
  ['boolean'].include?(type.to_s) ? type.to_s.delete(':').to_sym : type.to_s.constantize
29
8
  end
30
9
 
31
- def try_detect_capfile
32
- root = Pathname.new(FileUtils.pwd)
33
- root = root.parent unless root.directory?
34
- root = root.parent until root.children.find { |f| f.file? && f.basename.to_s.downcase == 'capfile' }.present? || root.root?
35
- fail "Can't detect Capfile in the application root".red if root.root?
36
- root
37
- end
38
-
39
10
  def app_debug_enabled?
40
11
  app_configuration.multi_debug.to_s.downcase == 'true'
41
12
  end
@@ -48,10 +19,6 @@ module CapistranoMulticonfigParallel
48
19
  CapistranoMulticonfigParallel.configuration
49
20
  end
50
21
 
51
- def custom_commands
52
- CapistranoMulticonfigParallel.custom_commands
53
- end
54
-
55
22
  def app_logger
56
23
  CapistranoMulticonfigParallel.logger
57
24
  end
@@ -66,22 +33,30 @@ module CapistranoMulticonfigParallel
66
33
  end
67
34
 
68
35
  def ask_confirm(message, default)
36
+ force_confirmation do
37
+ Ask.input message, default: default
38
+ end
39
+ rescue
40
+ return nil
41
+ end
42
+
43
+ def force_confirmation(&block)
69
44
  `stty -raw echo`
70
45
  check_terminal_tty
71
- result = Ask.input message, default: default
46
+ result = block.call
72
47
  $stdout.flush
73
48
  `stty -raw echo`
74
- return result
75
- rescue
76
- return nil
49
+ result
50
+ end
51
+
52
+ def log_error(error)
53
+ log_to_file(format_error(error))
77
54
  end
78
55
 
79
- def log_error(message)
80
- log_to_file(
81
- class_name: message.class,
82
- message: message.respond_to?(:message) ? message.message : message.inspect,
83
- backtrace: message.respond_to?(:backtrace) ? message.backtrace.join("\n\n") : ''
84
- )
56
+ def format_error(error)
57
+ JSON.pretty_generate(class_name: error.class,
58
+ message: error.respond_to?(:message) ? error.message : error.inspect,
59
+ backtrace: error.respond_to?(:backtrace) ? error.backtrace.join("\n\n") : '')
85
60
  end
86
61
 
87
62
  def log_to_file(message, job_id = nil)
@@ -91,8 +66,8 @@ module CapistranoMulticonfigParallel
91
66
 
92
67
  def find_worker_log(job_id)
93
68
  return if job_id.blank?
94
- FileUtils.mkdir_p(CapistranoMulticonfigParallel.log_directory) unless File.directory?(CapistranoMulticonfigParallel.log_directory)
95
- filename = File.join(CapistranoMulticonfigParallel.log_directory, "worker_#{job_id}.log")
69
+ FileUtils.mkdir_p(log_directory) unless File.directory?(log_directory)
70
+ filename = File.join(log_directory, "worker_#{job_id}.log")
96
71
  worker_log = ::Logger.new(filename)
97
72
  worker_log.level = ::Logger::Severity::DEBUG
98
73
  worker_log.formatter = proc do |severity, datetime, progname, msg|
@@ -103,15 +78,33 @@ module CapistranoMulticonfigParallel
103
78
  end
104
79
 
105
80
  def debug_websocket?
106
- websocket_config['enable_debug'].to_s == 'true'
81
+ websocket_server_config['enable_debug'].to_s == 'true'
82
+ end
83
+
84
+ def websocket_server_config
85
+ app_configuration.fetch(:websocket_server, {}).stringify_keys
107
86
  end
108
87
 
109
88
  def websocket_config
110
- config = app_configuration[:websocket_server]
111
- config.present? && config.is_a?(Hash) ? config.stringify_keys : {}
112
- config['enable_debug'] = config.fetch('enable_debug', '').to_s == 'true'
113
- config
89
+ websocket_server_config.merge('enable_debug' => debug_websocket?)
90
+ end
91
+
92
+ def execute_with_rescue(output = nil)
93
+ yield if block_given?
94
+ rescue Interrupt
95
+ rescue_interrupt
96
+ rescue => error
97
+ rescue_error(error, output)
114
98
  end
115
99
 
100
+ def rescue_error(error, output = nil)
101
+ output.blank? ? log_error(error) : puts(format_error(error))
102
+ exit(1)
103
+ end
104
+
105
+ def rescue_interrupt
106
+ `stty icanon echo`
107
+ puts "\n Command was cancelled due to an Interrupt error."
108
+ end
116
109
  end
117
110
  end
@@ -0,0 +1,68 @@
1
+ module CapistranoMulticonfigParallel
2
+ # internal helpers for logging mostly
3
+ module InternalHelper
4
+ module_function
5
+
6
+ def internal_config_directory
7
+ File.join(root.to_s, 'capistrano_multiconfig_parallel', 'configuration')
8
+ end
9
+
10
+ def internal_config_file
11
+ File.join(internal_config_directory, 'default.yml')
12
+ end
13
+
14
+ def default_internal_config
15
+ @default_config ||= YAML.load_file(internal_config_file)['default_config']
16
+ @default_config
17
+ end
18
+
19
+ def find_env_multi_cap_root
20
+ ENV['MULTI_CAP_ROOT']
21
+ end
22
+
23
+ def root
24
+ File.expand_path(File.dirname(File.dirname(__dir__)))
25
+ end
26
+
27
+ def try_detect_capfile
28
+ root = Pathname.new(FileUtils.pwd)
29
+ root = root.parent unless root.directory?
30
+ root = root.parent until root.children.find { |f| f.file? && f.basename.to_s.downcase == 'capfile' }.present? || root.root?
31
+ fail "Can't detect Capfile in the application root".red if root.root?
32
+ root
33
+ end
34
+
35
+ def detect_root
36
+ if find_env_multi_cap_root
37
+ Pathname.new(find_env_multi_cap_root)
38
+ elsif defined?(::Rails)
39
+ ::Rails.root
40
+ else
41
+ try_detect_capfile
42
+ end
43
+ end
44
+
45
+ def config_file
46
+ File.join(detect_root.to_s, 'config', 'multi_cap.yml')
47
+ end
48
+
49
+ def log_directory
50
+ File.join(detect_root.to_s, 'log')
51
+ end
52
+
53
+ def main_log_file
54
+ File.join(log_directory, 'multi_cap.log')
55
+ end
56
+
57
+ def custom_commands
58
+ ['deploy_multi_stages']
59
+ end
60
+
61
+ def enable_main_log_file
62
+ FileUtils.mkdir_p(log_directory) unless File.directory?(log_directory)
63
+ FileUtils.touch(main_log_file) unless File.file?(main_log_file)
64
+ log_file = File.open(main_log_file, 'w')
65
+ log_file.sync = true
66
+ end
67
+ end
68
+ end
@@ -8,7 +8,7 @@ module CapistranoMulticonfigParallel
8
8
  module VERSION
9
9
  MAJOR = 0
10
10
  MINOR = 18
11
- TINY = 1
11
+ TINY = 2
12
12
  PRE = nil
13
13
 
14
14
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano_multiconfig_parallel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.1
4
+ version: 0.18.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - bogdanRada
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-03 00:00:00.000000000 Z
11
+ date: 2015-12-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: celluloid-pmap
@@ -602,6 +602,7 @@ files:
602
602
  - ".codeclimate.yml"
603
603
  - ".coveralls.yml"
604
604
  - ".gitignore"
605
+ - ".reek"
605
606
  - ".rspec"
606
607
  - ".rubocop.yml"
607
608
  - ".travis.yml"
@@ -639,6 +640,7 @@ files:
639
640
  - lib/capistrano_multiconfig_parallel/helpers/application_helper.rb
640
641
  - lib/capistrano_multiconfig_parallel/helpers/configuration.rb
641
642
  - lib/capistrano_multiconfig_parallel/helpers/core_helper.rb
643
+ - lib/capistrano_multiconfig_parallel/helpers/internal_helper.rb
642
644
  - lib/capistrano_multiconfig_parallel/helpers/stages_helper.rb
643
645
  - lib/capistrano_multiconfig_parallel/initializers/rake.rb
644
646
  - lib/capistrano_multiconfig_parallel/version.rb