capistrano_multiconfig_parallel 0.15.6 → 0.16.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 +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
|