capistrano 3.3.5 → 3.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +5 -5
  2. data/.github/issue_template.md +19 -0
  3. data/.github/pull_request_template.md +22 -0
  4. data/.github/release-drafter.yml +17 -0
  5. data/.github/workflows/push.yml +12 -0
  6. data/.gitignore +8 -5
  7. data/.rubocop.yml +62 -0
  8. data/.travis.yml +25 -7
  9. data/CHANGELOG.md +1 -273
  10. data/CONTRIBUTING.md +63 -93
  11. data/DEVELOPMENT.md +127 -0
  12. data/Dangerfile +1 -0
  13. data/Gemfile +36 -3
  14. data/LICENSE.txt +1 -1
  15. data/README.md +118 -292
  16. data/RELEASING.md +17 -0
  17. data/Rakefile +9 -1
  18. data/UPGRADING-3.7.md +86 -0
  19. data/bin/cap +1 -1
  20. data/capistrano.gemspec +24 -24
  21. data/features/deploy.feature +35 -1
  22. data/features/doctor.feature +11 -0
  23. data/features/installation.feature +8 -3
  24. data/features/sshconnect.feature +11 -0
  25. data/features/stage_failure.feature +9 -0
  26. data/features/step_definitions/assertions.rb +57 -20
  27. data/features/step_definitions/cap_commands.rb +9 -0
  28. data/features/step_definitions/setup.rb +56 -8
  29. data/features/subdirectory.feature +9 -0
  30. data/features/support/env.rb +5 -5
  31. data/features/support/remote_command_helpers.rb +12 -6
  32. data/features/support/vagrant_helpers.rb +17 -11
  33. data/lib/Capfile +1 -1
  34. data/lib/capistrano/all.rb +10 -10
  35. data/lib/capistrano/application.rb +47 -34
  36. data/lib/capistrano/configuration.rb +95 -44
  37. data/lib/capistrano/configuration/empty_filter.rb +9 -0
  38. data/lib/capistrano/configuration/filter.rb +16 -46
  39. data/lib/capistrano/configuration/host_filter.rb +29 -0
  40. data/lib/capistrano/configuration/null_filter.rb +9 -0
  41. data/lib/capistrano/configuration/plugin_installer.rb +51 -0
  42. data/lib/capistrano/configuration/question.rb +31 -9
  43. data/lib/capistrano/configuration/role_filter.rb +29 -0
  44. data/lib/capistrano/configuration/scm_resolver.rb +149 -0
  45. data/lib/capistrano/configuration/server.rb +30 -62
  46. data/lib/capistrano/configuration/servers.rb +38 -12
  47. data/lib/capistrano/configuration/validated_variables.rb +110 -0
  48. data/lib/capistrano/configuration/variables.rb +112 -0
  49. data/lib/capistrano/defaults.rb +26 -4
  50. data/lib/capistrano/deploy.rb +1 -2
  51. data/lib/capistrano/doctor.rb +6 -0
  52. data/lib/capistrano/doctor/environment_doctor.rb +19 -0
  53. data/lib/capistrano/doctor/gems_doctor.rb +45 -0
  54. data/lib/capistrano/doctor/output_helpers.rb +79 -0
  55. data/lib/capistrano/doctor/servers_doctor.rb +105 -0
  56. data/lib/capistrano/doctor/variables_doctor.rb +72 -0
  57. data/lib/capistrano/dotfile.rb +1 -2
  58. data/lib/capistrano/dsl.rb +49 -18
  59. data/lib/capistrano/dsl/env.rb +16 -46
  60. data/lib/capistrano/dsl/paths.rb +11 -25
  61. data/lib/capistrano/dsl/stages.rb +14 -2
  62. data/lib/capistrano/dsl/task_enhancements.rb +7 -12
  63. data/lib/capistrano/framework.rb +1 -1
  64. data/lib/capistrano/i18n.rb +32 -24
  65. data/lib/capistrano/immutable_task.rb +30 -0
  66. data/lib/capistrano/install.rb +1 -1
  67. data/lib/capistrano/plugin.rb +95 -0
  68. data/lib/capistrano/proc_helpers.rb +13 -0
  69. data/lib/capistrano/scm.rb +7 -20
  70. data/lib/capistrano/scm/git.rb +100 -0
  71. data/lib/capistrano/scm/hg.rb +55 -0
  72. data/lib/capistrano/scm/plugin.rb +13 -0
  73. data/lib/capistrano/scm/svn.rb +56 -0
  74. data/lib/capistrano/scm/tasks/git.rake +73 -0
  75. data/lib/capistrano/scm/tasks/hg.rake +53 -0
  76. data/lib/capistrano/scm/tasks/svn.rake +53 -0
  77. data/lib/capistrano/setup.rb +20 -6
  78. data/lib/capistrano/tasks/console.rake +4 -8
  79. data/lib/capistrano/tasks/deploy.rake +105 -74
  80. data/lib/capistrano/tasks/doctor.rake +24 -0
  81. data/lib/capistrano/tasks/framework.rake +13 -14
  82. data/lib/capistrano/tasks/install.rake +14 -15
  83. data/lib/capistrano/templates/Capfile +22 -11
  84. data/lib/capistrano/templates/deploy.rb.erb +18 -27
  85. data/lib/capistrano/templates/stage.rb.erb +36 -20
  86. data/lib/capistrano/upload_task.rb +1 -1
  87. data/lib/capistrano/version.rb +1 -1
  88. data/lib/capistrano/version_validator.rb +5 -10
  89. data/spec/integration/dsl_spec.rb +311 -289
  90. data/spec/integration_spec_helper.rb +3 -5
  91. data/spec/lib/capistrano/application_spec.rb +23 -39
  92. data/spec/lib/capistrano/configuration/empty_filter_spec.rb +17 -0
  93. data/spec/lib/capistrano/configuration/filter_spec.rb +83 -79
  94. data/spec/lib/capistrano/configuration/host_filter_spec.rb +71 -0
  95. data/spec/lib/capistrano/configuration/null_filter_spec.rb +17 -0
  96. data/spec/lib/capistrano/configuration/plugin_installer_spec.rb +98 -0
  97. data/spec/lib/capistrano/configuration/question_spec.rb +58 -26
  98. data/spec/lib/capistrano/configuration/role_filter_spec.rb +80 -0
  99. data/spec/lib/capistrano/configuration/scm_resolver_spec.rb +55 -0
  100. data/spec/lib/capistrano/configuration/server_spec.rb +124 -100
  101. data/spec/lib/capistrano/configuration/servers_spec.rb +143 -123
  102. data/spec/lib/capistrano/configuration_spec.rb +231 -59
  103. data/spec/lib/capistrano/doctor/environment_doctor_spec.rb +44 -0
  104. data/spec/lib/capistrano/doctor/gems_doctor_spec.rb +67 -0
  105. data/spec/lib/capistrano/doctor/output_helpers_spec.rb +47 -0
  106. data/spec/lib/capistrano/doctor/servers_doctor_spec.rb +86 -0
  107. data/spec/lib/capistrano/doctor/variables_doctor_spec.rb +89 -0
  108. data/spec/lib/capistrano/dsl/paths_spec.rb +201 -42
  109. data/spec/lib/capistrano/dsl/task_enhancements_spec.rb +57 -37
  110. data/spec/lib/capistrano/dsl_spec.rb +84 -11
  111. data/spec/lib/capistrano/immutable_task_spec.rb +31 -0
  112. data/spec/lib/capistrano/plugin_spec.rb +84 -0
  113. data/spec/lib/capistrano/scm/git_spec.rb +184 -0
  114. data/spec/lib/capistrano/scm/hg_spec.rb +109 -0
  115. data/spec/lib/capistrano/scm/svn_spec.rb +137 -0
  116. data/spec/lib/capistrano/scm_spec.rb +7 -8
  117. data/spec/lib/capistrano/upload_task_spec.rb +7 -7
  118. data/spec/lib/capistrano/version_validator_spec.rb +61 -46
  119. data/spec/lib/capistrano_spec.rb +2 -3
  120. data/spec/spec_helper.rb +21 -8
  121. data/spec/support/Vagrantfile +18 -8
  122. data/spec/support/tasks/database.rake +3 -3
  123. data/spec/support/tasks/fail.rake +4 -3
  124. data/spec/support/tasks/failed.rake +2 -2
  125. data/spec/support/tasks/plugin.rake +6 -0
  126. data/spec/support/tasks/root.rake +11 -0
  127. data/spec/support/test_app.rb +63 -39
  128. metadata +121 -44
  129. data/features/remote_file_task.feature +0 -14
  130. data/lib/capistrano/git.rb +0 -46
  131. data/lib/capistrano/hg.rb +0 -43
  132. data/lib/capistrano/svn.rb +0 -38
  133. data/lib/capistrano/tasks/git.rake +0 -81
  134. data/lib/capistrano/tasks/hg.rake +0 -52
  135. data/lib/capistrano/tasks/svn.rake +0 -52
  136. data/spec/lib/capistrano/git_spec.rb +0 -81
  137. data/spec/lib/capistrano/hg_spec.rb +0 -81
  138. data/spec/lib/capistrano/svn_spec.rb +0 -79
