capistrano_multiconfig_parallel 0.2.1 → 0.4.0

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: 5b9578694025dca215377cd4d9d78dea9a0bad48
4
- data.tar.gz: 0de2d1f4b3c3ad520620769ac2e2baf3c2b88e67
3
+ metadata.gz: 807e40ee77401d31f5ca168c79daa993f0742d2e
4
+ data.tar.gz: f0fcf399fd6dde6a96fdc40ae10fa6c6e593bd5d
5
5
  SHA512:
6
- metadata.gz: 2c123c22fc754c732ec4d64be8477f264e2deb67080b638848a23253453aa3e0270281c6867516d618ed427bf86c245e3811b7dc300c692afe1a94f9493dac50
7
- data.tar.gz: 5e8cd281aed6385d4bb2e072767572206a6c1b824bb8a0b4ce0cef170e50e7f6ab9aad40036d17f31fc0a609b3defedd34abb80310d896081a9e6ed322bcfcf3
6
+ metadata.gz: 5e4d5b0d0e9869d781067480e025b25ac187c67a196247fd8f07c2691adb8f968425c297f4b3d5d788068b01b226a7668a32af096cab4b0cdadedf0dfbf2cb94
7
+ data.tar.gz: 1ce688cb8219b2bb26ade54ca01af7a198497ed9932ba03242a9c385f951bdc681417b42da32fbb298d613ffd6955020ff4cf29dbf448e1f2cc8906e5df399d0
data/README.md CHANGED
@@ -98,7 +98,8 @@ websocket_server:
98
98
  development_stages:
99
99
  - development
100
100
  - webdev
101
-
101
+
102
+ syncronize_confirmation: true
102
103
  task_confirmation_active: false
103
104
  task_confirmations:
104
105
  - deploy:symlink:release
@@ -128,6 +129,9 @@ application_dependencies: []
128
129
  * --development_stages
129
130
  * if option is present and has value an ARRAY of STRINGS, each of them will be used as a development stage
130
131
 
132
+ * --syncronize_confirmation
133
+ * if option is present and has value TRUE, all workers will be synchronized to wait for same task from the ***task_confirmations** Array before they execute it
134
+
131
135
  * --task_confirmation_active
132
136
  * if option is present and has value TRUE, will enable user confirmation dialogs before executing each task from option **--task_confirmations**
133
137
 
@@ -23,7 +23,7 @@ module CapistranoMulticonfigParallel
23
23
  }
24
24
 
25
25
  class << self
26
- attr_accessor :show_task_progress, :interactive_menu, :execute_in_sequence, :logger, :show_task_progress_tree
26
+ attr_accessor :show_task_progress, :execute_in_sequence, :logger, :original_args
27
27
 
28
28
  def root
29
29
  File.expand_path(File.dirname(__dir__))
@@ -33,14 +33,6 @@ module CapistranoMulticonfigParallel
33
33
  Ask.input message, default: default
34
34
  end
35
35
 
36
- def verify_app_dependencies(stages)
37
- applications = stages.map { |stage| stage.split(':').reverse[1] }
38
- wrong = CapistranoMulticonfigParallel.configuration.application_dependencies.find do |hash|
39
- !applications.include?(hash[:app]) || (hash[:dependencies].present? && hash[:dependencies].find { |val| !applications.include?(val) })
40
- end
41
- raise ArgumentError, "invalid configuration for #{wrong.inspect}" if wrong.present?
42
- end
43
-
44
36
  def log_directory
45
37
  File.join(CapistranoMulticonfigParallel.detect_root.to_s, 'log')
46
38
  end
@@ -56,14 +48,13 @@ module CapistranoMulticonfigParallel
56
48
  def enable_logging
57
49
  CapistranoMulticonfigParallel.configuration_valid?
58
50
  return unless CapistranoMulticonfigParallel::CelluloidManager.debug_enabled
59
- FileUtils.mkdir_p(log_directory) unless File.directory?(log_directory)
51
+ FileUtils.mkdir_p(log_directory) unless File.directory?(log_directory)
60
52
  FileUtils.touch(main_log_file) unless File.file?(main_log_file)
61
- if ENV[CapistranoMulticonfigParallel::ENV_KEY_JOB_ID].blank?
53
+ if ENV[CapistranoMulticonfigParallel::ENV_KEY_JOB_ID].blank?
62
54
  log_file = File.open(main_log_file, 'w')
63
55
  log_file.sync = true
64
56
  end
65
57
  self.logger = ::Logger.new(main_log_file)
66
- Celluloid.logger = logger
67
58
  end
68
59
 
69
60
  def log_message(message)
@@ -90,11 +81,11 @@ module CapistranoMulticonfigParallel
90
81
  try_detect_capfile
91
82
  end
92
83
  end
93
-
84
+
94
85
  def try_detect_capfile
