capistrano_multiconfig_parallel 0.15.6 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +25 -0
- data/.gitignore +0 -1
- data/Gemfile.lock +327 -0
- data/README.md +1 -1
- data/lib/capistrano_multiconfig_parallel/all.rb +16 -1
- data/lib/capistrano_multiconfig_parallel/application.rb +340 -11
- data/lib/capistrano_multiconfig_parallel/base.rb +8 -8
- data/lib/capistrano_multiconfig_parallel/celluloid/celluloid_manager.rb +3 -6
- data/lib/capistrano_multiconfig_parallel/celluloid/celluloid_worker.rb +6 -0
- data/lib/capistrano_multiconfig_parallel/cli.rb +8 -1
- data/lib/capistrano_multiconfig_parallel/configuration.rb +8 -30
- data/lib/capistrano_multiconfig_parallel/extensions/rake.rb +1 -1
- data/lib/capistrano_multiconfig_parallel/{multi_app_helpers → helpers}/dependency_tracker.rb +5 -5
- data/lib/capistrano_multiconfig_parallel/helpers/helper.rb +9 -0
- data/lib/capistrano_multiconfig_parallel/{extensions → helpers}/rake_hook_actor.rb +0 -1
- data/lib/capistrano_multiconfig_parallel/initializers/conf.rb +2 -3
- data/lib/capistrano_multiconfig_parallel/initializers/default.yml +3 -3
- data/lib/capistrano_multiconfig_parallel/version.rb +2 -2
- metadata +11 -9
- data/lib/capistrano_multiconfig_parallel/managers/base_manager.rb +0 -348
- /data/lib/capistrano_multiconfig_parallel/{extensions → helpers}/input_stream.rb +0 -0
- /data/lib/capistrano_multiconfig_parallel/{multi_app_helpers → helpers}/interactive_menu.rb +0 -0
- /data/lib/capistrano_multiconfig_parallel/{extensions → helpers}/output_stream.rb +0 -0
- /data/lib/capistrano_multiconfig_parallel/{managers → helpers}/standard_deploy.rb +0 -0
@@ -1,20 +1,349 @@
|
|
1
1
|
module CapistranoMulticonfigParallel
|
2
|
-
#
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
# finds app dependencies, shows menu and delegates jobs to celluloid manager
|
3
|
+
# rubocop:disable ClassLength
|
4
|
+
class Application
|
5
|
+
include Celluloid
|
6
|
+
include Celluloid::Logger
|
7
|
+
|
8
|
+
attr_accessor :stages,:stage_apps, :top_level_tasks, :jobs, :branch_backup, :condition, :manager, :dependency_tracker, :application, :stage, :name, :args, :argv, :default_stage
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@stages = fetch_stages
|
12
|
+
@stage_apps = multi_apps? ? @stages.map { |stage| stage.split(':').reverse[1] }.uniq : []
|
13
|
+
collect_command_line_tasks(CapistranoMulticonfigParallel.original_args)
|
14
|
+
@jobs = []
|
15
|
+
CapistranoMulticonfigParallel.configuration_valid?(@stages)
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def start
|
20
|
+
verify_app_dependencies(@stages) if multi_apps? && configuration.application_dependencies.present?
|
21
|
+
check_before_starting
|
22
|
+
initialize_data
|
23
|
+
run
|
24
|
+
end
|
25
|
+
|
26
|
+
def verify_app_dependencies(stages)
|
27
|
+
wrong = configuration.application_dependencies.find do |hash|
|
28
|
+
!@stage_apps.include?(hash[:app]) || (hash[:dependencies].present? && hash[:dependencies].find { |val| !@stage_apps.include?(val) })
|
29
|
+
end
|
30
|
+
raise ArgumentError,"Invalid configuration for #{wrong.inspect}".red if wrong.present?
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def fetch_stages
|
35
|
+
fetch_stages_paths do |paths|
|
36
|
+
paths.reject! { |path| check_stage_path(paths, path) }
|
37
|
+
paths.sort if paths.present?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def check_stage_path(paths, path)
|
42
|
+
paths.any? { |another| another != path && another.start_with?(path + ':') }
|
43
|
+
end
|
44
|
+
|
45
|
+
def stages_paths
|
46
|
+
stages_root = 'config/deploy'
|
47
|
+
Dir["#{stages_root}/**/*.rb"].map do |file|
|
48
|
+
file.slice(stages_root.size + 1..-4).tr('/', ':')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def fetch_stages_paths
|
53
|
+
stages_paths.tap { |paths| yield paths if block_given? }
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
def run_custom_command(options)
|
59
|
+
custom_stages = fetch_multi_stages
|
60
|
+
return if custom_stages.blank?
|
61
|
+
custom_stages = check_multi_stages(custom_stages)
|
62
|
+
custom_stages.each do |stage|
|
63
|
+
collect_jobs(options.merge('stage' => stage))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def deploy_multiple_apps(applications, options)
|
68
|
+
options = options.stringify_keys
|
69
|
+
return unless applications.present?
|
70
|
+
applications.each do |app|
|
71
|
+
deploy_app(options.merge('app' => app))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def backup_the_branch
|
76
|
+
return if custom_command? || @argv['BRANCH'].blank?
|
77
|
+
@branch_backup = @argv['BRANCH'].to_s
|
78
|
+
@argv['BRANCH'] = nil
|
79
|
+
end
|
80
|
+
|
81
|
+
def can_start?
|
82
|
+
@top_level_tasks.size >= 1 && (@stages.include?(@top_level_tasks.first) || custom_command?) && @argv[CapistranoMulticonfigParallel::ENV_KEY_JOB_ID].blank?
|
83
|
+
end
|
84
|
+
|
85
|
+
def custom_command?
|
86
|
+
if multi_apps?
|
87
|
+
!@stages.include?(@top_level_tasks.first) && custom_commands.values.include?(@top_level_tasks.first)
|
88
|
+
else
|
89
|
+
!@stages.include?(@top_level_tasks.second) && @stages.include?(@top_level_tasks.first) && custom_commands.values.include?(@top_level_tasks.second)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def custom_commands
|
94
|
+
key = multi_apps? ? CapistranoMulticonfigParallel::MULTI_KEY : CapistranoMulticonfigParallel::SINGLE_KEY
|
95
|
+
CapistranoMulticonfigParallel::CUSTOM_COMMANDS[key]
|
96
|
+
end
|
97
|
+
|
98
|
+
def multi_apps?
|
99
|
+
@stages.find { |stage| stage.include?(':') }.present?
|
100
|
+
end
|
101
|
+
|
102
|
+
def configuration
|
103
|
+
CapistranoMulticonfigParallel.configuration
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
def initialize_data
|
108
|
+
@application = custom_command? ? nil : @top_level_tasks.first.split(':').reverse[1]
|
109
|
+
@stage = custom_command? ? nil : @top_level_tasks.first.split(':').reverse[0]
|
110
|
+
@stage = @stage.present? ? @stage : @default_stage
|
111
|
+
@name, @args = parse_task_string(@top_level_tasks.second)
|
112
|
+
end
|
113
|
+
|
114
|
+
def collect_command_line_tasks(args) # :nodoc:
|
115
|
+
@argv = {}
|
116
|
+
@top_level_tasks = []
|
117
|
+
args.each do |arg|
|
118
|
+
if arg =~ /^(\w+)=(.*)$/m
|
119
|
+
@argv[Regexp.last_match(1)] = Regexp.last_match(2)
|
120
|
+
else
|
121
|
+
@top_level_tasks << arg unless arg =~ /^-/
|
122
|
+
end
|
123
|
+
end
|
124
|
+
@top_level_tasks.push(Rake.application.default_task_name) if @top_level_tasks.blank?
|
125
|
+
end
|
126
|
+
|
127
|
+
def parse_task_string(string) # :nodoc:
|
128
|
+
/^([^\[]+)(?:\[(.*)\])$/ =~ string.to_s
|
129
|
+
|
130
|
+
name = Regexp.last_match(1)
|
131
|
+
remaining_args = Regexp.last_match(2)
|
132
|
+
|
133
|
+
return string, [] unless name
|
134
|
+
return name, [] if remaining_args.empty?
|
135
|
+
|
136
|
+
args = []
|
137
|
+
|
138
|
+
loop do
|
139
|
+
/((?:[^\\,]|\\.)*?)\s*(?:,\s*(.*))?$/ =~ remaining_args
|
140
|
+
|
141
|
+
remaining_args = Regexp.last_match(2)
|
142
|
+
args << Regexp.last_match(1).gsub(/\\(.)/, '\1')
|
143
|
+
break if remaining_args.blank?
|
144
|
+
end
|
145
|
+
|
146
|
+
[name, args]
|
147
|
+
end
|
148
|
+
|
149
|
+
def verify_options_custom_command(options)
|
150
|
+
options[:action] = @argv['ACTION'].present? ? @argv['ACTION'] : 'deploy'
|
151
|
+
options
|
152
|
+
end
|
153
|
+
|
154
|
+
def check_before_starting
|
155
|
+
CapistranoMulticonfigParallel.enable_logging
|
156
|
+
@dependency_tracker = CapistranoMulticonfigParallel::DependencyTracker.new(Actor.current)
|
157
|
+
@default_stage = CapistranoMulticonfigParallel.configuration.development_stages.present? ? CapistranoMulticonfigParallel.configuration.development_stages.first : 'development'
|
158
|
+
@condition = Celluloid::Condition.new
|
159
|
+
@manager = CapistranoMulticonfigParallel::CelluloidManager.new(Actor.current)
|
160
|
+
end
|
161
|
+
|
162
|
+
def collect_jobs(options = {}, &_block)
|
163
|
+
options = prepare_options(options)
|
164
|
+
options = options.stringify_keys
|
165
|
+
apps = @dependency_tracker.fetch_apps_needed_for_deployment(options['app'], options['action'])
|
166
|
+
backup_the_branch if multi_apps?
|
167
|
+
deploy_multiple_apps(apps, options)
|
168
|
+
deploy_app(options) if !custom_command? || !multi_apps?
|
169
|
+
rescue => e
|
170
|
+
CapistranoMulticonfigParallel.log_message(e)
|
171
|
+
end
|
172
|
+
|
173
|
+
def process_jobs
|
174
|
+
return unless @jobs.present?
|
175
|
+
FileUtils.rm Dir["#{CapistranoMulticonfigParallel.log_directory}/worker_*.log"]
|
176
|
+
if configuration.multi_secvential.to_s.downcase == 'true'
|
177
|
+
@jobs.each { |job| CapistranoMulticonfigParallel::StandardDeploy.new(job) }
|
178
|
+
else
|
179
|
+
run_async_jobs
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def tag_staging_exists? # check exists task from capistrano-gitflow
|
184
|
+
CapistranoMulticonfigParallel.find_loaded_gem('capistrano-gitflow').present?
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
def fetch_multi_stages
|
189
|
+
custom_stages = @argv['STAGES'].blank? ? '' : @argv['STAGES']
|
190
|
+
custom_stages = parse_inputted_value('value' => custom_stages).split(',').compact if custom_stages.present?
|
191
|
+
custom_stages = custom_stages.present? ? custom_stages : [@default_stage]
|
192
|
+
custom_stages
|
193
|
+
end
|
194
|
+
|
195
|
+
def wants_deploy_production?
|
196
|
+
(!custom_command? && @stage == 'production') || (custom_command? && fetch_multi_stages.include?('production'))
|
197
|
+
end
|
198
|
+
|
199
|
+
def can_tag_staging?
|
200
|
+
wants_deploy_production? && tag_staging_exists? && fetch_multi_stages.include?('staging')
|
201
|
+
end
|
202
|
+
|
203
|
+
def check_multi_stages(custom_stages)
|
204
|
+
can_tag_staging? ? custom_stages.reject { |u| u == 'production' } : custom_stages
|
205
|
+
end
|
206
|
+
|
207
|
+
def deploy_app(options = {})
|
208
|
+
options = options.stringify_keys
|
209
|
+
app = options['app'].is_a?(Hash) ? options['app'] : { 'app' => options['app'] }
|
210
|
+
branch = @branch_backup.present? ? @branch_backup : @argv['BRANCH'].to_s
|
211
|
+
call_task_deploy_app({
|
212
|
+
branch: branch,
|
213
|
+
app: app,
|
214
|
+
action: options['action']
|
215
|
+
}.reverse_merge(options))
|
6
216
|
end
|
7
217
|
|
8
|
-
def
|
9
|
-
|
218
|
+
def get_app_additional_env_options(app, app_message)
|
219
|
+
app_name = (app.is_a?(Hash) && app[:app].present?) ? app[:app].camelcase : app
|
220
|
+
app_name = app_name.present? ? app_name : 'current application'
|
221
|
+
message = "Please write additional ENV options for #{app_name} for #{app_message}"
|
222
|
+
app_additional_env_options = CapistranoMulticonfigParallel.ask_confirm(message, nil)
|
223
|
+
fetch_app_additional_env_options(app_additional_env_options)
|
10
224
|
end
|
11
225
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
226
|
+
def worker_environments
|
227
|
+
@jobs.map { |job| job['env'] }
|
228
|
+
end
|
229
|
+
|
230
|
+
def run
|
231
|
+
options = {}
|
232
|
+
if custom_command?
|
233
|
+
options = verify_options_custom_command(options)
|
234
|
+
run_custom_command(options)
|
16
235
|
else
|
17
|
-
|
236
|
+
collect_jobs(options)
|
237
|
+
end
|
238
|
+
process_jobs
|
239
|
+
end
|
240
|
+
|
241
|
+
def call_task_deploy_app(options = {})
|
242
|
+
options = options.stringify_keys
|
243
|
+
main_box_name = @argv['BOX'].blank? ? '' : @argv['BOX']
|
244
|
+
stage = options.fetch('stage', @default_stage)
|
245
|
+
if CapistranoMulticonfigParallel.configuration.development_stages.include?(stage) && main_box_name.present? && /^[a-z0-9,]+/.match(main_box_name)
|
246
|
+
execute_on_multiple_boxes(main_box_name, options)
|
247
|
+
else
|
248
|
+
prepare_job(options)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def run_async_jobs
|
253
|
+
return unless @jobs.present?
|
254
|
+
@jobs.pmap do |job|
|
255
|
+
@manager.async.delegate(job)
|
256
|
+
end
|
257
|
+
until @manager.registration_complete
|
258
|
+
sleep(0.1) # keep current thread alive
|
259
|
+
end
|
260
|
+
return unless @manager.registration_complete
|
261
|
+
@manager.async.process_jobs
|
262
|
+
wait_jobs_termination
|
263
|
+
end
|
264
|
+
|
265
|
+
def wait_jobs_termination
|
266
|
+
return if configuration.multi_secvential.to_s.downcase == 'true'
|
267
|
+
result = @condition.wait
|
268
|
+
return unless result.present?
|
269
|
+
@manager.terminate
|
270
|
+
terminate
|
271
|
+
end
|
272
|
+
|
273
|
+
def prepare_job(options)
|
274
|
+
options = options.stringify_keys
|
275
|
+
branch_name = options.fetch('branch', {})
|
276
|
+
app = options.fetch('app', {})
|
277
|
+
app = app.fetch('app', '')
|
278
|
+
box = options['env_options']['BOX']
|
279
|
+
message = box.present? ? "BOX #{box}:" : "stage #{options['stage']}:"
|
280
|
+
env_opts = get_app_additional_env_options(app, message)
|
281
|
+
|
282
|
+
options['env_options'] = options['env_options'].reverse_merge(env_opts)
|
283
|
+
|
284
|
+
env_options = branch_name.present? ? { 'BRANCH' => branch_name }.merge(options['env_options']) : options['env_options']
|
285
|
+
job_env_options = custom_command? && env_options['ACTION'].present? ? env_options.except('ACTION') : env_options
|
286
|
+
|
287
|
+
job = {
|
288
|
+
id: SecureRandom.random_number(500),
|
289
|
+
app: app,
|
290
|
+
env: options['stage'],
|
291
|
+
action: custom_command? && env_options['ACTION'].present? ? env_options['ACTION'] : options['action'],
|
292
|
+
task_arguments: options['task_arguments'],
|
293
|
+
env_options: job_env_options
|
294
|
+
}
|
295
|
+
@jobs << job.stringify_keys
|
296
|
+
end
|
297
|
+
|
298
|
+
def prepare_options(options)
|
299
|
+
options = options.stringify_keys
|
300
|
+
options['app'] = options.fetch('app', @application.to_s.clone)
|
301
|
+
options['action'] = options.fetch('action', @name.to_s.clone)
|
302
|
+
options['stage'] = options.fetch('stage', @stage.to_s.clone)
|
303
|
+
options['env_options'] = options.fetch('env_options', @argv.clone)
|
304
|
+
options['task_arguments'] = options.fetch('task_arguments', @args.clone)
|
305
|
+
options
|
306
|
+
end
|
307
|
+
|
308
|
+
def parse_inputted_value(options = {})
|
309
|
+
options = options.stringify_keys
|
310
|
+
value = options['value'].present? ? options['value'] : nil
|
311
|
+
if value.present?
|
312
|
+
branch = value.gsub("\r\n", '')
|
313
|
+
branch = branch.delete("\n") if branch.present?
|
314
|
+
branch = branch.gsub(/\s+/, ' ') if branch.present?
|
315
|
+
branch = branch.strip if branch.present?
|
316
|
+
return branch
|
317
|
+
else
|
318
|
+
return ''
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
def fetch_app_additional_env_options(variable)
|
323
|
+
options = {}
|
324
|
+
return options if variable.blank?
|
325
|
+
env_options = parse_inputted_value('value' => variable)
|
326
|
+
env_options = env_options.split(' ')
|
327
|
+
options = multi_fetch_argv(env_options)
|
328
|
+
options.stringify_keys!
|
329
|
+
options
|
330
|
+
end
|
331
|
+
|
332
|
+
def multi_fetch_argv(args)
|
333
|
+
options = {}
|
334
|
+
args.each do |arg|
|
335
|
+
if arg =~ /^(\w+)=(.*)$/m
|
336
|
+
options[Regexp.last_match(1)] = Regexp.last_match(2)
|
337
|
+
end
|
338
|
+
end
|
339
|
+
options
|
340
|
+
end
|
341
|
+
|
342
|
+
def execute_on_multiple_boxes(main_box_name, options)
|
343
|
+
boxes = parse_inputted_value('value' => main_box_name).split(',').compact
|
344
|
+
boxes.each do |box_name|
|
345
|
+
options['env_options']['BOX'] = box_name
|
346
|
+
prepare_job(options)
|
18
347
|
end
|
19
348
|
end
|
20
349
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# base module that has the statis methods that this gem is using
|
2
2
|
module CapistranoMulticonfigParallel
|
3
3
|
include CapistranoMulticonfigParallel::Configuration
|
4
|
+
include Helper
|
4
5
|
|
5
6
|
ENV_KEY_JOB_ID = 'multi_cap_job_id'
|
6
7
|
MULTI_KEY = 'multi'
|
@@ -57,10 +58,8 @@ module CapistranoMulticonfigParallel
|
|
57
58
|
FileUtils.mkdir_p(log_directory) unless File.directory?(log_directory)
|
58
59
|
if CapistranoMulticonfigParallel::CelluloidManager.debug_enabled.to_s.downcase == 'true'
|
59
60
|
FileUtils.touch(main_log_file) unless File.file?(main_log_file)
|
60
|
-
|
61
|
-
|
62
|
-
log_file.sync = true
|
63
|
-
end
|
61
|
+
log_file = File.open(main_log_file, 'w')
|
62
|
+
log_file.sync = true
|
64
63
|
self.logger = ::Logger.new(main_log_file)
|
65
64
|
else
|
66
65
|
self.logger = ::Logger.new(DevNull.new)
|
@@ -75,15 +74,16 @@ module CapistranoMulticonfigParallel
|
|
75
74
|
err_backtrace = message.respond_to?(:backtrace) ? message.backtrace.join("\n\n") : ''
|
76
75
|
if err_backtrace.present?
|
77
76
|
logger.debug(
|
78
|
-
|
79
|
-
|
80
|
-
|
77
|
+
class_name: message.class,
|
78
|
+
message: error_message,
|
79
|
+
backtrace: err_backtrace
|
81
80
|
)
|
82
81
|
else
|
83
82
|
logger.debug(message)
|
84
83
|
end
|
85
84
|
end
|
86
85
|
|
86
|
+
|
87
87
|
def detect_root
|
88
88
|
if ENV['MULTI_CAP_ROOT']
|
89
89
|
Pathname.new(ENV['MULTI_CAP_ROOT'])
|
@@ -98,7 +98,7 @@ module CapistranoMulticonfigParallel
|
|
98
98
|
root = Pathname.new(FileUtils.pwd)
|
99
99
|
root = root.parent unless root.directory?
|
100
100
|
root = root.parent until root.children.find { |f| f.file? && f.basename.to_s.downcase == 'capfile' }.present? || root.root?
|
101
|
-
raise "Can't detect Capfile in the application root" if root.root?
|
101
|
+
raise "Can't detect Capfile in the application root".red if root.root?
|
102
102
|
root
|
103
103
|
end
|
104
104
|
end
|
@@ -54,10 +54,7 @@ module CapistranoMulticonfigParallel
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def generate_job_id(job)
|
57
|
-
|
58
|
-
job['id'] = primary_key
|
59
|
-
@jobs[primary_key] = job
|
60
|
-
@jobs[primary_key]
|
57
|
+
@jobs[job['id']] = job
|
61
58
|
job['id']
|
62
59
|
end
|
63
60
|
|
@@ -181,8 +178,8 @@ module CapistranoMulticonfigParallel
|
|
181
178
|
message = "Do you want to continue the deployment and execute #{task.upcase}"
|
182
179
|
message += " for JOB #{worker.job_id}" if worker.present?
|
183
180
|
message += '?'
|
184
|
-
|
185
|
-
until
|
181
|
+
apps_symlink_confirmation = Celluloid::Actor[:terminal_server].show_confirmation(message, 'Y/N')
|
182
|
+
until apps_symlink_confirmation.present?
|
186
183
|
sleep(0.1) # keep current thread alive
|
187
184
|
end
|
188
185
|
end
|
@@ -83,6 +83,12 @@ module CapistranoMulticonfigParallel
|
|
83
83
|
"cd #{CapistranoMulticonfigParallel.detect_root}"
|
84
84
|
end
|
85
85
|
|
86
|
+
# def generate_command_new
|
87
|
+
# <<-CMD
|
88
|
+
# bundle exec ruby -e "require 'bundler' ; Bundler.with_clean_env { %x[cd #{cd_working_directory} && bundle install && RAILS_ENV=#{@env_name} bundle exec cap #{@task_argv.join(' ')}] } "
|
89
|
+
# CMD
|
90
|
+
# end
|
91
|
+
|
86
92
|
def generate_command
|
87
93
|
<<-CMD
|
88
94
|
#{cd_working_directory} && RAILS_ENV=#{@env_name} bundle exec multi_cap #{@task_argv.join(' ')}
|
@@ -3,15 +3,22 @@ Gem.find_files('capistrano_multiconfig_parallel/extensions/**/*.rb').each { |pat
|
|
3
3
|
module CapistranoMulticonfigParallel
|
4
4
|
# this is the class that will be invoked from terminal , and willl use the invoke task as the primary function.
|
5
5
|
class CLI
|
6
|
+
# method used to start
|
6
7
|
def self.start
|
7
8
|
CapistranoMulticonfigParallel.check_terminal_tty
|
8
9
|
CapistranoMulticonfigParallel.original_args = ARGV.dup
|
9
|
-
CapistranoMulticonfigParallel::Application.new
|
10
|
+
job_manager = CapistranoMulticonfigParallel::Application.new
|
11
|
+
if job_manager.can_start?
|
12
|
+
job_manager.start
|
13
|
+
else
|
14
|
+
Capistrano::Application.new.run
|
15
|
+
end
|
10
16
|
rescue Interrupt
|
11
17
|
`stty icanon echo`
|
12
18
|
$stderr.puts 'Command cancelled.'
|
13
19
|
rescue => error
|
14
20
|
$stderr.puts error
|
21
|
+
$stderr.puts error.backtrace if error.respond_to?(:backtrace)
|
15
22
|
exit(1)
|
16
23
|
end
|
17
24
|
end
|
@@ -8,15 +8,16 @@ module CapistranoMulticonfigParallel
|
|
8
8
|
|
9
9
|
def configuration
|
10
10
|
@config ||= Configliere::Param.new
|
11
|
-
@config.use :commandline
|
12
11
|
command_line_params.each do |param|
|
13
|
-
|
12
|
+
param_type = change_config_type(param['type'].to_s)
|
13
|
+
@config.define param['name'], type: param_type, description: param['description'], default: param['default']
|
14
14
|
end
|
15
15
|
|
16
16
|
ARGV.clear
|
17
|
+
|
17
18
|
CapistranoMulticonfigParallel.original_args.each { |a| ARGV << a }
|
18
19
|
@config.read config_file if File.file?(config_file)
|
19
|
-
@config.
|
20
|
+
@config.use :commandline
|
20
21
|
|
21
22
|
@config.use :config_block
|
22
23
|
@config.finally do |c|
|
@@ -34,30 +35,14 @@ module CapistranoMulticonfigParallel
|
|
34
35
|
end
|
35
36
|
|
36
37
|
def command_line_params
|
37
|
-
@default_config ||=
|
38
|
-
@default_config
|
39
|
-
@default_config.resolve!
|
40
|
-
@default_config[:default_config].map do |item|
|
41
|
-
item[:type] = change_config_type(item[:type].to_s)
|
42
|
-
item
|
43
|
-
end
|
38
|
+
@default_config ||= YAML.load_file(File.join(internal_config_directory, 'default.yml'))['default_config']
|
39
|
+
@default_config
|
44
40
|
end
|
45
41
|
|
46
42
|
def change_config_type(type)
|
47
|
-
|
43
|
+
['boolean'].include?(type) ? type.delete(':').to_sym : type.constantize
|
48
44
|
end
|
49
45
|
|
50
|
-
def capistrano_options
|
51
|
-
command_line_params.map do |param|
|
52
|
-
[
|
53
|
-
"--#{param[:name]}[=CAP_VALUE]",
|
54
|
-
"--#{param[:name]}",
|
55
|
-
"[MULTI_CAP] #{param[:description]}. By default #{param[:default]}",
|
56
|
-
lambda do |_value|
|
57
|
-
end
|
58
|
-
]
|
59
|
-
end
|
60
|
-
end
|
61
46
|
|
62
47
|
def verify_array_of_strings(value)
|
63
48
|
return true if value.blank?
|
@@ -80,13 +65,7 @@ module CapistranoMulticonfigParallel
|
|
80
65
|
end
|
81
66
|
end
|
82
67
|
|
83
|
-
|
84
|
-
applications = stages.map { |stage| stage.split(':').reverse[1] }
|
85
|
-
wrong = configuration.application_dependencies.find do |hash|
|
86
|
-
!applications.include?(hash[:app]) || (hash[:dependencies].present? && hash[:dependencies].find { |val| !applications.include?(val) })
|
87
|
-
end
|
88
|
-
raise ArgumentError, "invalid configuration for #{wrong.inspect}" if wrong.present?
|
89
|
-
end
|
68
|
+
|
90
69
|
|
91
70
|
def check_boolean(c, prop)
|
92
71
|
raise ArgumentError, "the property `#{prop}` must be boolean" unless %w(true false).include?(c[prop].to_s.downcase)
|
@@ -94,7 +73,6 @@ module CapistranoMulticonfigParallel
|
|
94
73
|
|
95
74
|
def configuration_valid?(stages)
|
96
75
|
configuration
|
97
|
-
verify_app_dependencies(stages) if configuration.application_dependencies.present?
|
98
76
|
end
|
99
77
|
|
100
78
|
def check_boolean_props(c, props)
|
data/lib/capistrano_multiconfig_parallel/{multi_app_helpers → helpers}/dependency_tracker.rb
RENAMED
@@ -68,8 +68,8 @@ module CapistranoMulticonfigParallel
|
|
68
68
|
|
69
69
|
def check_app_dependency_unique(applications_selected, apps_dependencies, applications_to_deploy, action)
|
70
70
|
return applications_to_deploy if applications_selected.blank? || apps_dependencies.blank? || (apps_dependencies.map { |app| app['app'] } - applications_to_deploy.map { |app| app['app'] }).blank?
|
71
|
-
|
72
|
-
applications_to_deploy = applications_to_deploy.concat(apps_dependencies) if
|
71
|
+
apps_dependency_confirmation = CapistranoMulticonfigParallel.ask_confirm("Do you want to #{action} all dependencies also ?", 'Y/N')
|
72
|
+
applications_to_deploy = applications_to_deploy.concat(apps_dependencies) if apps_dependency_confirmation.present? && apps_dependency_confirmation.downcase == 'y'
|
73
73
|
applications_to_deploy
|
74
74
|
end
|
75
75
|
|
@@ -102,10 +102,10 @@ module CapistranoMulticonfigParallel
|
|
102
102
|
|
103
103
|
def print_frameworks_used(app_names, applications_to_deploy, action)
|
104
104
|
app_names.each { |app| puts "#{app}" }
|
105
|
-
|
106
|
-
if
|
105
|
+
apps_deploy_confirmation = CapistranoMulticonfigParallel.ask_confirm("Are you sure you want to #{action} these apps?", 'Y/N')
|
106
|
+
if apps_deploy_confirmation.blank? || (apps_deploy_confirmation.present? && apps_deploy_confirmation.downcase != 'y')
|
107
107
|
return []
|
108
|
-
elsif
|
108
|
+
elsif apps_deploy_confirmation.present? && apps_deploy_confirmation.downcase == 'y'
|
109
109
|
return applications_to_deploy
|
110
110
|
end
|
111
111
|
end
|
@@ -1,11 +1,10 @@
|
|
1
|
-
require 'configliere'
|
2
1
|
require 'configliere/commandline'
|
3
2
|
Configliere::Commandline.class_eval do
|
4
3
|
def resolve!(print_help_and_exit = true)
|
5
4
|
process_argv!
|
6
|
-
if print_help_and_exit && self[:
|
5
|
+
if print_help_and_exit && self[:help]
|
7
6
|
dump_help
|
8
|
-
|
7
|
+
# exit(2)
|
9
8
|
end
|
10
9
|
super()
|
11
10
|
self
|
@@ -1,18 +1,18 @@
|
|
1
1
|
default_config:
|
2
2
|
- name: 'multi_debug'
|
3
|
-
type: '
|
3
|
+
type: 'boolean'
|
4
4
|
description: >-
|
5
5
|
Enable debugging of workers, CAP_VALUE can be true or false
|
6
6
|
default: TRUE
|
7
7
|
|
8
8
|
- name: 'multi_secvential'
|
9
|
-
type: '
|
9
|
+
type: 'boolean'
|
10
10
|
description: >-
|
11
11
|
Forces execution of jobs in sequence, CAP_VALUE can be true or false
|
12
12
|
default: false
|
13
13
|
|
14
14
|
- name: 'websocket_server.enable_debug'
|
15
|
-
type: '
|
15
|
+
type: 'boolean'
|
16
16
|
description: >-
|
17
17
|
Enables debugging of websocket communication between the workers,
|
18
18
|
CAP_VALUE can be true or false
|