capistrano_multiconfig_parallel 1.7.2 → 2.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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}")
|