95
86
  root = Pathname.new(FileUtils.pwd)
96
87
  root = root.parent unless root.directory?
97
- root = root.parent until root.children.find{|f| f.file? && f.basename.to_s.downcase == "capfile"}.present? || root.root?
88
+ root = root.parent until root.children.find { |f| f.file? && f.basename.to_s.downcase == 'capfile' }.present? || root.root?
98
89
  raise "Can't detect Rails application root" if root.root?
99
90
  root
100
91
  end
@@ -24,6 +24,7 @@ module CapistranoMulticonfigParallel
24
24
  @mutex = Mutex.new
25
25
  # http://rubydoc.info/gems/celluloid/Celluloid/SupervisionGroup/Member
26
26
  @workers = @worker_supervisor.pool(CapistranoMulticonfigParallel::CelluloidWorker, as: :workers, size: 10)
27
+ Actor.current.link @workers
27
28
  # Get a handle on the PoolManager
28
29
  # http://rubydoc.info/gems/celluloid/Celluloid/PoolManager
29
30
  # @workers = workers_pool.actor
@@ -83,59 +84,76 @@ module CapistranoMulticonfigParallel
83
84
  @worker_to_job[worker.mailbox.address] = job
84
85
  debug("worker #{worker.job_id} registed into manager") if self.class.debug_enabled?
85
86
  Actor.current.link worker
87
+ worker.async.start_task unless syncronized_confirmation?
86
88
  if @job_manager.jobs.size == @job_to_worker.size
87
89
  @registration_complete = true
88
90
  end
89
91
  end
90
92
  end
91
93
 
92
- def process_jobs(&block)
93
- @job_to_worker.pmap do |job_id, worker|
94
- setup_worker_conditions(job_id)
95
- worker.async.start_task
94
+ def process_jobs
95
+ if syncronized_confirmation?
96
+ @job_to_worker.pmap do |_job_id, worker|
97
+ worker.async.start_task
98
+ end
99
+ wait_task_confirmations
96
100
  end
97
- block_given? ? block.call : wait_task_confirmations
98
- until @job_to_worker.all?{|job_id, worker| worker.alive? && worker.worker_state =='finished'}
101
+ condition = @job_to_worker.all? { |_job_id, worker| worker.alive? && worker.worker_state == 'finished' }
102
+ until condition == true
99
103
  sleep(0.1) # keep current thread alive
100
104
  end
101
- mark_completed_remaining_tasks
102
- @job_manager.condition.signal("completed")
105
+ debug("all jobs have completed #{condition}") if self.class.debug_enabled?
106
+ @job_manager.condition.signal('completed') if condition
103
107
  end
104
-
105
- def setup_worker_conditions(job_id)
108
+
109
+ def syncronized_confirmation?
110
+ CapistranoMulticonfigParallel.configuration.syncronize_confirmation.to_s.downcase == 'true' && !@job_manager.executes_deploy_stages?
111
+ end
112
+
113
+ def setup_worker_conditions(worker)
106
114
  hash_conditions = {}
107
115
  if need_confirmations?
108
116
  CapistranoMulticonfigParallel.configuration.task_confirmations.each do |task|
109
- hash_conditions[task] = { condition: Celluloid::Condition.new, status: 'unconfirmed' }
117
+ hash_conditions[task] = { condition: Celluloid::Condition.new, status: 'unconfirmed' }
110
118
  end
111
119
  end
112
- @job_to_condition[job_id] = hash_conditions
120
+ @job_to_condition[worker.job_id] = hash_conditions
113
121
  end
114
122
 
115
123
  def need_confirmations?
116
124
  CapistranoMulticonfigParallel.configuration.task_confirmation_active.to_s.downcase == 'true'
117
125
  end
118
-
119
- def mark_completed_remaining_tasks
126
+
127
+ def mark_completed_remaining_tasks(worker)
120
128
  return unless need_confirmations?
121
- CapistranoMulticonfigParallel.configuration.task_confirmations.each_with_index do |task, index|
122
- @jobs.pmap do |job_id, _job|
123
- fake_result = proc{ |sum| sum }
124
- task_confirmation = @job_to_condition[job_id][task]
125
- if task_confirmation[:status] != 'confirmed'
126
- task_confirmation[:status] = 'confirmed'
127
- task_confirmation[:condition].signal(fake_result)
128
- end
129
+ CapistranoMulticonfigParallel.configuration.task_confirmations.each_with_index do |task, _index|
130
+ fake_result = proc { |sum| sum }
131
+ task_confirmation = @job_to_condition[worker.job_id][task]
132
+ if task_confirmation[:status] != 'confirmed'
133
+ task_confirmation[:status] = 'confirmed'
134
+ task_confirmation[:condition].signal(fake_result)
129
135
  end
130
136
  end
131
137
  end