@@ -0,0 +1,24 @@
1
+ desc "Display a Capistrano troubleshooting report (all doctor: tasks)"
2
+ task doctor: ["doctor:environment", "doctor:gems", "doctor:variables", "doctor:servers"]
3
+
4
+ namespace :doctor do
5
+ desc "Display Ruby environment details"
6
+ task :environment do
7
+ Capistrano::Doctor::EnvironmentDoctor.new.call
8
+ end
9
+
10
+ desc "Display Capistrano gem versions"
11
+ task :gems do
12
+ Capistrano::Doctor::GemsDoctor.new.call
13
+ end
14
+
15
+ desc "Display the values of all Capistrano variables"
16
+ task :variables do
17
+ Capistrano::Doctor::VariablesDoctor.new.call
18
+ end
19
+
20
+ desc "Display the effective servers configuration"
21
+ task :servers do
22
+ Capistrano::Doctor::ServersDoctor.new.call
23
+ end
24
+ end
@@ -1,50 +1,49 @@
1
1
  namespace :deploy do
2
-
3
- desc 'Start a deployment, make sure server(s) ready.'
2
+ desc "Start a deployment, make sure server(s) ready."
4
3
  task :starting do
5
4
  end
6
5
 
7
- desc 'Started'
6
+ desc "Started"
8
7
  task :started do
9
8
  end
10
9
 
11
- desc 'Update server(s) by setting up a new release.'
10
+ desc "Update server(s) by setting up a new release."
12
11
  task :updating do
13
12
  end
14
13
 
15
- desc 'Updated'
14
+ desc "Updated"
16
15
  task :updated do
17
16
  end
18
17
 
19
- desc 'Revert server(s) to previous release.'
18
+ desc "Revert server(s) to previous release."
20
19
  task :reverting do
21
20
  end
22
21
 
23
- desc 'Reverted'
22
+ desc "Reverted"
24
23
  task :reverted do
25
24
  end
26
25
 
27
- desc 'Publish the release.'
26
+ desc "Publish the release."
28
27
  task :publishing do
29
28
  end
30
29
 
31
- desc 'Published'
30
+ desc "Published"
32
31
  task :published do
33
32
  end
34
33
 
35
- desc 'Finish the deployment, clean up server(s).'
34
+ desc "Finish the deployment, clean up server(s)."
36
35
  task :finishing do
37
36
  end
38
37
 
39
- desc 'Finish the rollback, clean up server(s).'
38
+ desc "Finish the rollback, clean up server(s)."
40
39
  task :finishing_rollback do
41
40
  end
42
41
 
43
- desc 'Finished'
42
+ desc "Finished"
44
43
  task :finished do
45
44
  end
46
45
 
47
- desc 'Rollback to previous release.'
46
+ desc "Rollback to previous release."
48
47
  task :rollback do
