capistrano_multiconfig_parallel 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +21 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +68 -0
  6. data/.travis.yml +12 -0
  7. data/CONTRIBUTING.md +44 -0
  8. data/Gemfile +3 -0
  9. data/Guardfile +12 -0
  10. data/LICENSE +20 -0
  11. data/README.md +220 -0
  12. data/Rakefile +56 -0
  13. data/bin/multi_cap +7 -0
  14. data/capistrano_multiconfig_parallel.gemspec +51 -0
  15. data/img/parallel_demo.png +0 -0
  16. data/init.rb +1 -0
  17. data/lib/capistrano_multiconfig_parallel/application.rb +57 -0
  18. data/lib/capistrano_multiconfig_parallel/base.rb +92 -0
  19. data/lib/capistrano_multiconfig_parallel/celluloid/celluloid_manager.rb +178 -0
  20. data/lib/capistrano_multiconfig_parallel/celluloid/celluloid_worker.rb +238 -0
  21. data/lib/capistrano_multiconfig_parallel/celluloid/child_process.rb +104 -0
  22. data/lib/capistrano_multiconfig_parallel/celluloid/rake_worker.rb +83 -0
  23. data/lib/capistrano_multiconfig_parallel/celluloid/state_machine.rb +49 -0
  24. data/lib/capistrano_multiconfig_parallel/celluloid/terminal_table.rb +122 -0
  25. data/lib/capistrano_multiconfig_parallel/cli.rb +55 -0
  26. data/lib/capistrano_multiconfig_parallel/configuration.rb +70 -0
  27. data/lib/capistrano_multiconfig_parallel/helpers/base_manager.rb +217 -0
  28. data/lib/capistrano_multiconfig_parallel/helpers/multi_app_manager.rb +84 -0
  29. data/lib/capistrano_multiconfig_parallel/helpers/single_app_manager.rb +48 -0
  30. data/lib/capistrano_multiconfig_parallel/helpers/standard_deploy.rb +40 -0
  31. data/lib/capistrano_multiconfig_parallel/initializers/conf.rb +6 -0
  32. data/lib/capistrano_multiconfig_parallel/initializers/confirm_question.rb +25 -0
  33. data/lib/capistrano_multiconfig_parallel/initializers/i18n.rb +10 -0
  34. data/lib/capistrano_multiconfig_parallel/initializers/rake.rb +28 -0
  35. data/lib/capistrano_multiconfig_parallel/multi_app_helpers/dependency_tracker.rb +111 -0
  36. data/lib/capistrano_multiconfig_parallel/multi_app_helpers/interactive_menu.rb +61 -0
  37. data/lib/capistrano_multiconfig_parallel/version.rb +16 -0
  38. data/lib/capistrano_multiconfig_parallel.rb +2 -0
  39. data/spec/spec_helper.rb +48 -0
  40. 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,10 @@
1
+ require 'i18n'
2
+ en = {
3
+ confirm_question: '%{key} (%{default_value}): '
4
+ }
5
+
6
+ I18n.backend.store_translations(:en, capistrano: en)
7
+
8
+ if I18n.respond_to?(:enforce_available_locales=)
9
+ I18n.enforce_available_locales = true
10
+ 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
@@ -0,0 +1,2 @@
1
+ require 'capistrano_multiconfig_parallel/version'
2
+ require 'capistrano_multiconfig_parallel/base'
@@ -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