132
-
138
+
139
+ def wait_task_confirmations_worker(worker)
140
+ return if !need_confirmations? || syncronized_confirmation?
141
+ CapistranoMulticonfigParallel.configuration.task_confirmations.each_with_index do |task, _index|
142
+ result = wait_condition_for_task(worker.job_id, task)
143
+ confirm_task_approval(result, task, worker) if result.present?
144
+ end
145
+ end
146
+
147
+ def wait_condition_for_task(job_id, task)
148
+ @job_to_condition[job_id][task][:condition].wait
149
+ end
150
+
133
151
  def wait_task_confirmations
134
152
  return unless need_confirmations?
135
- CapistranoMulticonfigParallel.configuration.task_confirmations.each_with_index do |task, index|
153
+ CapistranoMulticonfigParallel.configuration.task_confirmations.each_with_index do |task, _index|
136
154
  results = []
137
155
  @jobs.pmap do |job_id, _job|
138
- result = @job_to_condition[job_id][task][:condition].wait
156
+ result = wait_condition_for_task(job_id, task)
139
157
  results << result
140
158
  end
141
159
  if results.size == @jobs.size
@@ -144,11 +162,13 @@ module CapistranoMulticonfigParallel
144
162
  end
145
163
  end
146
164
 
147
-
148
- def confirm_task_approval(results, task)
149
- return unless results.present?
150
- if results.detect {|x| !x.is_a?(Proc)}
151
- set :apps_symlink_confirmation, CapistranoMulticonfigParallel.ask_confirm("Do you want to continue the deployment and execute #{task}?", 'Y/N')
165
+ def confirm_task_approval(result, task, worker = nil)
166
+ return unless result.present?
167
+ unless result.is_a?(Proc)
168
+ message = "Do you want to continue the deployment and execute #{task.upcase}"
169
+ message += " for JOB #{worker.job_id}" if worker.present?
170
+ message += '?'
171
+ set :apps_symlink_confirmation, CapistranoMulticonfigParallel.ask_confirm(message, 'Y/N')
152
172
  until fetch(:apps_symlink_confirmation).present?
153
173
  sleep(0.1) # keep current thread alive
154
174
  end
@@ -157,9 +177,9 @@ module CapistranoMulticonfigParallel
157
177
  @jobs.pmap do |job_id, job|
158
178
  worker = get_worker_for_job(job_id)
159
179
  worker.publish_rake_event('approved' => 'yes',
160
- 'action' => 'invoke',
161
- 'job_id' => job['id'],
162
- 'task' => task
180
+ 'action' => 'invoke',
181
+ 'job_id' => job['id'],
182
+ 'task' => task
163
183
  )
164
184
  end
165
185
  end
@@ -177,6 +197,21 @@ module CapistranoMulticonfigParallel
177
197
  end
178
198
  end
179
199
 
200
+ def process_job(job)
201
+ env_options = {}
202
+ job['env_options'].each do |key, value|
203
+ env_options[key] = value if value.present?
204
+ end
205
+ {
206
+ 'job_id' => job['id'],
207
+ 'app_name' => job['app'],
208
+ 'env_name' => job['env'],
209
+ 'action_name' => job['action'],
210
+ 'env_options' => env_options,
211
+ 'task_arguments' => job['task_arguments'],
212
+ }
213
+ end
214
+
180
215
  # lookup status of job by asking actor running it
181
216
  def get_job_status(job)
182
217
  status = nil
@@ -44,6 +44,7 @@ module CapistranoMulticonfigParallel
44
44
  end
45
45
 
46
46
  def start_task
47
+ @manager.setup_worker_conditions(Actor.current)
47
48
  debug("exec worker #{@job_id} starts task with #{@job.inspect}") if debug_enabled?
48
49
  @client = CelluloidPubsub::Client.connect(actor: Actor.current, enable_debug: @manager.class.debug_websocket?) do |ws|
49
50
  ws.subscribe(@subscription_channel)
@@ -77,8 +78,8 @@ module CapistranoMulticonfigParallel
77
78
  @task_argv << 'count_rake=true'
78
79
  @child_process = CapistranoMulticonfigParallel::ChildProcess.new
79
80
  Actor.current.link @child_process
80
- debug("worker #{@job_id} executes: bundle exec multi_cap #{@task_argv.join(' ')}") if debug_enabled?
81
- @child_process.async.work("bundle exec multi_cap #{@task_argv.join(' ')}", actor: Actor.current, dry_run: true)
81
+ debug("worker #{@job_id} executes: #{generate_command}") if debug_enabled?
82
+ @child_process.async.work(generate_command, actor: Actor.current, silent: true, dry_run: true)
82
83
  else
83
84
  async.execute_deploy
84
85
  end
@@ -88,9 +89,23 @@ module CapistranoMulticonfigParallel
88
89
  @rake_tasks ||= []