49
48
  %w{ starting started
50
49
  reverting reverted
@@ -55,7 +54,7 @@ namespace :deploy do
55
54
  end
56
55
  end
57
56
 
58
- desc 'Deploy a new release.'
57
+ desc "Deploy a new release."
59
58
  task :deploy do
60
59
  set(:deploying, true)
61
60
  %w{ starting started
@@ -1,12 +1,12 @@
1
- require 'erb'
2
- require 'pathname'
3
- desc 'Install Capistrano, cap install STAGES=staging,production'
1
+ require "erb"
2
+ require "pathname"
3
+ desc "Install Capistrano, cap install STAGES=staging,production"
4
4
  task :install do
5
- envs = ENV['STAGES'] || 'staging,production'
5
+ envs = ENV["STAGES"] || "staging,production"
6
6
 
7
- tasks_dir = Pathname.new('lib/capistrano/tasks')
8
- config_dir = Pathname.new('config')
9
- deploy_dir = config_dir.join('deploy')
7
+ tasks_dir = Pathname.new("lib/capistrano/tasks")
8
+ config_dir = Pathname.new("config")
9
+ deploy_dir = config_dir.join("deploy")
10
10
 
11
11
  deploy_rb = File.expand_path("../../templates/deploy.rb.erb", __FILE__)
12
12
  stage_rb = File.expand_path("../../templates/stage.rb.erb", __FILE__)
@@ -14,14 +14,14 @@ task :install do
14
14
 
15
15
  mkdir_p deploy_dir
16
16
 
17
- entries = [{template: deploy_rb, file: config_dir.join('deploy.rb')}]
18
- entries += envs.split(',').map { |stage| {template: stage_rb, file: deploy_dir.join("#{stage}.rb")} }
17
+ entries = [{ template: deploy_rb, file: config_dir.join("deploy.rb") }]
18
+ entries += envs.split(",").map { |stage| { template: stage_rb, file: deploy_dir.join("#{stage}.rb") } }
19
19
 
20
20
  entries.each do |entry|
21
- if File.exists?(entry[:file])
21
+ if File.exist?(entry[:file])
22
22
  warn "[skip] #{entry[:file]} already exists"
23
23
  else
24
- File.open(entry[:file], 'w+') do |f|
24
+ File.open(entry[:file], "w+") do |f|
25
25
  f.write(ERB.new(File.read(entry[:template])).result(binding))
26
26
  puts I18n.t(:written_file, scope: :capistrano, file: entry[:file])
27
27
  end
@@ -30,13 +30,12 @@ task :install do
30
30
 
31
31
  mkdir_p tasks_dir
32
32
 
33
- if File.exists?('Capfile')
33
+ if File.exist?("Capfile")
34
34
  warn "[skip] Capfile already exists"
35
35
  else
36
- FileUtils.cp(capfile, 'Capfile')
37
- puts I18n.t(:written_file, scope: :capistrano, file: 'Capfile')
36
+ FileUtils.cp(capfile, "Capfile")
37
+ puts I18n.t(:written_file, scope: :capistrano, file: "Capfile")
38
38
  end
39
39
 
40
-
41
40
  puts I18n.t :capified, scope: :capistrano
42
41
  end
@@ -1,8 +1,19 @@
1
1
  # Load DSL and set up stages
2
- require 'capistrano/setup'
2
+ require "capistrano/setup"
3
3
 
4
4
  # Include default deployment tasks
5
- require 'capistrano/deploy'
5
+ require "capistrano/deploy"
6
+
7
+ # Load the SCM plugin appropriate to your project:
8
+ #
9
+ # require "capistrano/scm/hg"
10
+ # install_plugin Capistrano::SCM::Hg
11
+ # or
12
+ # require "capistrano/scm/svn"
13
+ # install_plugin Capistrano::SCM::Svn
14
+ # or
15
+ require "capistrano/scm/git"
16
+ install_plugin Capistrano::SCM::Git
6
17
 
7
18
  # Include tasks from other gems included in your Gemfile
8
19
  #
@@ -15,13 +26,13 @@ require 'capistrano/deploy'
15
26
  # https://github.com/capistrano/rails
16
27
  # https://github.com/capistrano/passenger
17
28
  #
18
- # require 'capistrano/rvm'
19
- # require 'capistrano/rbenv'
20
- # require 'capistrano/chruby'
21
- # require 'capistrano/bundler'
22
- # require 'capistrano/rails/assets'
23
- # require 'capistrano/rails/migrations'
24
- # require 'capistrano/passenger'
29
+ # require "capistrano/rvm"
30
+ # require "capistrano/rbenv"
31
+ # require "capistrano/chruby"
32
+ # require "capistrano/bundler"
33
+ # require "capistrano/rails/assets"
34
+ # require "capistrano/rails/migrations"
35
+ # require "capistrano/passenger"
25
36
 
26
- # Load custom tasks from `lib/capistrano/tasks' if you have any defined
27
- Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
37
+ # Load custom tasks from `lib/capistrano/tasks` if you have any defined
38
+ Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
@@ -1,48 +1,39 @@
1
- # config valid only for current version of Capistrano
2
- lock '<%= Capistrano::VERSION %>'
1
+ # config valid for current version and patch releases of Capistrano
2
+ lock "~> <%= Capistrano::VERSION %>"
3
3
 
4
- set :application, 'my_app_name'
5
- set :repo_url, 'git@example.com:me/my_repo.git'
4
+ set :application, "my_app_name"
5
+ set :repo_url, "git@example.com:me/my_repo.git"
6
6
 
7
7
  # Default branch is :master
8
- # ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }.call
8
+ # ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp
9
9
 
10
10
  # Default deploy_to directory is /var/www/my_app_name
11
- # set :deploy_to, '/var/www/my_app_name'
11
+ # set :deploy_to, "/var/www/my_app_name"
12
12
 
13
- # Default value for :scm is :git
14
- # set :scm, :git
13
+ # Default value for :format is :airbrussh.
14
+ # set :format, :airbrussh
15
15
 
16
- # Default value for :format is :pretty
17
- # set :format, :pretty
18
-
19
- # Default value for :log_level is :debug
20
- # set :log_level, :debug
16
+ # You can configure the Airbrussh format using :format_options.
17
+ # These are the defaults.
18
+ # set :format_options, command_output: true, log_file: "log/capistrano.log", color: :auto, truncate: :auto
21
19
 
22
20
  # Default value for :pty is false
23
21
  # set :pty, true
24
22
 
25
23
  # Default value for :linked_files is []
26
- # set :linked_files, fetch(:linked_files, []).push('config/database.yml')
24
+ # append :linked_files, "config/database.yml"
27
25
 
28
26
  # Default value for linked_dirs is []
29
- # set :linked_dirs, fetch(:linked_dirs, []).push('bin', 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
27
+ # append :linked_dirs, "log", "tmp/pids", "tmp/cache", "tmp/sockets", "public/system"
30
28
 
31
29
  # Default value for default_env is {}
32
30
  # set :default_env, { path: "/opt/ruby/bin:$PATH" }
33
31
 
32
+ # Default value for local_user is ENV['USER']
33
+ # set :local_user, -> { `git config user.name`.chomp }
34
+
34
35
  # Default value for keep_releases is 5
35
36
  # set :keep_releases, 5
36
37
 
37
- namespace :deploy do
38
-
39
- after :restart, :clear_cache do
40
- on roles(:web), in: :groups, limit: 3, wait: 10 do
41
- # Here we can do anything such as:
42
- # within release_path do
43
- # execute :rake, 'cache:clear'
44
- # end
45
- end
46
- end
47
-
48
- end
38
+ # Uncomment the following to require manually verifying the host key before first deploy.
39
+ # set :ssh_options, verify_host_key: :secure
@@ -1,45 +1,61 @@
1
- # Simple Role Syntax
1
+ # server-based syntax
2
+ # ======================
3
+ # Defines a single server with a list of roles and multiple properties.
4
+ # You can define all roles on a single server, or split them:
5
+
6
+ # server "example.com", user: "deploy", roles: %w{app db web}, my_property: :my_value
7
+ # server "example.com", user: "deploy", roles: %w{app web}, other_property: :other_value
8
+ # server "db.example.com", user: "deploy", roles: %w{db}
9
+
10
+
11
+
12
+ # role-based syntax
2
13
  # ==================
3
- # Supports bulk-adding hosts to roles, the primary server in each group
4
- # is considered to be the first unless any hosts have the primary
5
- # property set. Don't declare `role :all`, it's a meta role.
6
14
 
7
- role :app, %w{deploy@example.com}
8
- role :web, %w{deploy@example.com}
9
- role :db, %w{deploy@example.com}
15
+ # Defines a role with one or multiple servers. The primary server in each
16
+ # group is considered to be the first unless any hosts have the primary
17
+ # property set. Specify the username and a domain or IP for the server.
18
+ # Don't use `:all`, it's a meta role.
10
19
 
20
+ # role :app, %w{deploy@example.com}, my_property: :my_value
21
+ # role :web, %w{user1@primary.com user2@additional.com}, other_property: :other_value
22
+ # role :db, %w{deploy@example.com}
11
23
 
12
- # Extended Server Syntax
13
- # ======================
14
- # This can be used to drop a more detailed server definition into the
15
- # server list. The second argument is a, or duck-types, Hash and is
16
- # used to set extended properties on the server.
17
24
 
18
- server 'example.com', user: 'deploy', roles: %w{web app}, my_property: :my_value
25
+
26
+ # Configuration
27
+ # =============
28
+ # You can set any configuration variable like in config/deploy.rb
29
+ # These variables are then only loaded and set in this stage.
30
+ # For available Capistrano configuration variables see the documentation page.
31
+ # http://capistranorb.com/documentation/getting-started/configuration/
32
+ # Feel free to add new variables to customise your setup.
33
+
19
34
 
20
35
 
21
36
  # Custom SSH Options
22
37
  # ==================
23
38
  # You may pass any option but keep in mind that net/ssh understands a
24
- # limited set of options, consult[net/ssh documentation](http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start).
39
+ # limited set of options, consult the Net::SSH documentation.
40
+ # http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start
25
41
  #
26
42
  # Global options
27
43
  # --------------
28
44
  # set :ssh_options, {
29
- # keys: %w(/home/rlisowski/.ssh/id_rsa),
45
+ # keys: %w(/home/user_name/.ssh/id_rsa),
30
46
  # forward_agent: false,
31
47
  # auth_methods: %w(password)
32
48
  # }
33
49
  #
34
- # And/or per server (overrides global)
50
+ # The server-based syntax can be used to override options:
35
51
  # ------------------------------------
36
- # server 'example.com',
37
- # user: 'user_name',
52
+ # server "example.com",
53
+ # user: "user_name",
38
54
  # roles: %w{web app},
39
55
  # ssh_options: {
40
- # user: 'user_name', # overrides user setting above
56
+ # user: "user_name", # overrides user setting above
41
57
  # keys: %w(/home/user_name/.ssh/id_rsa),
42
58
  # forward_agent: false,
43
59
  # auth_methods: %w(publickey password)
44
- # # password: 'please use keys'
60
+ # # password: "please use keys"
45
61
  # }
@@ -1,4 +1,4 @@
1
- require 'rake/file_creation_task'
1
+ require "rake/file_creation_task"
2
2
 
3
3
  module Capistrano
4
4
  class UploadTask < Rake::FileCreationTask
@@ -1,3 +1,3 @@
1
1
  module Capistrano
2
- VERSION = "3.3.5"
2
+ VERSION = "3.16.0".freeze
3
3
  end
@@ -1,21 +1,17 @@
1
1
  module Capistrano
2
2
  class VersionValidator
3
-
4
3
  def initialize(version)
5
4
  @version = version
6
5
  end
7
6
 
8
7
  def verify
9
- if match?
10
- self
11
- else
12
- fail "Capfile locked at #{version}, but #{current_version} is loaded"
13
- end
8
+ return self if match?
9
+ raise "Capfile locked at #{version}, but #{current_version} is loaded"
14
10
  end
15
11
 
16
12
  private
17
- attr_reader :version
18
13
 
14
+ attr_reader :version
19
15
 
20
16
  def match?
21
17
  available =~ requested
@@ -26,12 +22,11 @@ module Capistrano
26
22
  end
27
23
 
28
24
  def available
29
- Gem::Dependency.new('cap', version)
25
+ Gem::Dependency.new("cap", version)
30
26
  end
31
27
 
32
28
  def requested
33
- Gem::Dependency.new('cap', current_version)
29
+ Gem::Dependency.new("cap", current_version)
34
30
  end
35
-
36
31
  end
37
32
  end
@@ -1,148 +1,177 @@
1
- require 'spec_helper'
1
+ require "spec_helper"
2
2
 
3
3
  describe Capistrano::DSL do
4
-
5
4
  let(:dsl) { Class.new.extend Capistrano::DSL }
6
5
 
7
6
  before do
8
7
  Capistrano::Configuration.reset!
9
8
  end
10
9
 
11
- describe 'setting and fetching hosts' do
12
- describe 'when defining a host using the `server` syntax' do
10
+ describe "setting and fetching hosts" do
11
+ describe "when defining a host using the `server` syntax" do
13
12
  before do
14
- dsl.server 'example1.com', roles: %w{web}, active: true
15
- dsl.server 'example2.com', roles: %w{web}
16
- dsl.server 'example3.com', roles: %w{app web}, active: true
17
- dsl.server 'example4.com', roles: %w{app}, primary: true
18
- dsl.server 'example5.com', roles: %w{db}, no_release: true
13
+ dsl.server "example1.com", roles: %w{web}, active: true
14
+ dsl.server "example2.com", roles: %w{web}
15
+ dsl.server "example3.com", roles: %w{app web}, active: true
16
+ dsl.server "example4.com", roles: %w{app}, primary: true
17
+ dsl.server "example5.com", roles: %w{db}, no_release: true, active: true
19
18
  end
20
19
 
21
- describe 'fetching all servers' do
20
+ describe "fetching all servers" do
22
21
  subject { dsl.roles(:all) }
23
22
 
24
- it 'returns all servers' do
23
+ it "returns all servers" do
25
24
  expect(subject.map(&:hostname)).to eq %w{example1.com example2.com example3.com example4.com example5.com}
26
25
  end
27
26
  end
28
27
 
29
- describe 'fetching all release servers' do
30
-
31
- context 'with no additional options' do
28
+ describe "fetching all release servers" do
29
+ context "with no additional options" do
32
30
  subject { dsl.release_roles(:all) }
33
31
 
34
- it 'returns all release servers' do
32
+ it "returns all release servers" do
35
33
  expect(subject.map(&:hostname)).to eq %w{example1.com example2.com example3.com example4.com}
36
34
  end
37
35
  end
38
36
 
39
- context 'with property filter options' do
37
+ context "with property filter options" do
40
38
  subject { dsl.release_roles(:all, filter: :active) }
41
39
 
42
- it 'returns all release servers that match the property filter' do
40
+ it "returns all release servers that match the property filter" do
43
41
  expect(subject.map(&:hostname)).to eq %w{example1.com example3.com}
44
42
  end
45
43
  end
46
44
  end
47
45
 
48
- describe 'fetching servers by multiple roles' do
46
+ describe "fetching servers by multiple roles" do
49
47
  it "does not confuse the last role with options" do
50
48
  expect(dsl.roles(:app, :web).count).to eq 4
51
49
  expect(dsl.roles(:app, :web, filter: :active).count).to eq 2
52
50
  end
53
51
  end
54
52
 
55
- describe 'fetching servers by role' do
53
+ describe "fetching servers by role" do
56
54
  subject { dsl.roles(:app) }
57
55
 
58
- it 'returns the servers' do
56
+ it "returns the servers" do
59
57
  expect(subject.map(&:hostname)).to eq %w{example3.com example4.com}
60
58
  end
61
59
  end
62
60
 
63
- describe 'fetching servers by an array of roles' do
61
+ describe "fetching servers by an array of roles" do
64
62
  subject { dsl.roles([:app]) }
65
63
 
66
- it 'returns the servers' do
64
+ it "returns the servers" do
67
65
  expect(subject.map(&:hostname)).to eq %w{example3.com example4.com}
68
66
  end
69
67
  end
70
68
 
71
- describe 'fetching filtered servers by role' do
69
+ describe "fetching filtered servers by role" do
72
70
  subject { dsl.roles(:app, filter: :active) }
73
71
 
74
- it 'returns the servers' do
72
+ it "returns the servers" do
75
73
  expect(subject.map(&:hostname)).to eq %w{example3.com}
76
74
  end
77
75
  end
78
76
 
79
- describe 'fetching selected servers by role' do
77
+ describe "fetching selected servers by role" do
80
78
  subject { dsl.roles(:app, select: :active) }
81
79
 
82
- it 'returns the servers' do
80
+ it "returns the servers" do
83
81
  expect(subject.map(&:hostname)).to eq %w{example3.com}
84
82
  end
85
83
  end
86
84
 
87
- describe 'fetching the primary server by role' do
88
- context 'when inferring primary status based on order' do
85
+ describe "fetching the primary server by role" do
86
+ context "when inferring primary status based on order" do
89
87
  subject { dsl.primary(:web) }
90
- it 'returns the servers' do
91
- expect(subject.hostname).to eq 'example1.com'
88
+ it "returns the servers" do
89
+ expect(subject.hostname).to eq "example1.com"
92
90
  end
93
91
  end
94
92
 
95
- context 'when the attribute `primary` is explicitly set' do
93
+ context "when the attribute `primary` is explicitly set" do
96
94
  subject { dsl.primary(:app) }
97
- it 'returns the servers' do
98
- expect(subject.hostname).to eq 'example4.com'
95
+ it "returns the servers" do
96
+ expect(subject.hostname).to eq "example4.com"
99
97
  end
100
98
  end
101
99
  end
102
100
 
103
- describe 'setting an internal host filter' do
101
+ describe "setting an internal host filter" do
104
102
  subject { dsl.roles(:app) }
105
- it 'is ignored' do
106
- dsl.set :filter, { host: 'example3.com' }
107
- expect(subject.map(&:hostname)).to eq(['example3.com', 'example4.com'])
103
+ it "is ignored" do
104
+ dsl.set :filter, host: "example3.com"
105
+ expect(subject.map(&:hostname)).to eq(["example3.com", "example4.com"])
108
106
  end
109
107
  end
110
108
 
111
- describe 'setting an internal role filter' do
109
+ describe "setting an internal role filter" do
112
110
  subject { dsl.roles(:app) }
113
- it 'ignores it' do
114
- dsl.set :filter, { role: :web }
115
- expect(subject.map(&:hostname)).to eq(['example3.com','example4.com'])
111
+ it "ignores it" do
112
+ dsl.set :filter, role: :web
113
+ expect(subject.map(&:hostname)).to eq(["example3.com", "example4.com"])
116
114
  end
117
115
  end
118
116
 
119
- describe 'setting an internal host and role filter' do
117
+ describe "setting an internal host and role filter" do
120
118
  subject { dsl.roles(:app) }
121
- it 'ignores it' do
122
- dsl.set :filter, { role: :web, host: 'example1.com' }
123
- expect(subject.map(&:hostname)).to eq(['example3.com','example4.com'])
119
+ it "ignores it" do
120
+ dsl.set :filter, role: :web, host: "example1.com"
121
+ expect(subject.map(&:hostname)).to eq(["example3.com", "example4.com"])
124
122
  end
125
123
  end
126
124
 
127
- describe 'setting an internal regexp host filter' do
125
+ describe "setting an internal regexp host filter" do
128
126
  subject { dsl.roles(:all) }
129
- it 'is ignored' do
130
- dsl.set :filter, { host: /1/ }
127
+ it "is ignored" do
128
+ dsl.set :filter, host: /1/
131
129
  expect(subject.map(&:hostname)).to eq(%w{example1.com example2.com example3.com example4.com example5.com})
132
130
  end
133
131
  end
134
132
 
133
+ describe "setting an internal hosts filter" do
134
+ subject { dsl.roles(:app) }
135
+ it "is ignored" do
136
+ dsl.set :filter, hosts: "example3.com"
137
+ expect(subject.map(&:hostname)).to eq(["example3.com", "example4.com"])
138
+ end
139
+ end
140
+
141
+ describe "setting an internal roles filter" do
142
+ subject { dsl.roles(:app) }
143
+ it "ignores it" do
144
+ dsl.set :filter, roles: :web
145
+ expect(subject.map(&:hostname)).to eq(["example3.com", "example4.com"])
146
+ end
147
+ end
148
+
149
+ describe "setting an internal hosts and roles filter" do
150
+ subject { dsl.roles(:app) }
151
+ it "ignores it" do
152
+ dsl.set :filter, roles: :web, hosts: "example1.com"
153
+ expect(subject.map(&:hostname)).to eq(["example3.com", "example4.com"])
154
+ end
155
+ end
156
+
157
+ describe "setting an internal regexp hosts filter" do
158
+ subject { dsl.roles(:all) }
159
+ it "is ignored" do
160
+ dsl.set :filter, hosts: /1/
161
+ expect(subject.map(&:hostname)).to eq(%w{example1.com example2.com example3.com example4.com example5.com})
162
+ end
163
+ end
135
164
  end
136
165
 
137
- describe 'when defining role with reserved name' do
138
- it 'fails with ArgumentError' do
139
- expect {
166
+ describe "when defining role with reserved name" do
167
+ it "fails with ArgumentError" do
168
+ expect do
140
169
  dsl.role :all, %w{example1.com}
141
- }.to raise_error(ArgumentError, "all reserved name for role. Please choose another name")
170
+ end.to raise_error(ArgumentError, "all reserved name for role. Please choose another name")
142
171
  end
143
172
  end
144
173
 
145
- describe 'when defining hosts using the `role` syntax' do
174
+ describe "when defining hosts using the `role` syntax" do
146
175
  before do
147
176
  dsl.role :web, %w{example1.com example2.com example3.com}
148
177
  dsl.role :web, %w{example1.com}, active: true
@@ -152,223 +181,239 @@ describe Capistrano::DSL do
152
181
  dsl.role :db, %w{example5.com}, no_release: true
153
182
  end
154
183
 
155
- describe 'fetching all servers' do
184
+ describe "fetching all servers" do
156
185
  subject { dsl.roles(:all) }
157
186
 
158
- it 'returns all servers' do
187
+ it "returns all servers" do
159
188
  expect(subject.map(&:hostname)).to eq %w{example1.com example2.com example3.com example4.com example5.com}
160
189
  end
161
190
  end
162
191
 
163
- describe 'fetching all release servers' do
164
-
165
- context 'with no additional options' do
192
+ describe "fetching all release servers" do
193
+ context "with no additional options" do
166
194
  subject { dsl.release_roles(:all) }
167
195
 
168
- it 'returns all release servers' do
196
+ it "returns all release servers" do
169
197
  expect(subject.map(&:hostname)).to eq %w{example1.com example2.com example3.com example4.com}
170
198
  end
171
199
  end
172
200
 
173
- context 'with filter options' do
201
+ context "with filter options" do
174
202
  subject { dsl.release_roles(:all, filter: :active) }
175
203
 
176
- it 'returns all release servers that match the filter' do
204
+ it "returns all release servers that match the filter" do
177
205
  expect(subject.map(&:hostname)).to eq %w{example1.com example3.com}
178
206
  end
179
207
  end
180
208
  end
181
209
 
182
-
183
- describe 'fetching servers by role' do
210
+ describe "fetching servers by role" do
184
211
  subject { dsl.roles(:app) }
185
212
 
186
- it 'returns the servers' do
213
+ it "returns the servers" do
187
214
  expect(subject.map(&:hostname)).to eq %w{example3.com example4.com}
188
215
  end
189
216
  end
190
217
 
191
- describe 'fetching servers by an array of roles' do
218
+ describe "fetching servers by an array of roles" do
192
219
  subject { dsl.roles([:app]) }
193
220
 
194
- it 'returns the servers' do
221
+ it "returns the servers" do
195
222
  expect(subject.map(&:hostname)).to eq %w{example3.com example4.com}
196
223
  end
197
224
  end
198
225
 
199
- describe 'fetching filtered servers by role' do
226
+ describe "fetching filtered servers by role" do
200
227
  subject { dsl.roles(:app, filter: :active) }
201
228
 
202
- it 'returns the servers' do
229
+ it "returns the servers" do
203
230
  expect(subject.map(&:hostname)).to eq %w{example3.com}
204
231
  end
205
232
  end
206
233
 
207
- describe 'fetching selected servers by role' do
234
+ describe "fetching selected servers by role" do
208
235
  subject { dsl.roles(:app, select: :active) }
209
236
 
210
- it 'returns the servers' do
237
+ it "returns the servers" do
211
238
  expect(subject.map(&:hostname)).to eq %w{example3.com}
212
239
  end
213
240
  end
214
241
 
215
- describe 'fetching the primary server by role' do
216
- context 'when inferring primary status based on order' do
242
+ describe "fetching the primary server by role" do
243
+ context "when inferring primary status based on order" do
217
244
  subject { dsl.primary(:web) }
218
- it 'returns the servers' do
219
- expect(subject.hostname).to eq 'example1.com'
245
+ it "returns the servers" do
246
+ expect(subject.hostname).to eq "example1.com"
220
247
  end
221
248
  end
222
249
 
223
- context 'when the attribute `primary` is explicity set' do
250
+ context "when the attribute `primary` is explicity set" do
224
251
  subject { dsl.primary(:app) }
225
- it 'returns the servers' do
226
- expect(subject.hostname).to eq 'example4.com'
252
+ it "returns the servers" do
253
+ expect(subject.hostname).to eq "example4.com"
227
254
  end
228
255
  end
229
256
  end
230
-
231
257
  end
232
258
 
233
- describe 'when defining a host using a combination of the `server` and `role` syntax' do
234
-
259
+ describe "when defining a host using a combination of the `server` and `role` syntax" do
235
260
  before do
236
- dsl.server 'db@example1.com:1234', roles: %w{db}, active: true
237
- dsl.server 'root@example1.com:1234', roles: %w{web}, active: true
238
- dsl.server 'example1.com:5678', roles: %w{web}, active: true
261
+ dsl.server "db@example1.com:1234", roles: %w{db}, active: true
262
+ dsl.server "root@example1.com:1234", roles: %w{web}, active: true
263
+ dsl.server "example1.com:5678", roles: %w{web}, active: true
239
264
  dsl.role :app, %w{deployer@example1.com:1234}
240
265
  dsl.role :app, %w{example1.com:5678}
241
266
  end
242
267
 
243
- describe 'fetching all servers' do
244
- subject { dsl.roles(:all).map { |server| "#{server.user}@#{server.hostname}:#{server.port}" } }
245
-
246
- it 'creates a server instance for each unique user@host:port combination' do
247
- expect(subject).to eq %w{db@example1.com:1234 root@example1.com:1234 @example1.com:5678 deployer@example1.com:1234}
268
+ describe "fetching all servers" do
269
+ it "creates one server per hostname, ignoring user combinations" do
270
+ expect(dsl.roles(:all).size).to eq(2)
248
271
  end
249
272
  end
250
273
 
251
- describe 'fetching servers for a role' do
252
- it 'roles defined using the `server` syntax are included' do
253
- expect(dsl.roles(:web).size).to eq(2)
274
+ describe "fetching servers for a role" do
275
+ it "roles defined using the `server` syntax are included" do
276
+ as = dsl.roles(:web).map { |server| "#{server.user}@#{server.hostname}:#{server.port}" }
277
+ expect(as.size).to eq(2)
278
+ expect(as[0]).to eq("deployer@example1.com:1234")
279
+ expect(as[1]).to eq("@example1.com:5678")
254
280
  end
255
281
 
256
- it 'roles defined using the `role` syntax are included' do
257
- expect(dsl.roles(:app).size).to eq(2)
282
+ it "roles defined using the `role` syntax are included" do
283
+ as = dsl.roles(:app).map { |server| "#{server.user}@#{server.hostname}:#{server.port}" }
284
+ expect(as.size).to eq(2)
285
+ expect(as[0]).to eq("deployer@example1.com:1234")
286
+ expect(as[1]).to eq("@example1.com:5678")
258
287
  end
259
288
  end
260
-
261
289
  end
262
290
 
263
- end
291
+ describe "when setting user and port" do
292
+ subject { dsl.roles(:all).map { |server| "#{server.user}@#{server.hostname}:#{server.port}" }.first }
293
+
294
+ describe "using the :user property" do
295
+ it "takes precedence over in the host string" do
296
+ dsl.server "db@example1.com:1234", roles: %w{db}, active: true, user: "brian"
297
+ expect(subject).to eq("brian@example1.com:1234")
298
+ end
299
+ end
264
300
 
265
- describe 'setting and fetching variables' do
301
+ describe "using the :port property" do
302
+ it "takes precedence over in the host string" do
303
+ dsl.server "db@example1.com:9090", roles: %w{db}, active: true, port: 1234
304
+ expect(subject).to eq("db@example1.com:1234")
305
+ end
306
+ end
307
+ end
308
+ end
266
309
 
310
+ describe "setting and fetching variables" do
267
311
  before do
268
312
  dsl.set :scm, :git
269
313
  end
270
314
 
271
- context 'without a default' do
272
- context 'when the variables is defined' do
273
- it 'returns the variable' do
315
+ context "without a default" do
316
+ context "when the variables is defined" do
317
+ it "returns the variable" do
274
318
  expect(dsl.fetch(:scm)).to eq :git
275
319
  end
276
320
  end
277
321
 
278
- context 'when the variables is undefined' do
279
- it 'returns nil' do
322
+ context "when the variables is undefined" do
323
+ it "returns nil" do
280
324
  expect(dsl.fetch(:source_control)).to be_nil
281
325
  end
282
326
  end
283
327
  end
284
328
 
285
- context 'with a default' do
286
- context 'when the variables is defined' do
287
- it 'returns the variable' do
329
+ context "with a default" do
330
+ context "when the variables is defined" do
331
+ it "returns the variable" do
288
332
  expect(dsl.fetch(:scm, :svn)).to eq :git
289
333
  end
290
334
  end
291
335
 
292
- context 'when the variables is undefined' do
293
- it 'returns the default' do
336
+ context "when the variables is undefined" do
337
+ it "returns the default" do
294
338
  expect(dsl.fetch(:source_control, :svn)).to eq :svn
295
339
  end
296
340
  end
297
341
  end
298
342
 
299
- context 'with a block' do
300
- context 'when the variables is defined' do
301
- it 'returns the variable' do
343
+ context "with a block" do
344
+ context "when the variables is defined" do
345
+ it "returns the variable" do
302
346
  expect(dsl.fetch(:scm) { :svn }).to eq :git
303
347
  end
304
348
  end
305
349
 
306
- context 'when the variables is undefined' do
307
- it 'calls the block' do
350
+ context "when the variables is undefined" do
351
+ it "calls the block" do
308
352
  expect(dsl.fetch(:source_control) { :svn }).to eq :svn
309
353
  end
310
354
  end
311
355
  end
312
-
313
356
  end
314
357
 
315
- describe 'asking for a variable' do
358
+ describe "asking for a variable" do
359
+ let(:stdin) { stub(tty?: true) }
360
+
316
361
  before do
317
- dsl.ask(:scm, :svn)
362
+ dsl.ask(:scm, :svn, stdin: stdin)
318
363
  $stdout.stubs(:print)
319
364
  end
320
365
 
321
- context 'variable is provided' do
366
+ context "variable is provided" do
322
367
  before do
323
- $stdin.expects(:gets).returns('git')
368
+ stdin.expects(:gets).returns("git")
324
369
  end
325
370
 
326
- it 'sets the input as the variable' do
327
- expect(dsl.fetch(:scm)).to eq 'git'
371
+ it "sets the input as the variable" do
372
+ expect(dsl.fetch(:scm)).to eq "git"
328
373
  end
329
374
  end
330
375
 
331
- context 'variable is not provided' do
376
+ context "variable is not provided" do
332
377
  before do
333
- $stdin.expects(:gets).returns('')
378
+ stdin.expects(:gets).returns("")
334
379
  end
335
380
 
336
- it 'sets the variable as the default' do
381
+ it "sets the variable as the default" do
337
382
  expect(dsl.fetch(:scm)).to eq :svn
338
383
  end
339
384
  end
340
385
  end
341
386
 
342
- describe 'checking for presence' do
387
+ describe "checking for presence" do
343
388
  subject { dsl.any? :linked_files }
344
389
 
345
390
  before do
346
391
  dsl.set(:linked_files, linked_files)
347
392
  end
348
393
 
349
- context 'variable is an non-empty array' do
394
+ context "variable is an non-empty array" do
350
395
  let(:linked_files) { %w{1} }
351
396
 
352
397
  it { expect(subject).to be_truthy }
353
398
  end
354
399
 
355
- context 'variable is an empty array' do
400
+ context "variable is an empty array" do
356
401
  let(:linked_files) { [] }
357
402
  it { expect(subject).to be_falsey }
358
403
  end
359
404
 
360
- context 'variable exists, is not an array' do
405
+ context "variable exists, is not an array" do
361
406
  let(:linked_files) { stub }
362
407
  it { expect(subject).to be_truthy }
363
408
  end
364
409
 
365
- context 'variable is nil' do
410
+ context "variable is nil" do
366
411
  let(:linked_files) { nil }
367
412
  it { expect(subject).to be_falsey }
368
413
  end
369
414
  end
370
415
 
371
- describe 'configuration SSHKit' do
416
+ describe "configuration SSHKit" do
372
417
  let(:config) { SSHKit.config }
373
418
  let(:backend) { SSHKit.config.backend.config }
374
419
  let(:default_env) { { rails_env: :production } }
@@ -379,232 +424,209 @@ describe Capistrano::DSL do
379
424
  dsl.set(:default_env, default_env)
380
425
  dsl.set(:pty, true)
381
426
  dsl.set(:connection_timeout, 10)
382
- dsl.set(:ssh_options, {
383
- keys: %w(/home/user/.ssh/id_rsa),
384
- forward_agent: false,
385
- auth_methods: %w(publickey password)
386
- })
427
+ dsl.set(:ssh_options, keys: %w(/home/user/.ssh/id_rsa),
428
+ forward_agent: false,
429
+ auth_methods: %w(publickey password))
387
430
  dsl.configure_backend
388
431
  end
389
432
 
390
- it 'sets the output' do
433
+ it "sets the output" do
391
434
  expect(config.output).to be_a SSHKit::Formatter::Dot
392
435
  end
393
436
 
394
- it 'sets the output verbosity' do
437
+ it "sets the output verbosity" do
395
438
  expect(config.output_verbosity).to eq 0
396
439
  end
397
440
 
398
- it 'sets the default env' do
441
+ it "sets the default env" do
399
442
  expect(config.default_env).to eq default_env
400
443
  end
401
444
 
402
- it 'sets the backend pty' do
445
+ it "sets the backend pty" do
403
446
  expect(backend.pty).to be_truthy
404
447
  end
405
448
 
406
- it 'sets the backend connection timeout' do
449
+ it "sets the backend connection timeout" do
407
450
  expect(backend.connection_timeout).to eq 10
408
451
  end
409
452
 
410
- it 'sets the backend ssh_options' do
453
+ it "sets the backend ssh_options" do
411
454
  expect(backend.ssh_options[:keys]).to eq %w(/home/user/.ssh/id_rsa)
412
455
  expect(backend.ssh_options[:forward_agent]).to eq false
413
456
  expect(backend.ssh_options[:auth_methods]).to eq %w(publickey password)
414
457
  end
415
-
416
458
  end
417
459
 
418
- describe 'release path' do
419
-
420
- before do
421
- dsl.set(:deploy_to, '/var/www')
422
- end
423
-
424
- describe 'fetching release path' do
425
- subject { dsl.release_path }
426
-
427
- context 'where no release path has been set' do
428
- before do
429
- dsl.delete(:release_path)
430
- end
431
-
432
- it 'returns the `current_path` value' do
433
- expect(subject.to_s).to eq '/var/www/current'
434
- end
460
+ describe "on()" do
461
+ describe "when passed server objects" do
462
+ before do
463
+ dsl.server "example1.com", roles: %w{web}, active: true
464
+ dsl.server "example2.com", roles: %w{web}
465
+ dsl.server "example3.com", roles: %w{app web}, active: true
466
+ dsl.server "example4.com", roles: %w{app}, primary: true
467
+ dsl.server "example5.com", roles: %w{db}, no_release: true
468
+ @coordinator = mock("coordinator")
469
+ @coordinator.expects(:each).returns(nil)
470
+ ENV.delete "ROLES"
471
+ ENV.delete "HOSTS"
435
472
  end
436
473
 
437
- context 'where the release path has been set' do
438
- before do
439
- dsl.set(:release_path, '/var/www/release_path')
440
- end
441
-
442
- it 'returns the set `release_path` value' do
443
- expect(subject.to_s).to eq '/var/www/release_path'
444
- end
474
+ it "filters by role from the :filter variable" do
475
+ hosts = dsl.roles(:web)
476
+ all = dsl.roles(:all)
477
+ SSHKit::Coordinator.expects(:new).with(hosts).returns(@coordinator)
478
+ dsl.set :filter, role: "web"
479
+ dsl.on(all)
445
480
  end
446
- end
447
-
448
- describe 'setting release path' do
449
- let(:now) { Time.parse("Oct 21 16:29:00 2015") }
450
- subject { dsl.release_path }
451
481
 
452
- context 'without a timestamp' do
453
- before do
454
- dsl.env.expects(:timestamp).returns(now)
455
- dsl.set_release_path
456
- end
457
-
458
- it 'returns the release path with the current env timestamp' do
459
- expect(subject.to_s).to eq '/var/www/releases/20151021162900'
460
- end
482
+ it "filters by host and role from the :filter variable" do
483
+ all = dsl.roles(:all)
484
+ SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator)
485
+ dsl.set :filter, role: "db", host: "example3.com"
486
+ dsl.on(all)
461
487
  end
462
488
 
463
- context 'with a timestamp' do
464
- before do
465
- dsl.set_release_path('timestamp')
466
- end
467
-
468
- it 'returns the release path with the timestamp' do
469
- expect(subject.to_s).to eq '/var/www/releases/timestamp'
470
- end
489
+ it "filters by roles from the :filter variable" do
490
+ hosts = dsl.roles(:web)
491
+ all = dsl.roles(:all)
492
+ SSHKit::Coordinator.expects(:new).with(hosts).returns(@coordinator)
493
+ dsl.set :filter, roles: "web"
494
+ dsl.on(all)
471
495
  end
472
- end
473
-
474
- describe 'setting deploy configuration path' do
475
- subject { dsl.deploy_config_path.to_s }
476
496
 
477
- context 'where no config path is set' do
478
- before do
479
- dsl.delete(:deploy_config_path)
480
- end
497
+ it "filters by hosts and roles from the :filter variable" do
498
+ all = dsl.roles(:all)
499
+ SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator)
500
+ dsl.set :filter, roles: "db", hosts: "example3.com"
501
+ dsl.on(all)
502
+ end
481
503
 
