capistrano_multiconfig_parallel 0.0.1
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 +7 -0
- data/.coveralls.yml +2 -0
- data/.gitignore +21 -0
- data/.rspec +1 -0
- data/.rubocop.yml +68 -0
- data/.travis.yml +12 -0
- data/CONTRIBUTING.md +44 -0
- data/Gemfile +3 -0
- data/Guardfile +12 -0
- data/LICENSE +20 -0
- data/README.md +220 -0
- data/Rakefile +56 -0
- data/bin/multi_cap +7 -0
- data/capistrano_multiconfig_parallel.gemspec +51 -0
- data/img/parallel_demo.png +0 -0
- data/init.rb +1 -0
- data/lib/capistrano_multiconfig_parallel/application.rb +57 -0
- data/lib/capistrano_multiconfig_parallel/base.rb +92 -0
- data/lib/capistrano_multiconfig_parallel/celluloid/celluloid_manager.rb +178 -0
- data/lib/capistrano_multiconfig_parallel/celluloid/celluloid_worker.rb +238 -0
- data/lib/capistrano_multiconfig_parallel/celluloid/child_process.rb +104 -0
- data/lib/capistrano_multiconfig_parallel/celluloid/rake_worker.rb +83 -0
- data/lib/capistrano_multiconfig_parallel/celluloid/state_machine.rb +49 -0
- data/lib/capistrano_multiconfig_parallel/celluloid/terminal_table.rb +122 -0
- data/lib/capistrano_multiconfig_parallel/cli.rb +55 -0
- data/lib/capistrano_multiconfig_parallel/configuration.rb +70 -0
- data/lib/capistrano_multiconfig_parallel/helpers/base_manager.rb +217 -0
- data/lib/capistrano_multiconfig_parallel/helpers/multi_app_manager.rb +84 -0
- data/lib/capistrano_multiconfig_parallel/helpers/single_app_manager.rb +48 -0
- data/lib/capistrano_multiconfig_parallel/helpers/standard_deploy.rb +40 -0
- data/lib/capistrano_multiconfig_parallel/initializers/conf.rb +6 -0
- data/lib/capistrano_multiconfig_parallel/initializers/confirm_question.rb +25 -0
- data/lib/capistrano_multiconfig_parallel/initializers/i18n.rb +10 -0
- data/lib/capistrano_multiconfig_parallel/initializers/rake.rb +28 -0
- data/lib/capistrano_multiconfig_parallel/multi_app_helpers/dependency_tracker.rb +111 -0
- data/lib/capistrano_multiconfig_parallel/multi_app_helpers/interactive_menu.rb +61 -0
- data/lib/capistrano_multiconfig_parallel/version.rb +16 -0
- data/lib/capistrano_multiconfig_parallel.rb +2 -0
- data/spec/spec_helper.rb +48 -0
- metadata +648 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
module Capistrano
|
3
|
+
# class used for configuration
|
4
|
+
class Configuration
|
5
|
+
# class used for confirming customized questions
|
6
|
+
class ConfirmQuestion < Capistrano::Configuration::Question
|
7
|
+
def question
|
8
|
+
I18n.t(:confirm_question, key: key, default_value: default, scope: :capistrano)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
Capistrano::DSL::Env.class_eval do
|
15
|
+
def ask_confirm(key, value, options = {})
|
16
|
+
env.ask_confirm(key, value, options)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
Capistrano::Configuration.class_eval do
|
21
|
+
def ask_confirm(key, default = nil, options = {})
|
22
|
+
question = Capistrano::Configuration::ConfirmQuestion.new(key, default, options)
|
23
|
+
set(key, question)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
Rake::Task.class_eval do
|
2
|
+
alias_method :original_execute, :execute
|
3
|
+
|
4
|
+
def execute(args = nil)
|
5
|
+
job_id = ENV[CapistranoMulticonfigParallel::ENV_KEY_JOB_ID]
|
6
|
+
if job_id.present?
|
7
|
+
run_the_actor(job_id) do
|
8
|
+
original_execute(*args)
|
9
|
+
end
|
10
|
+
else
|
11
|
+
original_execute(*args)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def run_the_actor(job_id, &block)
|
16
|
+
rake_actor_id = ENV['count_rake'].present? ? "rake_worker_#{job_id}_count" : "rake_worker_#{job_id}"
|
17
|
+
if Celluloid::Actor[rake_actor_id].blank?
|
18
|
+
CapistranoMulticonfigParallel::RakeWorker.supervise_as rake_actor_id
|
19
|
+
Celluloid::Actor[rake_actor_id].work(ENV, self, rake_actor_id: rake_actor_id)
|
20
|
+
else
|
21
|
+
Celluloid::Actor[rake_actor_id].publish_new_work(ENV, self)
|
22
|
+
end
|
23
|
+
until Celluloid::Actor[rake_actor_id].task_approved
|
24
|
+
sleep(0.1) # keep current thread alive
|
25
|
+
end
|
26
|
+
block.call if Celluloid::Actor[rake_actor_id].task_approved
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require_relative './interactive_menu'
|
2
|
+
|
3
|
+
module CapistranoMulticonfigParallel
|
4
|
+
# class used to find application dependencies
|
5
|
+
class DependencyTracker
|
6
|
+
attr_accessor :job_manager
|
7
|
+
|
8
|
+
def initialize(job_manager)
|
9
|
+
@job_manager = job_manager
|
10
|
+
end
|
11
|
+
|
12
|
+
def application_dependencies
|
13
|
+
deps = CapistranoMulticonfigParallel.configuration.track_dependencies ? CapistranoMulticonfigParallel.configuration.application_dependencies : []
|
14
|
+
deps.present? && deps.is_a?(Array) ? deps.map(&:stringify_keys) : []
|
15
|
+
end
|
16
|
+
|
17
|
+
def all_websites_return_applications_selected
|
18
|
+
applications = application_dependencies.map { |hash| hash['app'].camelcase }
|
19
|
+
applications << 'all_frameworks'
|
20
|
+
interactive_menu = CapistranoMulticonfigParallel::InteractiveMenu.new
|
21
|
+
applications_selected = interactive_menu.show_all_websites_interactive_menu(applications)
|
22
|
+
|
23
|
+
applications_selected = applications_selected.gsub("\r\n", '') if applications_selected.present?
|
24
|
+
applications_selected = applications_selected.gsub("\n", '') if applications_selected.present?
|
25
|
+
applications_selected = applications_selected.split(',') if applications_selected.present?
|
26
|
+
applications_selected.present? ? applications_selected : []
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_dependency_app(app_to_deploy, apps_dependencies, applications_to_deploy)
|
30
|
+
return unless app_to_deploy.present?
|
31
|
+
applications_to_deploy << app_to_deploy
|
32
|
+
return unless app_to_deploy['dependencies'].present?
|
33
|
+
app_to_deploy['dependencies'].each do |dependency|
|
34
|
+
dependency_app = application_dependencies.find { |hash| hash['app'] == dependency }
|
35
|
+
apps_dependencies << dependency_app if dependency_app.present?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def find_apps_and_deps(applications_selected)
|
40
|
+
applications_to_deploy = []
|
41
|
+
apps_dependencies = []
|
42
|
+
applications_selected.each do |app|
|
43
|
+
app_to_deploy = application_dependencies.find { |hash| hash['app'].camelcase == app }
|
44
|
+
add_dependency_app(app_to_deploy, apps_dependencies, applications_to_deploy)
|
45
|
+
end
|
46
|
+
[applications_to_deploy, apps_dependencies]
|
47
|
+
end
|
48
|
+
|
49
|
+
def check_app_dependency_unique(applications_selected, apps_dependencies, applications_to_deploy, action)
|
50
|
+
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?
|
51
|
+
set :apps_dependency_confirmation, ask_confirm("Do you want to #{action} all dependencies also ? (Y/N):", 'N')
|
52
|
+
applications_to_deploy = applications_to_deploy.concat(apps_dependencies) if fetch(:apps_dependency_confirmation).present? && fetch(:apps_dependency_confirmation).downcase == 'y'
|
53
|
+
applications_to_deploy
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_applications_to_deploy(action, applications_selected)
|
57
|
+
all_frameworks = applications_selected.find { |app| app == 'all_frameworks' }
|
58
|
+
if all_frameworks.present?
|
59
|
+
applications_to_deploy = application_dependencies.map { |hash| hash }
|
60
|
+
else
|
61
|
+
applications_to_deploy, apps_dependencies = find_apps_and_deps(applications_selected)
|
62
|
+
applications_to_deploy = check_app_dependency_unique(applications_selected, apps_dependencies, applications_to_deploy, action)
|
63
|
+
end
|
64
|
+
if applications_to_deploy.present?
|
65
|
+
applications_to_deploy = applications_to_deploy.uniq
|
66
|
+
applications_to_deploy = applications_to_deploy.sort_by { |hash| hash['priority'] }
|
67
|
+
end
|
68
|
+
show_frameworks_used(applications_to_deploy, all_frameworks, action)
|
69
|
+
end
|
70
|
+
|
71
|
+
def show_frameworks_used(applications_to_deploy, all_frameworks, action)
|
72
|
+
return [] if applications_to_deploy.blank? || applications_to_deploy.size <= 1
|
73
|
+
puts 'The following frameworks will be used:'
|
74
|
+
app_names = []
|
75
|
+
if all_frameworks.present?
|
76
|
+
app_names = applications_to_deploy.map { |app| app['app'].camelcase }
|
77
|
+
else
|
78
|
+
app_names = applications_to_deploy.map { |app| application_dependencies.find { |hash| hash['app'] == app['app'] }['app'].camelcase }
|
79
|
+
end
|
80
|
+
print_frameworks_used(app_names, applications_to_deploy, action)
|
81
|
+
end
|
82
|
+
|
83
|
+
def print_frameworks_used(app_names, applications_to_deploy, action)
|
84
|
+
app_names.each { |app| puts "#{app}" }
|
85
|
+
set :apps_deploy_confirmation, ask_confirm("Are you sure you want to #{action} these apps? (Y/N):", 'N')
|
86
|
+
if fetch(:apps_deploy_confirmation).blank? || (fetch(:apps_deploy_confirmation).present? && fetch(:apps_deploy_confirmation).downcase == 'n')
|
87
|
+
return []
|
88
|
+
elsif fetch(:apps_deploy_confirmation).present? && fetch(:apps_deploy_confirmation).downcase == 'y'
|
89
|
+
return applications_to_deploy
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def fetch_apps_needed_for_deployment(application, action)
|
94
|
+
applications = []
|
95
|
+
if @job_manager.custom_command? && @job_manager.multi_apps?
|
96
|
+
apps_selected = all_websites_return_applications_selected
|
97
|
+
applications = get_applications_to_deploy(action, apps_selected)
|
98
|
+
elsif CapistranoMulticonfigParallel.configuration.track_dependencies
|
99
|
+
if application.present?
|
100
|
+
applications = get_applications_to_deploy(action, [application.camelcase])
|
101
|
+
applications = applications.delete_if { |hash| hash['app'] == application }
|
102
|
+
else
|
103
|
+
applications = []
|
104
|
+
end
|
105
|
+
else
|
106
|
+
applications = []
|
107
|
+
end
|
108
|
+
applications
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module CapistranoMulticonfigParallel
|
2
|
+
# methods used for the interactive menu where are listed all aplications
|
3
|
+
class InteractiveMenu
|
4
|
+
def show_all_websites_interactive_menu(applications)
|
5
|
+
msg = ''
|
6
|
+
choices = []
|
7
|
+
print_menu_choices(msg, choices, applications)
|
8
|
+
print "\nYou selected"
|
9
|
+
msg = ' nothing'
|
10
|
+
result = ''
|
11
|
+
applications.each_with_index do |option_name, index|
|
12
|
+
next unless choices[index].present?
|
13
|
+
print(" #{option_name}")
|
14
|
+
msg = ''
|
15
|
+
result += "#{option_name},"
|
16
|
+
end
|
17
|
+
print "#{msg}\n"
|
18
|
+
result
|
19
|
+
end
|
20
|
+
|
21
|
+
def confirm_option_selected
|
22
|
+
print 'Enter a comma-separated list of option numbers or one single option number (again to uncheck, ENTER when done): '
|
23
|
+
$stdin.gets.squeeze(' ').strip
|
24
|
+
end
|
25
|
+
|
26
|
+
def print_menu_choices(msg, choices, applications)
|
27
|
+
while print_all_websites_available_options(applications, msg, choices) && (option = confirm_option_selected).present?
|
28
|
+
if /^[0-9,]+/.match(option)
|
29
|
+
handle_menu_option(msg, option, choices, applications)
|
30
|
+
else
|
31
|
+
msg = "Invalid option: #{option}\n "
|
32
|
+
next
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def print_all_websites_available_options(applications, msg, choices)
|
38
|
+
puts 'Available options:'
|
39
|
+
applications.each_with_index do |option, index|
|
40
|
+
puts "#{(index + 1)} #{choices[index].present? ? "#{choices[index]}" : ''}) #{option} "
|
41
|
+
end
|
42
|
+
puts "\n#{msg}" if msg.present?
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
def handle_menu_option(msg, option, choices, applications)
|
47
|
+
arr_in = option.split(',')
|
48
|
+
arr_in.each_with_index do |number_option, _index|
|
49
|
+
num = number_option.to_i
|
50
|
+
if /^[0-9]+/.match(num.to_s) && ((num.to_i > 0 && num.to_i <= applications.size))
|
51
|
+
num -= 1
|
52
|
+
msg += "#{applications[num]} was #{choices[num].present? ? 'un' : '' }checked\n"
|
53
|
+
choices[num] = choices[num].blank? ? '+' : ' '
|
54
|
+
else
|
55
|
+
msg = "Invalid option: #{num}\n"
|
56
|
+
next
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Returns the version of the currently loaded gem as a <tt>Gem::Version</tt>
|
2
|
+
module CapistranoMulticonfigParallel
|
3
|
+
def self.gem_version
|
4
|
+
Gem::Version.new VERSION::STRING
|
5
|
+
end
|
6
|
+
|
7
|
+
# module used for generating the version
|
8
|
+
module VERSION
|
9
|
+
MAJOR = 0
|
10
|
+
MINOR = 0
|
11
|
+
TINY = 1
|
12
|
+
PRE = nil
|
13
|
+
|
14
|
+
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
|
15
|
+
end
|
16
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Configure Rails Envinronment
|
2
|
+
ENV['RAILS_ENV'] = 'test'
|
3
|
+
|
4
|
+
require 'simplecov'
|
5
|
+
require 'simplecov-summary'
|
6
|
+
require 'coveralls'
|
7
|
+
|
8
|
+
# require "codeclimate-test-reporter"
|
9
|
+
formatters = [SimpleCov::Formatter::HTMLFormatter]
|
10
|
+
|
11
|
+
formatters << Coveralls::SimpleCov::Formatter # if ENV['TRAVIS']
|
12
|
+
# formatters << CodeClimate::TestReporter::Formatter # if ENV['CODECLIMATE_REPO_TOKEN'] && ENV['TRAVIS']
|
13
|
+
|
14
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[*formatters]
|
15
|
+
|
16
|
+
Coveralls.wear!
|
17
|
+
SimpleCov.start 'rails' do
|
18
|
+
add_filter 'spec'
|
19
|
+
|
20
|
+
at_exit {}
|
21
|
+
end
|
22
|
+
|
23
|
+
# CodeClimate::TestReporter.configure do |config|
|
24
|
+
# config.logger.level = Logger::WARN
|
25
|
+
# end
|
26
|
+
# CodeClimate::TestReporter.start
|
27
|
+
|
28
|
+
require 'bundler/setup'
|
29
|
+
require 'celluloid_pubsub'
|
30
|
+
|
31
|
+
require 'rspec/autorun'
|
32
|
+
|
33
|
+
RSpec.configure do |config|
|
34
|
+
require 'rspec/expectations'
|
35
|
+
config.include RSpec::Matchers
|
36
|
+
|
37
|
+
config.mock_with :mocha
|
38
|
+
|
39
|
+
config.after(:suite) do
|
40
|
+
if SimpleCov.running
|
41
|
+
silence_stream(STDOUT) do
|
42
|
+
SimpleCov::Formatter::HTMLFormatter.new.format(SimpleCov.result)
|
43
|
+
end
|
44
|
+
|
45
|
+
SimpleCov::Formatter::SummaryFormatter.new.format(SimpleCov.result)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|