89
90
  end
90
91
 
92
+ def generate_command
93
+ <<-CMD
94
+ bundle exec ruby -e "require 'bundler' ; Bundler.with_clean_env { %x[cd #{CapistranoMulticonfigParallel.detect_root.to_s} && bundle install && RAILS_ENV=#{@env_name} bundle exec multi_cap #{@task_argv.join(' ')} ] } "
95
+ CMD
96
+ end
97
+
91
98
  def execute_deploy
92
99
  @execute_deploy = true
93
100
  debug("invocation chain #{@job_id} is : #{@rake_tasks.inspect}") if debug_enabled? && CapistranoMulticonfigParallel.show_task_progress
101
+ check_child_proces
102
+ setup_task_arguments
103
+ debug("worker #{@job_id} executes: #{generate_command}") if debug_enabled?
104
+ @child_process.async.work(generate_command, actor: Actor.current, silent: true)
105
+ @manager.wait_task_confirmations_worker(Actor.current) unless @manager.syncronized_confirmation?
106
+ end
107
+
108
+ def check_child_proces
94
109
  if !defined?(@child_process) || @child_process.nil?
95
110
  @child_process = CapistranoMulticonfigParallel::ChildProcess.new
96
111
  Actor.current.link @child_process
@@ -98,9 +113,6 @@ module CapistranoMulticonfigParallel
98
113
  @client.unsubscribe("rake_worker_#{@job_id}_count")
99
114
  @child_process.exit_status = nil
100
115
  end
101
- setup_task_arguments
102
- debug("worker #{@job_id} executes: bundle exec multi_cap #{@task_argv.join(' ')}") if debug_enabled?
103
- @child_process.async.work("bundle exec multi_cap #{@task_argv.join(' ')}", actor: Actor.current, silent: true)
104
116
  end
105
117
 
106
118
  def on_close(code, reason)
@@ -171,19 +183,25 @@ module CapistranoMulticonfigParallel
171
183
  end
172
184
 
173
185
  def process_job(job)
174
- @job_id = job['id']
175
- @app_name = job['app']
176
- @env_name = job['env']
177
- @action_name = job['action']
178
- @env_options = {}
179
- job['env_options'].each do |key, value|
180
- @env_options[key] = value if value.present?
181
- end
182
- @task_arguments = job['task_arguments']
186
+ processed_job = @manager.process_job(job)
187
+ @job_id = processed_job['job_id']
188
+ @app_name = processed_job['app_name']
189
+ @env_name = processed_job['env_name']
190
+ @action_name = processed_job['action_name']
191
+ @env_options = processed_job['env_options']
192
+ @task_arguments = processed_job['task_arguments']
193
+ end
194
+
195
+ def crashed?
196
+ @action_name == 'deploy:rollback' || @action_name == 'deploy:failed'
183
197
  end
184
198
 
185
- def crashed?
186
- @action_name == 'deploy:rollback'
199
+ def finish_worker
200
+ @manager.mark_completed_remaining_tasks(Actor.current)
201
+ @worker_state = 'finished'
202
+ @manager.job_to_worker.each do|_job_id, worker|
203
+ debug("worker #{worker.job_id}has state #{worker.worker_state}") if worker.alive? && ebug_enabled?
204
+ end
187
205
  end
188
206
 
189
207
  def notify_finished(exit_status)
@@ -194,16 +212,8 @@ module CapistranoMulticonfigParallel
194
212
  else
195
213
  update_machine_state('FINISHED')
196
214
  debug("worker #{job_id} notifies manager has finished") if debug_enabled?
197
- @worker_state = "finished"
198
- if debug_enabled?
199
- debug("worker #{job_id}has state #{@worker_state}")
200
- @manager.job_to_worker.each{|job_id, worker|
201
- debug("worker #{worker.job_id}has state #{worker.worker_state}") if worker.alive?
202
- }
203
- end
215
+ finish_worker
204
216
  end
205
217
  end
206
-
207
-
208
218
  end
209
219
  end
@@ -4,13 +4,12 @@ module CapistranoMulticonfigParallel
4
4
  include Celluloid
5
5
  include Celluloid::Logger
6
6
 
7
- attr_accessor :actor, :pid, :exit_status, :process, :filename,:worker_log
8
-
7
+ attr_accessor :actor, :pid, :exit_status, :process, :filename, :worker_log
9
8
 
10
9
  def work(cmd, options = {})
11
10
  @options = options
12
11
  @actor = @options.fetch(:actor, nil)
13
- set_worker_log
12
+ set_worker_log
14
13
  EM.run do
15
14
  EM.next_tick do
16
15
  start_async_deploy(cmd, options)
@@ -33,8 +32,8 @@ module CapistranoMulticonfigParallel
33
32
  @worker_log = ::Logger.new(@filename)