482
- it 'returns "config/deploy.rb"' do
483
- expect(subject).to eq 'config/deploy.rb'
484
- end
504
+ it "filters from ENV[ROLES]" do
505
+ hosts = dsl.roles(:db)
506
+ all = dsl.roles(:all)
507
+ SSHKit::Coordinator.expects(:new).with(hosts).returns(@coordinator)
508
+ ENV["ROLES"] = "db"
509
+ dsl.on(all)
485
510
  end
486
511
 
487
- context 'where a custom path is set' do
488
- before do
489
- dsl.set(:deploy_config_path, 'my/custom/path.rb')
490
- end
512
+ it "filters from ENV[HOSTS]" do
513
+ hosts = dsl.roles(:db)
514
+ all = dsl.roles(:all)
515
+ SSHKit::Coordinator.expects(:new).with(hosts).returns(@coordinator)
516
+ ENV["HOSTS"] = "example5.com"
517
+ dsl.on(all)
518
+ end
491
519
 
492
- it 'returns the custom path' do
493
- expect(subject).to eq 'my/custom/path.rb'
494
- end
520
+ it "filters by ENV[HOSTS] && ENV[ROLES]" do
521
+ all = dsl.roles(:all)
522
+ SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator)
523
+ ENV["HOSTS"] = "example5.com"
524
+ ENV["ROLES"] = "web"
525
+ dsl.on(all)
495
526
  end
