capistrano_multiconfig_parallel 1.7.2 → 2.0.0.beta1
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/Gemfile +0 -2
- data/README.md +38 -36
- data/V1_README.md +351 -0
- data/capistrano_multiconfig_parallel.gemspec +5 -8
- data/lib/capistrano_multiconfig_parallel/all.rb +3 -7
- data/lib/capistrano_multiconfig_parallel/application.rb +10 -5
- data/lib/capistrano_multiconfig_parallel/base.rb +11 -11
- data/lib/capistrano_multiconfig_parallel/celluloid/celluloid_manager.rb +3 -2
- data/lib/capistrano_multiconfig_parallel/celluloid/celluloid_worker.rb +32 -20
- data/lib/capistrano_multiconfig_parallel/celluloid/child_process.rb +3 -0
- data/lib/capistrano_multiconfig_parallel/celluloid/state_machine.rb +21 -14
- data/lib/capistrano_multiconfig_parallel/celluloid/terminal_table.rb +4 -3
- data/lib/capistrano_multiconfig_parallel/classes/cursor.rb +6 -2
- data/lib/capistrano_multiconfig_parallel/classes/dependency_tracker.rb +1 -1
- data/lib/capistrano_multiconfig_parallel/classes/job.rb +38 -13
- data/lib/capistrano_multiconfig_parallel/classes/job_command.rb +154 -15
- data/lib/capistrano_multiconfig_parallel/cli.rb +10 -26
- data/lib/capistrano_multiconfig_parallel/configuration/default.yml +1 -1
- data/lib/capistrano_multiconfig_parallel/helpers/application_helper.rb +26 -2
- data/lib/capistrano_multiconfig_parallel/helpers/capistrano_helper.rb +1 -1
- data/lib/capistrano_multiconfig_parallel/helpers/configuration.rb +3 -3
- data/lib/capistrano_multiconfig_parallel/helpers/gem_helper.rb +2 -1
- data/lib/capistrano_multiconfig_parallel/helpers/internal_helper.rb +18 -2
- data/lib/capistrano_multiconfig_parallel/version.rb +5 -4
- metadata +20 -60
- data/lib/capistrano_multiconfig_parallel/celluloid/rake_worker.rb +0 -132
- data/lib/capistrano_multiconfig_parallel/classes/input_stream.rb +0 -34
- data/lib/capistrano_multiconfig_parallel/classes/output_stream.rb +0 -33
- data/lib/capistrano_multiconfig_parallel/classes/rake_task_hooks.rb +0 -88
- data/lib/capistrano_multiconfig_parallel/initializers/capistrano2.rb +0 -37
- data/lib/capistrano_multiconfig_parallel/initializers/rake.rb +0 -11
- data/lib/capistrano_multiconfig_parallel/initializers/websocket.rb +0 -19
@@ -1,6 +1,5 @@
|
|
1
1
|
# base module that has the statis methods that this gem is using
|
2
2
|
module CapistranoMulticonfigParallel
|
3
|
-
ENV_KEY_JOB_ID = 'multi_cap_job_id'
|
4
3
|
GITFLOW_TAG_STAGING_TASK = 'gitflow:tag_staging'
|
5
4
|
GITFLOW_CALCULATE_TAG_TASK = 'gitflow:calculate_tag'
|
6
5
|
GITFLOW_VERIFY_UPTODATE_TASK = 'gitflow:verify_up_to_date'
|
@@ -15,6 +14,10 @@ module CapistranoMulticonfigParallel
|
|
15
14
|
@config
|
16
15
|
end
|
17
16
|
|
17
|
+
def env_job_key_id
|
18
|
+
CapistranoSentinel::RequestHooks::ENV_KEY_JOB_ID
|
19
|
+
end
|
20
|
+
|
18
21
|
def configuration_flags
|
19
22
|
default_internal_config.each_with_object({}) do |array_item, hash|
|
20
23
|
key = array_item[0].to_s
|
@@ -29,21 +32,18 @@ module CapistranoMulticonfigParallel
|
|
29
32
|
set_celluloid_exception_handling
|
30
33
|
end
|
31
34
|
|
32
|
-
def job_id
|
33
|
-
original_args_hash.fetch(CapistranoMulticonfigParallel::ENV_KEY_JOB_ID, nil)
|
34
|
-
end
|
35
|
-
|
36
35
|
def original_args_hash
|
37
36
|
multi_fetch_argv((original_args || ARGV).dup)
|
38
37
|
end
|
39
38
|
|
40
|
-
def capistrano_version
|
41
|
-
|
42
|
-
end
|
39
|
+
# def capistrano_version
|
40
|
+
# find_loaded_gem_property('capistrano', 'version')
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# def capistrano_version_2?
|
44
|
+
# capistrano_version.blank? ? false : verify_gem_version(capistrano_version, '3.0', operator: '<')
|
45
|
+
# end
|
43
46
|
|
44
|
-
def capistrano_version_2?
|
45
|
-
capistrano_version.blank? ? false : verify_gem_version(capistrano_version, '3.0', operator: '<')
|
46
|
-
end
|
47
47
|
|
48
48
|
private
|
49
49
|
|
@@ -6,7 +6,7 @@ module CapistranoMulticonfigParallel
|
|
6
6
|
# manager class that handles workers
|
7
7
|
class CelluloidManager
|
8
8
|
include CapistranoMulticonfigParallel::BaseActorHelper
|
9
|
-
|
9
|
+
attr_accessor :jobs, :job_to_worker, :worker_to_job, :job_to_condition, :mutex, :registration_complete, :workers_terminated, :stderr_buffer
|
10
10
|
|
11
11
|
attr_reader :worker_supervisor, :workers
|
12
12
|
trap_exit :worker_died
|
@@ -26,10 +26,10 @@ module CapistranoMulticonfigParallel
|
|
26
26
|
Actor.current.link @workers
|
27
27
|
setup_actor_supervision(@worker_supervisor, actor_name: :terminal_server, type: CapistranoMulticonfigParallel::TerminalTable, args: [Actor.current, @job_manager, configuration.fetch(:terminal, {})])
|
28
28
|
setup_actor_supervision(@worker_supervisor, actor_name: :web_server, type: CapistranoMulticonfigParallel::WebServer, args: websocket_config)
|
29
|
-
|
30
29
|
# Get a handle on the PoolManager
|
31
30
|
# http://rubydoc.info/gems/celluloid/Celluloid/PoolManager
|
32
31
|
# @workers = workers_pool.actor
|
32
|
+
|
33
33
|
@stderr_buffer = StringIO.new
|
34
34
|
@conditions = []
|
35
35
|
@jobs = {}
|
@@ -221,6 +221,7 @@ module CapistranoMulticonfigParallel
|
|
221
221
|
def worker_died(worker, reason)
|
222
222
|
job = @worker_to_job[worker.mailbox.address]
|
223
223
|
return true if job.blank? || job.rolling_back? || job.action != 'deploy'
|
224
|
+
job.rollback_changes_to_application
|
224
225
|
mailbox = worker.mailbox
|
225
226
|
@worker_to_job.delete(mailbox.address)
|
226
227
|
log_to_file("RESTARTING: worker job #{job.inspect} with mailbox #{mailbox.inspect} and #{mailbox.address.inspect} died for reason: #{reason}")
|
@@ -20,10 +20,10 @@ module CapistranoMulticonfigParallel
|
|
20
20
|
include CapistranoMulticonfigParallel::BaseActorHelper
|
21
21
|
class TaskFailed < StandardError; end
|
22
22
|
|
23
|
-
attr_accessor :job, :manager, :job_id, :app_name, :env_name, :action_name, :env_options, :machine, :
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
attr_accessor :job, :manager, :job_id, :app_name, :env_name, :action_name, :env_options, :machine, :socket_connection, :task_argv,
|
24
|
+
:rake_tasks, :current_task_number, # tracking tasks
|
25
|
+
:successfull_subscription, :subscription_channel, :publisher_channel, # for subscriptions and publishing events
|
26
|
+
:job_termination_condition, :worker_state, :invocation_chain, :filename, :worker_log, :exit_status
|
27
27
|
|
28
28
|
def initialize(*args)
|
29
29
|
end
|
@@ -35,12 +35,13 @@ module CapistranoMulticonfigParallel
|
|
35
35
|
@manager = manager
|
36
36
|
@job_confirmation_conditions = []
|
37
37
|
log_to_file("worker #{@job_id} received #{job.inspect}")
|
38
|
-
@subscription_channel = "
|
38
|
+
@subscription_channel = "#{CapistranoSentinel::RequestHooks::PUBLISHER_PREFIX}#{@job_id}"
|
39
39
|
@machine = CapistranoMulticonfigParallel::StateMachine.new(@job, Actor.current)
|
40
40
|
@manager.setup_worker_conditions(@job)
|
41
41
|
manager.register_worker_for_job(job, Actor.current)
|
42
42
|
end
|
43
43
|
|
44
|
+
|
44
45
|
def worker_state
|
45
46
|
if Actor.current.alive?
|
46
47
|
@machine.state.to_s.green
|
@@ -51,21 +52,18 @@ module CapistranoMulticonfigParallel
|
|
51
52
|
end
|
52
53
|
|
53
54
|
def start_task
|
54
|
-
log_to_file("exec worker #{@job_id} starts task")
|
55
|
-
@
|
55
|
+
log_to_file("exec worker #{@job_id} starts task and subscribes to #{@subscription_channel}")
|
56
|
+
@socket_connection = CelluloidPubsub::Client.new(actor: Actor.current, enable_debug: debug_websocket?, channel: subscription_channel, log_file_path: websocket_config.fetch('log_file_path', nil))
|
56
57
|
end
|
57
58
|
|
58
59
|
def publish_rake_event(data)
|
59
|
-
@
|
60
|
-
|
61
|
-
|
62
|
-
def rake_actor_id(_data)
|
63
|
-
"rake_worker_#{@job_id}"
|
60
|
+
log_to_file("worker #{@job_id} rties to publish into channel #{CapistranoSentinel::RequestHooks::SUBSCRIPTION_PREFIX}#{@job_id} data #{data.inspect}")
|
61
|
+
@socket_connection.publish("#{CapistranoSentinel::RequestHooks::SUBSCRIPTION_PREFIX}#{@job_id}", data)
|
64
62
|
end
|
65
63
|
|
66
64
|
def on_message(message)
|
67
65
|
log_to_file("worker #{@job_id} received: #{message.inspect}")
|
68
|
-
if @
|
66
|
+
if @socket_connection.succesfull_subscription?(message)
|
69
67
|
@successfull_subscription = true
|
70
68
|
execute_after_succesfull_subscription
|
71
69
|
else
|
@@ -89,7 +87,8 @@ module CapistranoMulticonfigParallel
|
|
89
87
|
def execute_deploy
|
90
88
|
log_to_file("invocation chain #{@job_id} is : #{@rake_tasks.inspect}")
|
91
89
|
check_child_proces
|
92
|
-
|
90
|
+
job.command.prepare_application_for_deployment
|
91
|
+
command = job.command.fetch_deploy_command
|
93
92
|
log_to_file("worker #{@job_id} executes: #{command}")
|
94
93
|
@child_process.async.work(@job, command, actor: Actor.current, silent: true)
|
95
94
|
end
|
@@ -98,7 +97,7 @@ module CapistranoMulticonfigParallel
|
|
98
97
|
@child_process = CapistranoMulticonfigParallel::ChildProcess.new
|
99
98
|
Actor.current.link @child_process
|
100
99
|
@child_process
|
101
|
-
|
100
|
+
end
|
102
101
|
|
103
102
|
def on_close(code, reason)
|
104
103
|
log_to_file("worker #{@job_id} websocket connection closed: #{code.inspect}, #{reason.inspect}")
|
@@ -119,18 +118,29 @@ module CapistranoMulticonfigParallel
|
|
119
118
|
elsif message_is_for_stdout?(message)
|
120
119
|
result = Celluloid::Actor[:terminal_server].show_confirmation(message['question'], message['default'])
|
121
120
|
publish_rake_event(message.merge('action' => 'stdin', 'result' => result, 'client_action' => 'stdin'))
|
121
|
+
elsif message_from_bundler?(message)
|
122
|
+
|
123
|
+
#gem_messsage = job.gem_specs.find{|spec| message['task'].include?(spec.name) }
|
124
|
+
# if gem_messsage.present?
|
125
|
+
# async.update_machine_state("insta")
|
126
|
+
# else
|
127
|
+
async.update_machine_state(message['task'])
|
128
|
+
#end
|
122
129
|
else
|
123
|
-
log_to_file(message, @job_id)
|
130
|
+
log_to_file(message, job_id: @job_id)
|
124
131
|
end
|
125
132
|
end
|
126
133
|
|
134
|
+
|
127
135
|
def executed_task?(task)
|
128
136
|
rake_tasks.present? && rake_tasks.index(task.to_s).present?
|
129
137
|
end
|
130
138
|
|
131
139
|
def task_approval(message)
|
132
140
|
job_conditions = @manager.job_to_condition[@job_id]
|
141
|
+
log_to_file("worker #{@job_id} checks if task : #{message['task'].inspect} is included in #{configuration.task_confirmations.inspect}")
|
133
142
|
if job_conditions.present? && configuration.task_confirmations.include?(message['task']) && message['action'] == 'invoke'
|
143
|
+
log_to_file("worker #{@job_id} signals approval for task : #{message['task'].inspect}")
|
134
144
|
task_confirmation = job_conditions[message['task']]
|
135
145
|
task_confirmation[:status] = 'confirmed'
|
136
146
|
task_confirmation[:condition].signal(message['task'])
|
@@ -145,15 +155,17 @@ module CapistranoMulticonfigParallel
|
|
145
155
|
invocation_chain << message['task'] if invocation_chain.last != message['task']
|
146
156
|
end
|
147
157
|
|
148
|
-
def update_machine_state(name)
|
149
|
-
log_to_file("worker #{@job_id} triest to transition from #{@machine.state} to #{name}")
|
150
|
-
@machine.go_to_transition(name.to_s)
|
158
|
+
def update_machine_state(name, options = {})
|
159
|
+
log_to_file("worker #{@job_id} triest to transition from #{@machine.state} to #{name}") unless options[:bundler]
|
160
|
+
@machine.go_to_transition(name.to_s, options)
|
151
161
|
error_message = "worker #{@job_id} task #{name} failed "
|
152
162
|
raise(CapistranoMulticonfigParallel::CelluloidWorker::TaskFailed.new(error_message), error_message) if job.failed? # force worker to rollback
|
153
163
|
end
|
154
164
|
|
155
165
|
def send_msg(channel, message = nil)
|
156
|
-
|
166
|
+
message = message.present? && message.is_a?(Hash) ? { job_id: @job_id }.merge(message) : { job_id: @job_id, message: message }
|
167
|
+
log_to_file("worker #{@job_id} triest to send to #{channel} #{message}")
|
168
|
+
publish channel, message
|
157
169
|
end
|
158
170
|
|
159
171
|
def finish_worker(exit_status)
|
@@ -25,6 +25,7 @@ module CapistranoMulticonfigParallel
|
|
25
25
|
@actor = @options.fetch(:actor, nil)
|
26
26
|
@job_id = @job.id
|
27
27
|
@exit_status = nil
|
28
|
+
@show_bundler = true
|
28
29
|
end
|
29
30
|
|
30
31
|
def setup_em_error_handler
|
@@ -96,6 +97,8 @@ module CapistranoMulticonfigParallel
|
|
96
97
|
end
|
97
98
|
|
98
99
|
def on_read_stdout(data)
|
100
|
+
@show_bundler = false if data.to_s.include?("The Gemfile's dependencies are satisfied") || data.to_s.include?("Bundle complete")
|
101
|
+
@actor.async.update_machine_state(truncate(data, 40), :bundler => true) if @show_bundler == true && data.strip.present? && data.strip != '.'
|
99
102
|
io_callback('stdout', data)
|
100
103
|
end
|
101
104
|
|
@@ -11,15 +11,21 @@ module CapistranoMulticonfigParallel
|
|
11
11
|
machine
|
12
12
|
end
|
13
13
|
|
14
|
-
def go_to_transition(action)
|
14
|
+
def go_to_transition(action, options = {})
|
15
15
|
transitions.on(action, state.to_s => action)
|
16
16
|
@job.status = action
|
17
|
-
|
17
|
+
if options[:bundler]
|
18
|
+
@job.bundler_status = action
|
19
|
+
actor_notify_state_change(state, "preparing_app_bundle_install", action)
|
20
|
+
else
|
21
|
+
@job.bundler_status = nil
|
22
|
+
machine.trigger(action)
|
23
|
+
end
|
18
24
|
end
|
19
25
|
|
20
26
|
def machine
|
21
27
|
@machine ||= ComposableStateMachine::MachineWithExternalState.new(
|
22
|
-
|
28
|
+
model, method(:state), method(:state=), state: @initial_state.to_s, callback_runner: self)
|
23
29
|
@machine
|
24
30
|
end
|
25
31
|
|
@@ -30,23 +36,24 @@ module CapistranoMulticonfigParallel
|
|
30
36
|
|
31
37
|
def model
|
32
38
|
ComposableStateMachine.model(
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
transitions: transitions,
|
40
|
+
behaviors: {
|
41
|
+
enter: {
|
42
|
+
any: proc do |current_state, event, new_state|
|
43
|
+
actor_notify_state_change(current_state, event, new_state)
|
44
|
+
end
|
45
|
+
}
|
46
|
+
},
|
47
|
+
initial_state: @initial_state
|
42
48
|
)
|
43
49
|
end
|
44
50
|
|
45
|
-
|
51
|
+
private
|
46
52
|
|
47
53
|
def actor_notify_state_change(current_state, event, new_state)
|
48
54
|
return unless @actor.alive?
|
49
|
-
@actor.
|
55
|
+
@actor.log_to_file("statemachine #{@job.id} triest to transition from #{@current_state} to #{new_state} for event #{event}")
|
56
|
+
@actor.async.send_msg(CapistranoMulticonfigParallel::TerminalTable.topic, type: 'event', new_state: new_state , current_state: current_state, event: event, message: "Going from #{current_state} to #{new_state} due to a #{event} event")
|
50
57
|
end
|
51
58
|
end
|
52
59
|
end
|
@@ -28,6 +28,7 @@ module CapistranoMulticonfigParallel
|
|
28
28
|
@screen_erased = false
|
29
29
|
async.run
|
30
30
|
rescue => ex
|
31
|
+
puts ex.inspect
|
31
32
|
rescue_exception(ex)
|
32
33
|
end
|
33
34
|
|
@@ -39,7 +40,7 @@ module CapistranoMulticonfigParallel
|
|
39
40
|
subscribe(CapistranoMulticonfigParallel::TerminalTable.topic, :notify_time_change)
|
40
41
|
end
|
41
42
|
|
42
|
-
def notify_time_change(_channel,
|
43
|
+
def notify_time_change(_channel, message)
|
43
44
|
table = Terminal::Table.new(title: 'Deployment Status Table', headings: default_heaadings)
|
44
45
|
jobs = setup_table_jobs(table)
|
45
46
|
display_table_on_terminal(table, jobs)
|
@@ -90,12 +91,12 @@ module CapistranoMulticonfigParallel
|
|
90
91
|
end
|
91
92
|
|
92
93
|
def managers_alive?
|
93
|
-
|
94
|
+
@manager.alive?
|
94
95
|
end
|
95
96
|
|
96
97
|
def signal_complete
|
97
98
|
if managers_alive? && @manager.all_workers_finished? && workers_terminated.instance_variable_get("@waiters").blank?
|
98
|
-
condition.signal('completed') if
|
99
|
+
condition.signal('completed') if condition.instance_variable_get("@waiters").present?
|
99
100
|
elsif !managers_alive?
|
100
101
|
terminate
|
101
102
|
end
|
@@ -6,8 +6,12 @@ module CapistranoMulticonfigParallel
|
|
6
6
|
include CapistranoMulticonfigParallel::ApplicationHelper
|
7
7
|
|
8
8
|
def display_on_screen(string, options = {})
|
9
|
-
|
10
|
-
|
9
|
+
begin
|
10
|
+
options = options.is_a?(Hash) ? options.stringify_keys : {}
|
11
|
+
handle_string_display(string, options)
|
12
|
+
rescue => ex
|
13
|
+
rescue_error(ex, 'stderr')
|
14
|
+
end
|
11
15
|
end
|
12
16
|
|
13
17
|
private
|
@@ -11,7 +11,7 @@ module CapistranoMulticonfigParallel
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def fetch_apps_needed_for_deployment(application, action)
|
14
|
-
return [[], {}] unless @job_manager.multi_apps?
|
14
|
+
return [[], {}] unless @job_manager.send(:multi_apps?)
|
15
15
|
if @job_manager.custom_command?
|
16
16
|
show_interactive_menu(action)
|
17
17
|
else
|
@@ -5,18 +5,21 @@ module CapistranoMulticonfigParallel
|
|
5
5
|
class Job
|
6
6
|
include CapistranoMulticonfigParallel::ApplicationHelper
|
7
7
|
|
8
|
-
attr_reader :options, :application, :manager
|
9
|
-
attr_writer :status, :exit_status
|
8
|
+
attr_reader :options, :application, :manager, :bundler_status
|
9
|
+
attr_writer :status, :exit_status, :bundler_status
|
10
10
|
|
11
11
|
delegate :job_stage,
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
:capistrano_action,
|
13
|
+
:execute_standard_deploy,
|
14
|
+
:setup_command_line,
|
15
|
+
:job_capistrano_version,
|
16
|
+
:gem_specs,
|
17
|
+
:job_stage_for_terminal,
|
18
|
+
:rollback_changes_to_application,
|
19
|
+
to: :command
|
17
20
|
|
18
21
|
delegate :stderr_buffer,
|
19
|
-
|
22
|
+
to: :manager
|
20
23
|
|
21
24
|
def initialize(application, options)
|
22
25
|
@options = options.stringify_keys
|
@@ -25,6 +28,7 @@ module CapistranoMulticonfigParallel
|
|
25
28
|
@gitflow ||= command.gitflow_enabled?
|
26
29
|
end
|
27
30
|
|
31
|
+
|
28
32
|
def save_stderr_error(data)
|
29
33
|
return unless development_debug?
|
30
34
|
return unless @manager.alive?
|
@@ -35,7 +39,7 @@ module CapistranoMulticonfigParallel
|
|
35
39
|
end
|
36
40
|
|
37
41
|
def env_variable
|
38
|
-
CapistranoMulticonfigParallel
|
42
|
+
CapistranoMulticonfigParallel.env_job_key_id
|
39
43
|
end
|
40
44
|
|
41
45
|
def command
|
@@ -47,12 +51,27 @@ module CapistranoMulticonfigParallel
|
|
47
51
|
end
|
48
52
|
|
49
53
|
def terminal_row
|
54
|
+
if bundler_status
|
55
|
+
bundler_terminal_row
|
56
|
+
else
|
57
|
+
[
|
58
|
+
{ value: id.to_s },
|
59
|
+
{ value: wrap_string(job_stage_for_terminal) },
|
60
|
+
{ value: wrap_string(capistrano_action) },
|
61
|
+
{ value: terminal_env_variables.map { |str| wrap_string(str) }.join("\n") },
|
62
|
+
{ value: wrap_string(worker_state) }
|
63
|
+
]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def bundler_terminal_row
|
50
69
|
[
|
51
70
|
{ value: id.to_s },
|
52
|
-
{ value: wrap_string(
|
53
|
-
{ value:
|
71
|
+
{ value: wrap_string(job_stage_for_terminal) },
|
72
|
+
{ value: "Preparing app...setting up gems" },
|
54
73
|
{ value: terminal_env_variables.map { |str| wrap_string(str) }.join("\n") },
|
55
|
-
{ value: wrap_string(
|
74
|
+
{ value: wrap_string(status.to_s.green) }
|
56
75
|
]
|
57
76
|
end
|
58
77
|
|
@@ -90,12 +109,18 @@ module CapistranoMulticonfigParallel
|
|
90
109
|
].each do |hash|
|
91
110
|
define_method hash[:name] do
|
92
111
|
value = @options.fetch(hash[:name], hash[:default])
|
93
|
-
value
|
112
|
+
setup_additional_env_variables(value) if hash[:name] == 'env_options'
|
94
113
|
value = verify_empty_options(value)
|
95
114
|
instance_variable_set("@#{hash[:name]}", instance_variable_get("@#{hash[:name]}") || value)
|
96
115
|
end
|
97
116
|
end
|
98
117
|
|
118
|
+
|
119
|
+
def setup_additional_env_variables(value)
|
120
|
+
value["#{env_variable}"] = id
|
121
|
+
value["capistrano_version"] = job_capistrano_version
|
122
|
+
end
|
123
|
+
|
99
124
|
def finished?
|
100
125
|
status == 'finished'
|
101
126
|
end
|
@@ -6,7 +6,7 @@ module CapistranoMulticonfigParallel
|
|
6
6
|
include FileUtils
|
7
7
|
include CapistranoMulticonfigParallel::ApplicationHelper
|
8
8
|
|
9
|
-
attr_reader :job, :job_capistrano_version, :legacy_capistrano
|
9
|
+
attr_reader :job, :job_capistrano_version, :legacy_capistrano, :tempfile
|
10
10
|
delegate :id, :app, :stage, :action, :task_arguments, :env_options, :path, to: :job
|
11
11
|
|
12
12
|
def initialize(job)
|
@@ -43,15 +43,29 @@ module CapistranoMulticonfigParallel
|
|
43
43
|
%w(STAGES ACTION)
|
44
44
|
end
|
45
45
|
|
46
|
-
def bundle_gemfile_env
|
47
|
-
"BUNDLE_GEMFILE=#{
|
46
|
+
def bundle_gemfile_env(gemfile = job_gemfile)
|
47
|
+
"BUNDLE_GEMFILE=#{gemfile}"
|
48
48
|
end
|
49
49
|
|
50
|
+
|
50
51
|
def gitflow_enabled?
|
51
|
-
|
52
|
+
gitflow_version = job_gem_version("capistrano-gitflow")
|
52
53
|
gitflow_version.present? ? true : false
|
53
54
|
end
|
54
55
|
|
56
|
+
def request_handler_gem_name
|
57
|
+
"capistrano_sentinel"
|
58
|
+
end
|
59
|
+
|
60
|
+
def request_handler_gem_available?
|
61
|
+
gitflow_version = job_gem_version(request_handler_gem_name)
|
62
|
+
gitflow_version.present? ? true : false
|
63
|
+
end
|
64
|
+
|
65
|
+
def job_stage_for_terminal
|
66
|
+
app.present? ? "#{app}:#{stage}" : "#{stage}"
|
67
|
+
end
|
68
|
+
|
55
69
|
def job_stage
|
56
70
|
multi_apps?(job_path) && app.present? ? "#{app}:#{stage}" : "#{stage}"
|
57
71
|
end
|
@@ -96,29 +110,154 @@ module CapistranoMulticonfigParallel
|
|
96
110
|
path || detect_root
|
97
111
|
end
|
98
112
|
|
99
|
-
def
|
100
|
-
|
101
|
-
|
113
|
+
def user_home_directory
|
114
|
+
user = Etc.getlogin
|
115
|
+
Dir.home(user)
|
116
|
+
end
|
117
|
+
|
118
|
+
def rvm_bin_path
|
119
|
+
@rvm_path ||= `which rvm`
|
102
120
|
end
|
103
121
|
|
104
|
-
def
|
105
|
-
|
106
|
-
environment_options = setup_command_line(config_flags).join(' ')
|
107
|
-
"#{command_prefix} && #{bundle_gemfile_env} bundle exec multi_cap #{job_stage} #{capistrano_action} #{environment_options}"
|
122
|
+
def bash_bin_path
|
123
|
+
@bash_bin_path ||= `which bash`
|
108
124
|
end
|
109
125
|
|
110
|
-
def
|
111
|
-
|
126
|
+
def rvm_installed?
|
127
|
+
rvm_bin_path.present?
|
128
|
+
end
|
129
|
+
|
130
|
+
def create_job_tempfile_command(output)
|
131
|
+
@tempfile ||= Tempfile.new(["multi_cap_#{job.id}_command_", ".rb"], encoding: 'utf-8')
|
132
|
+
@tempfile.write(output)
|
133
|
+
ObjectSpace.undefine_finalizer(@tempfile) # force garbage collector not to remove automatically the file
|
134
|
+
@tempfile.close
|
135
|
+
end
|
136
|
+
|
137
|
+
def rvm_scripts_path
|
138
|
+
File.join(File.dirname(File.dirname(rvm_bin_path)), 'scripts', 'rvm')
|
139
|
+
end
|
140
|
+
|
141
|
+
def job_rvmrc_file
|
142
|
+
File.join(job_path, '.rvmrc')
|
143
|
+
end
|
144
|
+
|
145
|
+
def job_rvmrc_enabled?
|
146
|
+
File.exists?(job_rvmrc_file)
|
147
|
+
end
|
148
|
+
|
149
|
+
def rvm_enabled_for_job?
|
150
|
+
job_rvmrc_enabled? && rvm_installed? && bash_bin_path.present?
|
151
|
+
end
|
152
|
+
|
153
|
+
def check_rvm_loaded
|
154
|
+
return "cd #{job_path}" unless rvm_enabled_for_job?
|
155
|
+
"source #{rvm_scripts_path} && rvm rvmrc trust #{job_path} && cd #{job_path} && source #{job_rvmrc_file}"
|
156
|
+
end
|
157
|
+
|
158
|
+
def fetch_deploy_command
|
159
|
+
# config_flags = CapistranoMulticonfigParallel.configuration_flags.merge("capistrano_version": job_capistrano_version)
|
160
|
+
environment_options = setup_command_line.join(' ')
|
161
|
+
command = "#{check_rvm_loaded} && if [ `which bundler |wc -l` = 0 ]; then gem install bundler;fi && (#{bundle_gemfile_env(job_gemfile_multi)} bundle check || #{bundle_gemfile_env(job_gemfile_multi)} bundle install ) && WEBSOCKET_LOGGING=#{debug_websocket?} LOG_FILE=#{websocket_config.fetch('log_file_path', nil)} #{bundle_gemfile_env(job_gemfile_multi)} bundle exec cap #{job_stage} #{capistrano_action} #{environment_options}"
|
162
|
+
|
163
|
+
command = "bash --login -c '#{command}'" if rvm_enabled_for_job?
|
164
|
+
command = command.inspect
|
165
|
+
|
166
|
+
command_text =<<-CMD
|
167
|
+
require 'rubygems'
|
168
|
+
require 'bundler'
|
169
|
+
Bundler.with_clean_env {
|
170
|
+
ENV['BUNDLE_GEMFILE'] = '#{job_gemfile_multi}'
|
171
|
+
ENV['#{CapistranoSentinel::RequestHooks::ENV_KEY_JOB_ID}']='#{job.id}'
|
172
|
+
Kernel.exec(#{command})
|
173
|
+
}
|
174
|
+
CMD
|
175
|
+
|
176
|
+
if rvm_enabled_for_job?
|
177
|
+
create_job_tempfile_command(command_text)
|
178
|
+
"ruby #{@tempfile.path}"
|
179
|
+
else
|
180
|
+
<<-CMD
|
181
|
+
cd #{job_path} && bundle exec ruby -e "#{command_text}"
|
182
|
+
CMD
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
def job_capfile
|
188
|
+
File.join(job_path, "Capfile")
|
189
|
+
end
|
190
|
+
|
191
|
+
def job_gemfile_multi
|
192
|
+
File.join(job_path, "Gemfile.multi_cap")
|
193
|
+
end
|
194
|
+
|
195
|
+
def prepare_application_for_deployment
|
196
|
+
check_handler_available
|
197
|
+
prepare_capfile
|
198
|
+
end
|
199
|
+
|
200
|
+
def check_handler_available
|
201
|
+
# '#{find_loaded_gem_property(request_handler_gem_name)}'
|
202
|
+
# path: '/home/raul/workspace/github/capistrano_sentinel'
|
203
|
+
FileUtils.rm_rf(job_gemfile_multi) if File.exists?(job_gemfile_multi)
|
204
|
+
FileUtils.touch(job_gemfile_multi)
|
205
|
+
if request_handler_gem_available?
|
206
|
+
FileUtils.copy(File.join(job_path, 'Gemfile'), job_gemfile_multi)
|
207
|
+
else
|
208
|
+
File.open(job_gemfile_multi, 'w') do |f|
|
209
|
+
cmd=<<-CMD
|
210
|
+
source "https://rubygems.org" do
|
211
|
+
gem "#{request_handler_gem_name}", '#{find_loaded_gem_property(request_handler_gem_name)}'
|
212
|
+
end
|
213
|
+
instance_eval(File.read(File.dirname(__FILE__) + "/Gemfile"))
|
214
|
+
CMD
|
215
|
+
f.write(cmd)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
FileUtils.copy(File.join(job_path, 'Gemfile.lock'), "#{job_gemfile_multi}.lock")
|
219
|
+
end
|
220
|
+
|
221
|
+
def prepare_capfile
|
222
|
+
return if File.foreach(job_capfile).grep(/#{request_handler_gem_name}/).any?
|
223
|
+
File.open(job_capfile, 'a+') do |f|
|
224
|
+
cmd=<<-CMD
|
225
|
+
require "#{request_handler_gem_name}"
|
226
|
+
CMD
|
227
|
+
f.write(cmd)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
|
232
|
+
def rollback_changes_to_application
|
233
|
+
FileUtils.rm_rf(job_gemfile_multi)
|
234
|
+
FileUtils.rm_rf("#{job_gemfile_multi}.lock")
|
235
|
+
unless request_handler_gem_available?
|
236
|
+
File.open(job_capfile, 'r') do |f|
|
237
|
+
File.open("#{job_capfile}.tmp", 'w') do |f2|
|
238
|
+
f.each_line do |line|
|
239
|
+
f2.write(line) unless line.include?(request_handler_gem_name)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
FileUtils.mv "#{job_capfile}.tmp", job_capfile
|
244
|
+
FileUtils.rm_rf("#{job_capfile}.tmp")
|
245
|
+
end
|
246
|
+
FileUtils.rm_rf(@tempfile.path) if defined?(@tempfile) && @tempfile
|
112
247
|
end
|
113
248
|
|
114
249
|
def execute_standard_deploy(action = nil)
|
115
|
-
run_shell_command(
|
250
|
+
run_shell_command(fetch_deploy_command)
|
116
251
|
rescue => ex
|
117
252
|
rescue_error(ex, 'stderr')
|
118
253
|
execute_standard_deploy('deploy:rollback') if action.blank? && @name == 'deploy'
|
119
254
|
end
|
120
255
|
|
121
|
-
|
256
|
+
private
|
257
|
+
|
258
|
+
def get_bash_command(command)
|
259
|
+
Shellwords.escape(command)
|
260
|
+
end
|
122
261
|
|
123
262
|
def run_shell_command(command)
|
124
263
|
sh("#{command}")
|