34
33
  @worker_log.level = ::Logger::Severity::DEBUG
35
34
  @worker_log.formatter = proc do |severity, datetime, progname, msg|
36
- date_format = datetime.strftime("%Y-%m-%d %H:%M:%S")
37
- "[#{date_format}] #{severity} (#{progname}): #{msg}\n"
35
+ date_format = datetime.strftime('%Y-%m-%d %H:%M:%S')
36
+ "[#{date_format}] #{severity} (#{progname}): #{msg}\n"
38
37
  end
39
38
  end
40
39
 
@@ -96,7 +95,7 @@ module CapistranoMulticonfigParallel
96
95
  end
97
96
 
98
97
  def io_callback(io, data)
99
- @worker_log.debug("#{io.upcase} ---- #{data}")
98
+ @worker_log.debug("#{io.upcase} ---- #{data}")
100
99
  end
101
100
  end
102
101
  end
@@ -50,22 +50,42 @@ module CapistranoMulticonfigParallel
50
50
  puts "\n"
51
51
  sleep(1)
52
52
  end
53
-
54
- def add_job_to_table(table, job_id)
53
+
54
+ def get_worker_details(job_id)
55
+ job = @manager.jobs[job_id]
56
+ processed_job = @manager.process_job(job)
55
57
  worker = @manager.get_worker_for_job(job_id)
56
- return unless worker.present?
58
+ if worker.alive?
59
+ state = worker.machine.state.to_s
60
+ state = worker_crashed?(worker) ? state.red : state.green
61
+ else
62
+ state = "dead".upcase.red
63
+ end
57
64
  worker_optons = ''
58
- worker.env_options.each do |key, value|
65
+ processed_job['env_options'].each do |key, value|
59
66
  worker_optons << "#{key}=#{value}\n"
60
67
  end
61
- state = worker.machine.state.to_s
62
- state = worker_crashed?(worker) ? state.red : state.green
63
- row = [{ value: worker.job_id.to_s },
64
- { value: "#{worker.app_name}\n#{worker.env_name}" },
65
- { value: worker.action_name },
66
- { value: worker_optons },
67
- { value: state }
68
- ]
68
+ action = processed_job['task_arguments'].present? ? "#{processed_job['action_name']}[#{processed_job['task_arguments'].join(',')}]" : processed_job['action_name']
69
+
70
+ {
71
+ 'job_id' => job_id,
72
+ 'app_name' =>processed_job['app_name'],
73
+ 'env_name' =>processed_job['env_name'],
74
+ 'action_name' => action,
75
+ 'env_options' => worker_optons,
76
+ 'task_arguments' => job['task_arguments'],
77
+ 'state' => state
78
+ }
79
+ end
80
+
81
+ def add_job_to_table(table, job_id)
82
+ details = get_worker_details(job_id)
83
+ row = [{ value: job_id.to_s },
84
+ { value: "#{details['app_name']}\n#{details['env_name']}" },
85
+ { value: details['action_name'] },
86
+ { value: details['env_options'] },
87
+ { value: "#{details['state']}" }
88
+ ]
69
89
  if CapistranoMulticonfigParallel.show_task_progress
70
90
  row << { value: worker.rake_tasks.size }
71
91
  row << { value: worker_progress(worker) }
@@ -10,6 +10,7 @@ module CapistranoMulticonfigParallel
10
10
  if $stdout.isatty
11
11
  $stdout.sync = true
12
12
  end
13
+ CapistranoMulticonfigParallel.original_args = ARGV.dup
13
14
  CapistranoMulticonfigParallel::Application.new.run
14
15
  rescue Interrupt
15
16
  `stty icanon echo`
@@ -13,18 +13,17 @@ module CapistranoMulticonfigParallel
13
13
  command_line_params.each do |param|
14
14
  @config.define param[:name], type: param[:type], description: param[:description], default: param[:default]
15
15
  end
16
-
16
+
17
+ ARGV.clear
18
+ CapistranoMulticonfigParallel.original_args.each { |a| ARGV << a }
17
19
  @config.read config_file if File.file?(config_file)
18
20
  @config.merge(Settings.use(:commandline).resolve!)
19
-
21
+
20
22
  @config.use :config_block
21
23
  @config.finally do |c|
22
24
  check_configuration(c)
23
25
  end
24
26
  @config.resolve!
25
- rescue => ex
26
- puts ex.inspect
27
- puts ex.backtrace if ex.respond_to?(:backtrace)
28
27
  end
29
28
 
30
29
  def default_config
@@ -42,65 +41,78 @@ module CapistranoMulticonfigParallel
42
41
  {
43
42
  name: 'multi_debug',
44
43
  type: :boolean,
45
- description: '[MULTI_CAP] if option is present and has value TRUE , will enable debugging of workers',
44
+ description: 'if option is present and has value TRUE , will enable debugging of workers',
46
45
  default: default_config[:multi_debug]
47
46
  },