496
527
  end
497
528
 
498
- describe 'setting stage configuration path' do
499
- subject { dsl.stage_config_path.to_s }
500
-
501
- context 'where no config path is set' do
502
-
503
- before do
504
- dsl.delete(:stage_config_path)
505
- end
506
-
507
- it 'returns "config/deploy"' do
508
- expect(subject).to eq 'config/deploy'
509
- end
529
+ describe "when passed server literal names" do
530
+ before do
531
+ ENV.delete "ROLES"
532
+ ENV.delete "HOSTS"
533
+ @coordinator = mock("coordinator")
534
+ @coordinator.expects(:each).returns(nil)
510
535
  end
511
536
 
512
- context 'where a custom path is set' do
513
- before do
514
- dsl.set(:stage_config_path, 'my/custom/path')
515
- end
516
-
517
- it 'returns the custom path' do
518
- expect(subject).to eq 'my/custom/path'
519
- end
537
+ it "selects nothing when a role filter is present" do
538
+ dsl.set :filter, role: "web"
539
+ SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator)
540
+ dsl.on("my.server")
520
541
  end
521
- end
522
- end
523
-
524
- describe 'local_user' do
525
- before do
526
- dsl.set :local_user, -> { Etc.getlogin }
527
- end
528
542
 
529
- describe 'fetching local_user' do
530
- subject { dsl.local_user }
543
+ it "selects using the string when a host filter is present" do
544
+ dsl.set :filter, host: "server.local"
545
+ SSHKit::Coordinator.expects(:new).with(["server.local"]).returns(@coordinator)
546
+ dsl.on("server.local")
547
+ end
531
548
 