48
47
  {
49
48
  name: 'multi_progress',
50
49
  type: :boolean,
51
- description: "[MULTI_CAP] if option is present and has value TRUE will first execute before any process ,
52
- same task but with option '--dry-run' in order to show progress of how many tasks are in total for that task and what is the progress of executing
53
- This will slow down the workers , because they will execute twice the same task.",
50
+ description: "if option is present and has value TRUE will first execute before any process
51
+ \t same task but with option '--dry-run' in order to show progress of how many tasks
52
+ \t are in total for that task and what is the progress of executing
53
+ \t This will slow down the workers , because they will execute twice the same task.",
54
54
  default: default_config[:multi_progress]
55
55
  },
56
56
  {
57
57
  name: 'multi_secvential',
58
58
  type: :boolean,
59
- description: "[MULTI_CAP] If parallel executing does not work for you, you can use this option so that each process is executed normally and ouputted to the screen.
60
- However this means that all other tasks will have to wait for each other to finish before starting ",
59
+ description: "If parallel executing does not work for you, you can use this option so that
60
+ \t each process is executed normally and ouputted to the screen.
61
+ \t However this means that all other tasks will have to wait for each other to finish before starting ",
61
62
  default: default_config[:multi_secvential]
62
63
  },
63
64
  {
64
65
  name: 'websocket_server.enable_debug',
65
66
  type: :boolean,
66
- description: '[MULTI_CAP] if option is present and has value TRUE, will enable debugging of websocket communication between the workers',
67
+ description: "if option is present and has value TRUE
68
+ \t will enable debugging of websocket communication between the workers",
67
69
  default: default_config[:websocket_server][:enable_debug]
68
70
  },
69
71
  {
70
72
  name: 'development_stages',
71
73
  type: Array,
72
- description: '[MULTI_CAP] if option is present and has value an ARRAY of STRINGS, each of them will be used as a development stage',
74
+ description: "if option is present and has value an ARRAY of STRINGS,
75
+ \t each of them will be used as a development stage",
73
76
  default: default_config[:development_stages]
74
77
  },
75
78
  {
76
79
  name: 'task_confirmations',
77
80
  type: Array,
78
- description: '[MULTI_CAP] if option is present and has value TRUE, will enable user confirmation dialogs
79
- before executing each task from option **--task_confirmations**',
81
+ description: "if option is present and has value TRUE, will enable user confirmation dialogs
82
+ \t before executing each task from option **--task_confirmations**",
80
83
  default: default_config[:task_confirmations]
81
84
  },
82
85
  {
83
86
  name: 'task_confirmation_active',
84
87
  type: :boolean,
85
- description: "[MULTI_CAP] if option is present and has value an ARRAY of Strings, and --task_confirmation_active is TRUE ,
86
- then will require a confirmation from user before executing the task.
87
- This will syncronize all workers to wait before executing that task, then a confirmation will be displayed,
88
- and when user will confirm , all workers will resume their operation",
88
+ description: "if option is present and has value an ARRAY of Strings, and --task_confirmation_active is TRUE ,
89
+ \t then will require a confirmation from user before executing the task.
90
+ \t This will syncronize all workers to wait before executing that task, then a confirmation will be displayed,
91
+ \t and when user will confirm , all workers will resume their operation",
89
92
  default: default_config[:task_confirmation_active]
90
93
  },
94
+ {
95
+ name: 'syncronize_confirmation',
96
+ type: :boolean,
97
+ description: "if option is present and has value TRUE, all workers will be synchronized to wait for same task
98
+ \t from the ***task_confirmations** Array before they execute it ",
99
+ default: default_config[:syncronize_confirmation]
100
+ },
91
101
  {
92
102
  name: 'track_dependencies',
93
103
  type: :boolean,
94
- description: "[MULTI_CAP] This should be useed only for Caphub-like applications , in order to deploy dependencies of an application in parallel.
95
- This is used only in combination with option **--application_dependencies** which is described
96
- at section **[2.) Multiple applications](#multiple_apps)**",
104
+ description: "This should be useed only for Caphub-like applications ,
105
+ \t in order to deploy dependencies of an application in parallel.
106
+ \t This is used only in combination with option **--application_dependencies** which is described
107
+ \t at section **[2.) Multiple applications](#multiple_apps)**",
97
108
  default: default_config[:track_dependencies]
98
109
  },
99
110
  {
100
111
  name: 'application_dependencies',
101
112
  type: Array,
102
- description: "[MULTI_CAP] This is an array of hashes. Each hash has only the keys 'app' ( app name), 'priority' and 'dependencies'
103
- ( an array of app names that this app is dependent to) ",
113
+ description: "This is an array of hashes. Each hash has only the keys
114
+ \t 'app' ( app name), 'priority' and 'dependencies'
115
+ \t ( an array of app names that this app is dependent to) ",
104
116
  default: default_config[:application_dependencies]
105
117
  }