532
- context 'where a local_user is not set' do
533
- before do
534
- Etc.expects(:getlogin).returns('login')
535
- end
549
+ it "doesn't select when a host filter is present that doesn't match" do
550
+ dsl.set :filter, host: "ruby.local"
551
+ SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator)
552
+ dsl.on("server.local")
553
+ end
536
554
 
537
- it 'returns the login name' do
538
- expect(subject.to_s).to eq 'login'
539
- end
555
+ it "selects nothing when a roles filter is present" do
556
+ dsl.set :filter, roles: "web"
557
+ SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator)
558
+ dsl.on("my.server")
540
559
  end
541
560
 
542
- context 'where a local_user is set' do
543
- before do
544
- dsl.set(:local_user, -> { 'custom login' })
545
- end
561
+ it "selects using the string when a hosts filter is present" do
562
+ dsl.set :filter, hosts: "server.local"
563
+ SSHKit::Coordinator.expects(:new).with(["server.local"]).returns(@coordinator)
564
+ dsl.on("server.local")
565
+ end
546
566
 
547
- it 'returns the custom name' do
548
- expect(subject.to_s).to eq 'custom login'
549
- end
567
+ it "doesn't select when a hosts filter is present that doesn't match" do
568
+ dsl.set :filter, hosts: "ruby.local"
569
+ SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator)
570
+ dsl.on("server.local")
550
571
  end
551
572
  end
552
573
  end
553
574
 
554
- describe 'on()' do
555
-
575
+ describe "role_properties()" do
556
576
  before do
557
- dsl.server 'example1.com', roles: %w{web}, active: true
558
- dsl.server 'example2.com', roles: %w{web}
559
- dsl.server 'example3.com', roles: %w{app web}, active: true
560
- dsl.server 'example4.com', roles: %w{app}, primary: true
561
- dsl.server 'example5.com', roles: %w{db}, no_release: true
562
- @coordinator = mock('coordinator')
563
- @coordinator.expects(:each).returns(nil)
564
- ENV.delete 'ROLES'
565
- ENV.delete 'HOSTS'
566
-
577
+ dsl.role :redis, %w[example1.com example2.com], redis: { port: 6379, type: :slave }
578
+ dsl.server "example1.com", roles: %w{web}, active: true, web: { port: 80 }
579
+ dsl.server "example2.com", roles: %w{web redis}, web: { port: 81 }, redis: { type: :master }
580
+ dsl.server "example3.com", roles: %w{app}, primary: true
567
581
  end
568
582
 
569
- it 'filters by role from the :filter variable' do
570
- hosts = dsl.roles(:web)
571
- all = dsl.roles(:all)
572
- SSHKit::Coordinator.expects(:new).with(hosts).returns(@coordinator)
573
- dsl.set :filter, { role: 'web' }
574
- dsl.on(all)
583
+ it "retrieves properties for a single role as a set" do
584
+ rps = dsl.role_properties(:app)
585
+ expect(rps).to eq(Set[{ hostname: "example3.com", role: :app }])
575
586
  end