106
118
  ]
@@ -111,7 +123,7 @@ module CapistranoMulticonfigParallel
111
123
  [
112
124
  "--#{param[:name]}[=CAP_VALUE]",
113
125
  "--#{param[:name]}",
114
- param[:description],
126
+ "[MULTI_CAP] #{param[:description]}",
115
127
  lambda do |_value|
116
128
  end
117
129
  ]
@@ -138,7 +150,7 @@ module CapistranoMulticonfigParallel
138
150
  end
139
151
 
140
152
  def check_boolean(c, prop)
141
- return unless c[prop].present?
153
+ # return unless c[prop].present?
142
154
  raise ArgumentError, "the property `#{prop}` must be boolean" unless [true, false, 'true', 'false'].include?(c[prop].to_s.downcase)
143
155
  end
144
156
 
@@ -158,13 +170,10 @@ module CapistranoMulticonfigParallel
158
170
  end
159
171
 
160
172
  def check_additional_config(c)
161
- if c[:multi_debug].to_s.downcase == 'true'
162
- CapistranoMulticonfigParallel::CelluloidManager.debug_enabled = true
163
- Celluloid.task_class = Celluloid::TaskThread
164
- end
173
+ CapistranoMulticonfigParallel::CelluloidManager.debug_enabled = true if c[:multi_debug].to_s.downcase == 'true'
165
174
  CapistranoMulticonfigParallel.show_task_progress = true if c[:multi_progress].to_s.downcase == 'true'
166
175
  CapistranoMulticonfigParallel.execute_in_sequence = true if c[:multi_secvential].to_s.downcase == 'true'
167
176
  end
168
177
  end
169
- end
178
+ end
170
179
  end
@@ -14,8 +14,6 @@ module CapistranoMulticonfigParallel
14
14
  @stages = stages
15
15
  @jobs = []
16
16
  CapistranoMulticonfigParallel.enable_logging
17
- CapistranoMulticonfigParallel.configuration_valid?
18
- CapistranoMulticonfigParallel.verify_app_dependencies(@stages) if CapistranoMulticonfigParallel.configuration.track_dependencies
19
17
  end
20
18
 
21
19
  def can_start?
@@ -31,11 +29,21 @@ module CapistranoMulticonfigParallel
31
29
  CapistranoMulticonfigParallel::CUSTOM_COMMANDS[key]
32
30
  end
33
31
 
32
+ def executes_deploy_stages?
33
+ @name == custom_commands[:stages]
34
+ end
35
+
34
36
  def multi_apps?
35
37
  @cap_app.multi_apps?
36
38
  end
37
39
 
40
+ def configuration
41
+ CapistranoMulticonfigParallel.configuration
42
+ end
43
+
38
44
  def start(&block)
45
+ CapistranoMulticonfigParallel.configuration_valid?
46
+ check_before_starting
39
47
  @application = custom_command? ? nil : @top_level_tasks.first.split(':').reverse[1]
40
48
  @stage = custom_command? ? nil : @top_level_tasks.first.split(':').reverse[0]
41
49
  @name, @args = @cap_app.parse_task_string(@top_level_tasks.second)
@@ -45,6 +53,15 @@ module CapistranoMulticonfigParallel
45
53
  run
46
54
  end
47
55
 
56
+ def check_before_starting
57
+ @condition = Celluloid::Condition.new
58
+ @manager = CapistranoMulticonfigParallel::CelluloidManager.new(Actor.current)
59
+ if CapistranoMulticonfigParallel::CelluloidManager.debug_enabled == true
60
+ Celluloid.logger = CapistranoMulticonfigParallel.logger
61
+ Celluloid.task_class = Celluloid::TaskThread
62
+ end
63
+ end
64
+
48
65
  def collect_jobs(options = {}, &block)
49
66
  options = prepare_options(options)
50
67
  block.call(options) if block_given?
@@ -52,12 +69,12 @@ module CapistranoMulticonfigParallel
52
69
  raise [e, e.backtrace].inspect
53
70
  end
54
71
 
55
- def process_jobs(&block)
72
+ def process_jobs
56
73
  return unless @jobs.present?
57
74
  if CapistranoMulticonfigParallel.execute_in_sequence
58
75
  @jobs.each { |job| CapistranoMulticonfigParallel::StandardDeploy.execute_standard_deploy(job) }
59
76
  else
60
- run_async_jobs(&block)
77
+ run_async_jobs
61
78
  end
62
79
  end
63
80
 
@@ -91,10 +108,8 @@ module CapistranoMulticonfigParallel
91
108
  end
92
109
  end
93
110
 
94
- def run_async_jobs(&block)
111
+ def run_async_jobs
95
112
  return unless @jobs.present?
96
- @condition = Celluloid::Condition.new
97
- @manager = CapistranoMulticonfigParallel::CelluloidManager.new(Actor.current)
98
113
  @jobs.pmap do |job|
99
114
  @manager.async.delegate(job)
100
115
  end
@@ -102,7 +117,7 @@ module CapistranoMulticonfigParallel
102
117
  sleep(0.1) # keep current thread alive
103
118
  end
104
119
  return unless @manager.registration_complete
105
- @manager.process_jobs(&block)
120
+ @manager.async.process_jobs
106
121
  wait_jobs_termination
107
122
  end
108
123
 
@@ -124,8 +139,8 @@ module CapistranoMulticonfigParallel
124
139
  env_opts = get_app_additional_env_options(app, message)
125
140
 
126
141
  options['env_options'] = options['env_options'].reverse_merge(env_opts.except('BOX'))
127
-
128
- env_options = branch_name.present? ? { 'BRANCH' => branch_name }.merge(options['env_options']) : options['env_options']
142
+
143
+ env_options = branch_name.present? ? { 'BRANCH' => branch_name }.merge(options['env_options']) : options['env_options']
129
144
 
130
145
  job = {
131
146
  app: app,
@@ -164,8 +179,6 @@ module CapistranoMulticonfigParallel
164
179
  end
165
180
  end
166
181
 
167
-
168
-
169
182
  def get_app_additional_env_options(app, app_message)
170
183
  app_name = (app.is_a?(Hash) && app[:app].present?) ? app[:app].camelcase : app
171
184
  app_name = app_name.present? ? app_name : 'current application'
@@ -11,6 +11,19 @@ module CapistranoMulticonfigParallel
11
11
  @dependency_tracker = CapistranoMulticonfigParallel::DependencyTracker.new(Actor.current)
12
12
  end
13
13
 
14
+ def check_before_starting
15
+ verify_app_dependencies(@stages) if configuration.present? && configuration.track_dependencies.to_s.downcase == 'true'
16
+ super
17
+ end
18
+
19
+ def verify_app_dependencies(stages)
20
+ applications = stages.map { |stage| stage.split(':').reverse[1] }
21
+ wrong = configuration.application_dependencies.find do |hash|
22
+ !applications.include?(hash[:app]) || (hash[:dependencies].present? && hash[:dependencies].find { |val| !applications.include?(val) })
23
+ end
24
+ raise ArgumentError, "invalid configuration for #{wrong.inspect}" if wrong.present?
25
+ end
26
+
14
27
  def run
15
28
  options = {}
16
29
  if custom_command?
@@ -54,7 +67,7 @@ module CapistranoMulticonfigParallel
54
67
  end
55
68
  end
56
69
 
57
- private
70
+ private
58
71
 
59
72
  def multi_collect_and_run_jobs(options = {}, &block)
60
73
  collect_jobs(options) do |new_options|
@@ -1,5 +1,5 @@
1
1
  multi_debug: true
2
- multi_progres: false
2
+ multi_progress: false
3
3
  multi_secvential: false
4
4
  websocket_server:
5
5
  enable_debug: false
@@ -7,7 +7,8 @@ websocket_server:
7
7
  development_stages:
8
8
  - development
9
9
  - webdev
10
-
10
+
11
+ syncronize_confirmation: true
11
12
  task_confirmation_active: false
12
13
  task_confirmations:
13
14
  - deploy:symlink:release
@@ -12,7 +12,7 @@ Rake::Task.class_eval do
12
12
  end
13
13
  end
14
14
 
15
- def run_the_actor(job_id, &block)
15
+ def run_the_actor(job_id)
16
16
  rake_actor_id = ENV['count_rake'].present? ? "rake_worker_#{job_id}_count" : "rake_worker_#{job_id}"
17
17
  if Celluloid::Actor[rake_actor_id].blank?
18
18
  CapistranoMulticonfigParallel::RakeWorker.supervise_as rake_actor_id
@@ -23,6 +23,6 @@ Rake::Task.class_eval do
23
23
  until Celluloid::Actor[rake_actor_id].task_approved
24
24
  sleep(0.1) # keep current thread alive
25
25
  end
26
- block.call if Celluloid::Actor[rake_actor_id].task_approved
26
+ yield if Celluloid::Actor[rake_actor_id].task_approved
27
27
  end
28
28
  end
@@ -7,8 +7,8 @@ module CapistranoMulticonfigParallel
7
7
  # module used for generating the version
8
8
  module VERSION
9
9
  MAJOR = 0
10
- MINOR = 2
11
- TINY = 1
10
+ MINOR = 4
11
+ TINY = 0
12
12
  PRE = nil
13
13
 
14
14
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano_multiconfig_parallel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - bogdanRada