576
587
 
577
- it 'filters by host and role from the :filter variable' do
578
- all = dsl.roles(:all)
579
- SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator)
580
- dsl.set :filter, { role: 'db', host: 'example3.com' }
581
- dsl.on(all)
588
+ it "retrieves properties for multiple roles as a set" do
589
+ rps = dsl.role_properties(:app, :web)
590
+ expect(rps).to eq(Set[{ hostname: "example3.com", role: :app }, { hostname: "example1.com", role: :web, port: 80 }, { hostname: "example2.com", role: :web, port: 81 }])
582
591
  end
583
592
 
584
- it 'filters from ENV[ROLES]' do
585
- hosts = dsl.roles(:db)
586
- all = dsl.roles(:all)
587
- SSHKit::Coordinator.expects(:new).with(hosts).returns(@coordinator)
588
- ENV['ROLES'] = 'db'
589
- dsl.on(all)
593
+ it "yields the properties for a single role" do
594
+ recipient = mock("recipient")
595
+ recipient.expects(:doit).with("example1.com", :redis, port: 6379, type: :slave)
596
+ recipient.expects(:doit).with("example2.com", :redis, port: 6379, type: :master)
597
+ dsl.role_properties(:redis) do |host, role, props|
598
+ recipient.doit(host, role, props)
599
+ end
590
600
  end
591
601
 
592
- it 'filters from ENV[HOSTS]' do
593
- hosts = dsl.roles(:db)
594
- all = dsl.roles(:all)
595
- SSHKit::Coordinator.expects(:new).with(hosts).returns(@coordinator)
596
- ENV['HOSTS'] = 'example5.com'
597
- dsl.on(all)
602
+ it "yields the properties for multiple roles" do
603
+ recipient = mock("recipient")
604
+ recipient.expects(:doit).with("example1.com", :redis, port: 6379, type: :slave)
605
+ recipient.expects(:doit).with("example2.com", :redis, port: 6379, type: :master)
606
+ recipient.expects(:doit).with("example3.com", :app, nil)
607
+ dsl.role_properties(:redis, :app) do |host, role, props|
608
+ recipient.doit(host, role, props)
609
+ end
598
610
  end
599
611
 
600
- it 'filters by ENV[HOSTS] && ENV[ROLES]' do
601
- all = dsl.roles(:all)
602
- SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator)
603
- ENV['HOSTS'] = 'example5.com'
604
- ENV['ROLES'] = 'web'
605
- dsl.on(all)
612
+ it "yields the merged properties for multiple roles" do
613
+ recipient = mock("recipient")
614
+ recipient.expects(:doit).with("example1.com", :redis, port: 6379, type: :slave)
615
+ recipient.expects(:doit).with("example2.com", :redis, port: 6379, type: :master)
616
+ recipient.expects(:doit).with("example1.com", :web, port: 80)
617
+ recipient.expects(:doit).with("example2.com", :web, port: 81)
618
+ dsl.role_properties(:redis, :web) do |host, role, props|
619
+ recipient.doit(host, role, props)
620
+ end
606
621
  end
607
622
 
623
+ it "honours a property filter before yielding" do
624
+ recipient = mock("recipient")
625
+ recipient.expects(:doit).with("example1.com", :redis, port: 6379, type: :slave)
626
+ recipient.expects(:doit).with("example1.com", :web, port: 80)
627
+ dsl.role_properties(:redis, :web, select: :active) do |host, role, props|
628
+ recipient.doit(host, role, props)
629
+ end
630
+ end
608
631
  end
609
-
610
632
  end