capistrano 2.8.0 → 3.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.docker/Dockerfile +7 -0
- data/.docker/ssh_key_rsa +49 -0
- data/.docker/ssh_key_rsa.pub +1 -0
- data/.docker/ubuntu_setup.sh +23 -0
- data/.github/issue_template.md +19 -0
- data/.github/pull_request_template.md +22 -0
- data/.github/release-drafter.yml +25 -0
- data/.github/workflows/ci.yml +80 -0
- data/.github/workflows/release-drafter.yml +18 -0
- data/.gitignore +23 -8
- data/.rubocop.yml +62 -0
- data/CHANGELOG.md +1 -0
- data/CONTRIBUTING.md +63 -0
- data/DEVELOPMENT.md +112 -0
- data/Gemfile +42 -9
- data/LICENSE.txt +21 -0
- data/README.md +221 -0
- data/RELEASING.md +17 -0
- data/Rakefile +17 -8
- data/UPGRADING-3.7.md +86 -0
- data/bin/cap +2 -3
- data/bin/capify +7 -89
- data/capistrano.gemspec +29 -43
- data/docker-compose.yml +8 -0
- data/features/configuration.feature +28 -0
- data/features/deploy.feature +92 -0
- data/features/deploy_failure.feature +17 -0
- data/features/doctor.feature +11 -0
- data/features/installation.feature +21 -0
- data/features/sshconnect.feature +11 -0
- data/features/stage_failure.feature +9 -0
- data/features/step_definitions/assertions.rb +162 -0
- data/features/step_definitions/cap_commands.rb +21 -0
- data/features/step_definitions/setup.rb +91 -0
- data/features/subdirectory.feature +9 -0
- data/features/support/docker_gateway.rb +53 -0
- data/features/support/env.rb +1 -0
- data/features/support/remote_command_helpers.rb +29 -0
- data/features/support/remote_ssh_helpers.rb +33 -0
- data/lib/Capfile +3 -0
- data/lib/capistrano/all.rb +17 -0
- data/lib/capistrano/application.rb +153 -0
- data/lib/capistrano/configuration/empty_filter.rb +9 -0
- data/lib/capistrano/configuration/filter.rb +26 -0
- data/lib/capistrano/configuration/host_filter.rb +29 -0
- data/lib/capistrano/configuration/null_filter.rb +9 -0
- data/lib/capistrano/configuration/plugin_installer.rb +51 -0
- data/lib/capistrano/configuration/question.rb +76 -0
- data/lib/capistrano/configuration/role_filter.rb +29 -0
- data/lib/capistrano/configuration/scm_resolver.rb +149 -0
- data/lib/capistrano/configuration/server.rb +137 -0
- data/lib/capistrano/configuration/servers.rb +56 -96
- data/lib/capistrano/configuration/validated_variables.rb +110 -0
- data/lib/capistrano/configuration/variables.rb +79 -94
- data/lib/capistrano/configuration.rb +178 -33
- data/lib/capistrano/console.rb +1 -0
- data/lib/capistrano/defaults.rb +36 -0
- data/lib/capistrano/deploy.rb +3 -0
- data/lib/capistrano/doctor/environment_doctor.rb +19 -0
- data/lib/capistrano/doctor/gems_doctor.rb +45 -0
- data/lib/capistrano/doctor/output_helpers.rb +79 -0
- data/lib/capistrano/doctor/servers_doctor.rb +105 -0
- data/lib/capistrano/doctor/variables_doctor.rb +74 -0
- data/lib/capistrano/doctor.rb +6 -0
- data/lib/capistrano/dotfile.rb +2 -0
- data/lib/capistrano/dsl/env.rb +43 -0
- data/lib/capistrano/dsl/paths.rb +89 -0
- data/lib/capistrano/dsl/stages.rb +31 -0
- data/lib/capistrano/dsl/task_enhancements.rb +61 -0
- data/lib/capistrano/dsl.rb +95 -0
- data/lib/capistrano/framework.rb +2 -0
- data/lib/capistrano/i18n.rb +46 -0
- data/lib/capistrano/immutable_task.rb +30 -0
- data/lib/capistrano/install.rb +1 -0
- data/lib/capistrano/plugin.rb +95 -0
- data/lib/capistrano/proc_helpers.rb +13 -0
- data/lib/capistrano/scm/git.rb +105 -0
- data/lib/capistrano/scm/hg.rb +55 -0
- data/lib/capistrano/scm/plugin.rb +13 -0
- data/lib/capistrano/scm/svn.rb +56 -0
- data/lib/capistrano/scm/tasks/git.rake +84 -0
- data/lib/capistrano/scm/tasks/hg.rake +53 -0
- data/lib/capistrano/scm/tasks/svn.rake +53 -0
- data/lib/capistrano/scm.rb +115 -0
- data/lib/capistrano/setup.rb +36 -0
- data/lib/capistrano/tasks/console.rake +25 -0
- data/lib/capistrano/tasks/deploy.rake +280 -0
- data/lib/capistrano/tasks/doctor.rake +24 -0
- data/lib/capistrano/tasks/framework.rake +67 -0
- data/lib/capistrano/tasks/install.rake +41 -0
- data/lib/capistrano/templates/Capfile +38 -0
- data/lib/capistrano/templates/deploy.rb.erb +39 -0
- data/lib/capistrano/templates/stage.rb.erb +61 -0
- data/lib/capistrano/upload_task.rb +9 -0
- data/lib/capistrano/version.rb +1 -14
- data/lib/capistrano/version_validator.rb +32 -0
- data/lib/capistrano.rb +0 -3
- data/spec/integration/dsl_spec.rb +632 -0
- data/spec/integration_spec_helper.rb +5 -0
- data/spec/lib/capistrano/application_spec.rb +60 -0
- data/spec/lib/capistrano/configuration/empty_filter_spec.rb +17 -0
- data/spec/lib/capistrano/configuration/filter_spec.rb +109 -0
- data/spec/lib/capistrano/configuration/host_filter_spec.rb +71 -0
- data/spec/lib/capistrano/configuration/null_filter_spec.rb +17 -0
- data/spec/lib/capistrano/configuration/plugin_installer_spec.rb +98 -0
- data/spec/lib/capistrano/configuration/question_spec.rb +92 -0
- data/spec/lib/capistrano/configuration/role_filter_spec.rb +80 -0
- data/spec/lib/capistrano/configuration/scm_resolver_spec.rb +56 -0
- data/spec/lib/capistrano/configuration/server_spec.rb +309 -0
- data/spec/lib/capistrano/configuration/servers_spec.rb +331 -0
- data/spec/lib/capistrano/configuration_spec.rb +357 -0
- data/spec/lib/capistrano/doctor/environment_doctor_spec.rb +44 -0
- data/spec/lib/capistrano/doctor/gems_doctor_spec.rb +67 -0
- data/spec/lib/capistrano/doctor/output_helpers_spec.rb +47 -0
- data/spec/lib/capistrano/doctor/servers_doctor_spec.rb +86 -0
- data/spec/lib/capistrano/doctor/variables_doctor_spec.rb +89 -0
- data/spec/lib/capistrano/dsl/paths_spec.rb +228 -0
- data/spec/lib/capistrano/dsl/task_enhancements_spec.rb +108 -0
- data/spec/lib/capistrano/dsl_spec.rb +125 -0
- data/spec/lib/capistrano/immutable_task_spec.rb +31 -0
- data/spec/lib/capistrano/plugin_spec.rb +84 -0
- data/spec/lib/capistrano/scm/git_spec.rb +194 -0
- data/spec/lib/capistrano/scm/hg_spec.rb +109 -0
- data/spec/lib/capistrano/scm/svn_spec.rb +137 -0
- data/spec/lib/capistrano/scm_spec.rb +103 -0
- data/spec/lib/capistrano/upload_task_spec.rb +19 -0
- data/spec/lib/capistrano/version_validator_spec.rb +118 -0
- data/spec/lib/capistrano_spec.rb +7 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/support/matchers.rb +5 -0
- data/spec/support/tasks/database.rake +11 -0
- data/spec/support/tasks/fail.rake +8 -0
- data/spec/support/tasks/failed.rake +5 -0
- data/spec/support/tasks/plugin.rake +6 -0
- data/spec/support/tasks/root.rake +11 -0
- data/spec/support/test_app.rb +205 -0
- metadata +234 -208
- data/.rvmrc +0 -1
- data/CHANGELOG +0 -954
- data/README.mdown +0 -76
- data/lib/capistrano/callback.rb +0 -45
- data/lib/capistrano/cli/execute.rb +0 -85
- data/lib/capistrano/cli/help.rb +0 -125
- data/lib/capistrano/cli/help.txt +0 -81
- data/lib/capistrano/cli/options.rb +0 -243
- data/lib/capistrano/cli/ui.rb +0 -40
- data/lib/capistrano/cli.rb +0 -47
- data/lib/capistrano/command.rb +0 -286
- data/lib/capistrano/configuration/actions/file_transfer.rb +0 -51
- data/lib/capistrano/configuration/actions/inspect.rb +0 -46
- data/lib/capistrano/configuration/actions/invocation.rb +0 -298
- data/lib/capistrano/configuration/callbacks.rb +0 -148
- data/lib/capistrano/configuration/connections.rb +0 -230
- data/lib/capistrano/configuration/execution.rb +0 -143
- data/lib/capistrano/configuration/loading.rb +0 -197
- data/lib/capistrano/configuration/namespaces.rb +0 -197
- data/lib/capistrano/configuration/roles.rb +0 -73
- data/lib/capistrano/errors.rb +0 -19
- data/lib/capistrano/ext/string.rb +0 -5
- data/lib/capistrano/extensions.rb +0 -57
- data/lib/capistrano/logger.rb +0 -59
- data/lib/capistrano/processable.rb +0 -53
- data/lib/capistrano/recipes/compat.rb +0 -32
- data/lib/capistrano/recipes/deploy/assets.rb +0 -57
- data/lib/capistrano/recipes/deploy/dependencies.rb +0 -44
- data/lib/capistrano/recipes/deploy/local_dependency.rb +0 -54
- data/lib/capistrano/recipes/deploy/remote_dependency.rb +0 -111
- data/lib/capistrano/recipes/deploy/scm/accurev.rb +0 -169
- data/lib/capistrano/recipes/deploy/scm/base.rb +0 -196
- data/lib/capistrano/recipes/deploy/scm/bzr.rb +0 -86
- data/lib/capistrano/recipes/deploy/scm/cvs.rb +0 -153
- data/lib/capistrano/recipes/deploy/scm/darcs.rb +0 -96
- data/lib/capistrano/recipes/deploy/scm/git.rb +0 -282
- data/lib/capistrano/recipes/deploy/scm/mercurial.rb +0 -137
- data/lib/capistrano/recipes/deploy/scm/none.rb +0 -44
- data/lib/capistrano/recipes/deploy/scm/perforce.rb +0 -138
- data/lib/capistrano/recipes/deploy/scm/subversion.rb +0 -121
- data/lib/capistrano/recipes/deploy/scm.rb +0 -19
- data/lib/capistrano/recipes/deploy/strategy/base.rb +0 -88
- data/lib/capistrano/recipes/deploy/strategy/checkout.rb +0 -20
- data/lib/capistrano/recipes/deploy/strategy/copy.rb +0 -224
- data/lib/capistrano/recipes/deploy/strategy/export.rb +0 -20
- data/lib/capistrano/recipes/deploy/strategy/remote.rb +0 -52
- data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +0 -57
- data/lib/capistrano/recipes/deploy/strategy.rb +0 -19
- data/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +0 -53
- data/lib/capistrano/recipes/deploy.rb +0 -568
- data/lib/capistrano/recipes/standard.rb +0 -37
- data/lib/capistrano/recipes/templates/maintenance.rhtml +0 -53
- data/lib/capistrano/role.rb +0 -102
- data/lib/capistrano/server_definition.rb +0 -56
- data/lib/capistrano/shell.rb +0 -260
- data/lib/capistrano/ssh.rb +0 -101
- data/lib/capistrano/task_definition.rb +0 -75
- data/lib/capistrano/transfer.rb +0 -216
- data/rvmrc.sample +0 -1
- data/test/cli/execute_test.rb +0 -132
- data/test/cli/help_test.rb +0 -165
- data/test/cli/options_test.rb +0 -329
- data/test/cli/ui_test.rb +0 -28
- data/test/cli_test.rb +0 -17
- data/test/command_test.rb +0 -289
- data/test/configuration/actions/file_transfer_test.rb +0 -61
- data/test/configuration/actions/inspect_test.rb +0 -65
- data/test/configuration/actions/invocation_test.rb +0 -247
- data/test/configuration/callbacks_test.rb +0 -220
- data/test/configuration/connections_test.rb +0 -420
- data/test/configuration/execution_test.rb +0 -175
- data/test/configuration/loading_test.rb +0 -132
- data/test/configuration/namespace_dsl_test.rb +0 -311
- data/test/configuration/roles_test.rb +0 -144
- data/test/configuration/servers_test.rb +0 -183
- data/test/configuration/variables_test.rb +0 -190
- data/test/configuration_test.rb +0 -88
- data/test/deploy/local_dependency_test.rb +0 -76
- data/test/deploy/remote_dependency_test.rb +0 -135
- data/test/deploy/scm/accurev_test.rb +0 -23
- data/test/deploy/scm/base_test.rb +0 -55
- data/test/deploy/scm/bzr_test.rb +0 -51
- data/test/deploy/scm/darcs_test.rb +0 -37
- data/test/deploy/scm/git_test.rb +0 -184
- data/test/deploy/scm/mercurial_test.rb +0 -134
- data/test/deploy/scm/none_test.rb +0 -35
- data/test/deploy/scm/subversion_test.rb +0 -32
- data/test/deploy/strategy/copy_test.rb +0 -321
- data/test/extensions_test.rb +0 -69
- data/test/fixtures/cli_integration.rb +0 -5
- data/test/fixtures/config.rb +0 -5
- data/test/fixtures/custom.rb +0 -3
- data/test/logger_test.rb +0 -123
- data/test/recipes_test.rb +0 -25
- data/test/role_test.rb +0 -11
- data/test/server_definition_test.rb +0 -121
- data/test/shell_test.rb +0 -90
- data/test/ssh_test.rb +0 -113
- data/test/task_definition_test.rb +0 -116
- data/test/transfer_test.rb +0 -160
- data/test/utils.rb +0 -37
@@ -0,0 +1,26 @@
|
|
1
|
+
require "capistrano/configuration"
|
2
|
+
require "capistrano/configuration/empty_filter"
|
3
|
+
require "capistrano/configuration/host_filter"
|
4
|
+
require "capistrano/configuration/null_filter"
|
5
|
+
require "capistrano/configuration/role_filter"
|
6
|
+
|
7
|
+
module Capistrano
|
8
|
+
class Configuration
|
9
|
+
class Filter
|
10
|
+
def initialize(type, values=nil)
|
11
|
+
raise "Invalid filter type #{type}" unless %i(host role).include? type
|
12
|
+
av = Array(values)
|
13
|
+
@strategy = if av.empty? then EmptyFilter.new
|
14
|
+
elsif av.include?(:all) || av.include?("all") then NullFilter.new
|
15
|
+
elsif type == :host then HostFilter.new(values)
|
16
|
+
elsif type == :role then RoleFilter.new(values)
|
17
|
+
else NullFilter.new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def filter(servers)
|
22
|
+
@strategy.filter servers
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Capistrano
|
2
|
+
class Configuration
|
3
|
+
class HostFilter
|
4
|
+
def initialize(values)
|
5
|
+
av = Array(values).dup
|
6
|
+
av = av.flat_map { |v| v.is_a?(String) && v =~ /^(?<name>[-A-Za-z0-9.]+)(,\g<name>)*$/ ? v.split(",") : v }
|
7
|
+
@rex = regex_matcher(av)
|
8
|
+
end
|
9
|
+
|
10
|
+
def filter(servers)
|
11
|
+
Array(servers).select { |s| @rex.match s.to_s }
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def regex_matcher(values)
|
17
|
+
values.map! do |v|
|
18
|
+
case v
|
19
|
+
when Regexp then v
|
20
|
+
else
|
21
|
+
vs = v.to_s
|
22
|
+
vs =~ /^[-A-Za-z0-9.]+$/ ? /^#{Regexp.quote(vs)}$/ : Regexp.new(vs)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
Regexp.union values
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# Encapsulates the logic for installing plugins into Capistrano. Plugins must
|
2
|
+
# simply conform to a basic API; the PluginInstaller takes care of invoking the
|
3
|
+
# API at appropriate times.
|
4
|
+
#
|
5
|
+
# This class is not used directly; instead it is typically accessed via the
|
6
|
+
# `install_plugin` method of the Capistrano DSL.
|
7
|
+
#
|
8
|
+
module Capistrano
|
9
|
+
class Configuration
|
10
|
+
class PluginInstaller
|
11
|
+
# "Installs" a Plugin into Capistrano by loading its tasks, hooks, and
|
12
|
+
# defaults at the appropriate time. The hooks in particular can be
|
13
|
+
# skipped, if you want full control over when and how the plugin's tasks
|
14
|
+
# are executed. Simply pass `load_hooks:false` to opt out.
|
15
|
+
#
|
16
|
+
# The plugin class or instance may be provided. These are equivalent:
|
17
|
+
#
|
18
|
+
# install(Capistrano::SCM::Git)
|
19
|
+
# install(Capistrano::SCM::Git.new)
|
20
|
+
#
|
21
|
+
# Note that the :load_immediately flag is for internal use only and will
|
22
|
+
# be removed in an upcoming release.
|
23
|
+
#
|
24
|
+
def install(plugin, load_hooks: true, load_immediately: false)
|
25
|
+
plugin = plugin.is_a?(Class) ? plugin.new : plugin
|
26
|
+
|
27
|
+
plugin.define_tasks
|
28
|
+
plugin.register_hooks if load_hooks
|
29
|
+
@scm_installed ||= provides_scm?(plugin)
|
30
|
+
|
31
|
+
if load_immediately
|
32
|
+
plugin.set_defaults
|
33
|
+
else
|
34
|
+
Rake::Task.define_task("load:defaults") do
|
35
|
+
plugin.set_defaults
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def scm_installed?
|
41
|
+
@scm_installed
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def provides_scm?(plugin)
|
47
|
+
plugin.respond_to?(:scm?) && plugin.scm?
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Capistrano
|
2
|
+
class Configuration
|
3
|
+
class Question
|
4
|
+
def initialize(key, default, options={})
|
5
|
+
@key = key
|
6
|
+
@default = default
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def call
|
11
|
+
ask_question
|
12
|
+
value_or_default
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_reader :key, :default, :options
|
18
|
+
|
19
|
+
def ask_question
|
20
|
+
$stdout.print question
|
21
|
+
$stdout.flush
|
22
|
+
end
|
23
|
+
|
24
|
+
def value_or_default
|
25
|
+
if response.empty?
|
26
|
+
default
|
27
|
+
else
|
28
|
+
response
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def response
|
33
|
+
return @response if defined? @response
|
34
|
+
|
35
|
+
@response = (gets || "").chomp
|
36
|
+
end
|
37
|
+
|
38
|
+
def gets
|
39
|
+
return unless stdin.tty?
|
40
|
+
|
41
|
+
if echo?
|
42
|
+
stdin.gets
|
43
|
+
else
|
44
|
+
stdin.noecho(&:gets).tap { $stdout.print "\n" }
|
45
|
+
end
|
46
|
+
rescue Errno::EIO
|
47
|
+
# when stdio gets closed
|
48
|
+
return
|
49
|
+
end
|
50
|
+
|
51
|
+
def question
|
52
|
+
if prompt && default.nil?
|
53
|
+
I18n.t(:question_prompt, key: prompt, scope: :capistrano)
|
54
|
+
elsif prompt
|
55
|
+
I18n.t(:question_prompt_default, key: prompt, default_value: default, scope: :capistrano)
|
56
|
+
elsif default.nil?
|
57
|
+
I18n.t(:question, key: key, scope: :capistrano)
|
58
|
+
else
|
59
|
+
I18n.t(:question_default, key: key, default_value: default, scope: :capistrano)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def echo?
|
64
|
+
(options || {}).fetch(:echo, true)
|
65
|
+
end
|
66
|
+
|
67
|
+
def stdin
|
68
|
+
(options || {}).fetch(:stdin, $stdin)
|
69
|
+
end
|
70
|
+
|
71
|
+
def prompt
|
72
|
+
(options || {}).fetch(:prompt, nil)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Capistrano
|
2
|
+
class Configuration
|
3
|
+
class RoleFilter
|
4
|
+
def initialize(values)
|
5
|
+
av = Array(values).dup
|
6
|
+
av = av.flat_map { |v| v.is_a?(String) ? v.split(",") : v }
|
7
|
+
@rex = regex_matcher(av)
|
8
|
+
end
|
9
|
+
|
10
|
+
def filter(servers)
|
11
|
+
Array(servers).select { |s| s.is_a?(String) ? false : s.roles.any? { |r| @rex.match r } }
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def regex_matcher(values)
|
17
|
+
values.map! do |v|
|
18
|
+
case v
|
19
|
+
when Regexp then v
|
20
|
+
else
|
21
|
+
vs = v.to_s
|
22
|
+
vs =~ %r{^/(.+)/$} ? Regexp.new($1) : /^#{Regexp.quote(vs)}$/
|
23
|
+
end
|
24
|
+
end
|
25
|
+
Regexp.union values
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
module Capistrano
|
2
|
+
class Configuration
|
3
|
+
# In earlier versions of Capistrano, users would specify the desired SCM
|
4
|
+
# implementation using `set :scm, :git`, for example. Capistrano would then
|
5
|
+
# load the matching .rb file based on this variable.
|
6
|
+
#
|
7
|
+
# Now we expect users to explicitly `require` and call `new` on the desired
|
8
|
+
# SCM implementation in their Capfile. The `set` technique is deprecated.
|
9
|
+
#
|
10
|
+
# This SCMResolver class takes care of managing the transition from the old
|
11
|
+
# to new system. It maintains the legacy behavior, but prints deprecation
|
12
|
+
# warnings when it is used.
|
13
|
+
#
|
14
|
+
# To maintain backwards compatibility, the resolver will load the Git SCM by
|
15
|
+
# if default it determines that no SCM has been explicitly specified or
|
16
|
+
# loaded. To force no SCM to be used at all, use `set :scm, nil`. This hack
|
17
|
+
# won't be necessary once backwards compatibility is removed in a future
|
18
|
+
# version.
|
19
|
+
#
|
20
|
+
# TODO: Remove this class entirely in Capistrano 4.0.
|
21
|
+
#
|
22
|
+
class SCMResolver
|
23
|
+
DEFAULT_GIT = :"default-git"
|
24
|
+
|
25
|
+
include Capistrano::DSL
|
26
|
+
|
27
|
+
def resolve
|
28
|
+
return if scm_name.nil?
|
29
|
+
set(:scm, :git) if using_default_scm?
|
30
|
+
|
31
|
+
print_deprecation_warnings_if_applicable
|
32
|
+
|
33
|
+
# Note that `scm_plugin_installed?` comes from Capistrano::DSL
|
34
|
+
if scm_plugin_installed?
|
35
|
+
delete(:scm)
|
36
|
+
return
|
37
|
+
end
|
38
|
+
|
39
|
+
if built_in_scm_name?
|
40
|
+
load_built_in_scm
|
41
|
+
else
|
42
|
+
# Compatibility with existing 3.x third-party SCMs
|
43
|
+
register_legacy_scm_hooks
|
44
|
+
load_legacy_scm_by_name
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def using_default_scm?
|
51
|
+
return @using_default_scm if defined? @using_default_scm
|
52
|
+
@using_default_scm = (fetch(:scm) == DEFAULT_GIT)
|
53
|
+
end
|
54
|
+
|
55
|
+
def scm_name
|
56
|
+
fetch(:scm)
|
57
|
+
end
|
58
|
+
|
59
|
+
def load_built_in_scm
|
60
|
+
require "capistrano/scm/#{scm_name}"
|
61
|
+
scm_class = Object.const_get(built_in_scm_plugin_class_name)
|
62
|
+
# We use :load_immediately because we are initializing the SCM plugin
|
63
|
+
# late in the load process and therefore can't use the standard
|
64
|
+
# load:defaults technique.
|
65
|
+
install_plugin(scm_class, load_immediately: true)
|
66
|
+
end
|
67
|
+
|
68
|
+
def load_legacy_scm_by_name
|
69
|
+
load("capistrano/#{scm_name}.rb")
|
70
|
+
end
|
71
|
+
|
72
|
+
def third_party_scm_name?
|
73
|
+
!built_in_scm_name?
|
74
|
+
end
|
75
|
+
|
76
|
+
def built_in_scm_name?
|
77
|
+
%w(git hg svn).include?(scm_name.to_s.downcase)
|
78
|
+
end
|
79
|
+
|
80
|
+
def built_in_scm_plugin_class_name
|
81
|
+
"Capistrano::SCM::#{scm_name.to_s.capitalize}"
|
82
|
+
end
|
83
|
+
|
84
|
+
# rubocop:disable Style/GuardClause
|
85
|
+
def register_legacy_scm_hooks
|
86
|
+
if Rake::Task.task_defined?("deploy:new_release_path")
|
87
|
+
after "deploy:new_release_path", "#{scm_name}:create_release"
|
88
|
+
end
|
89
|
+
|
90
|
+
if Rake::Task.task_defined?("deploy:check")
|
91
|
+
before "deploy:check", "#{scm_name}:check"
|
92
|
+
end
|
93
|
+
|
94
|
+
if Rake::Task.task_defined?("deploy:set_current_revision")
|
95
|
+
before "deploy:set_current_revision",
|
96
|
+
"#{scm_name}:set_current_revision"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
# rubocop:enable Style/GuardClause
|
100
|
+
|
101
|
+
def print_deprecation_warnings_if_applicable
|
102
|
+
if using_default_scm?
|
103
|
+
warn_add_git_to_capfile unless scm_plugin_installed?
|
104
|
+
elsif built_in_scm_name?
|
105
|
+
warn_set_scm_is_deprecated
|
106
|
+
elsif third_party_scm_name?
|
107
|
+
warn_third_party_scm_must_be_upgraded
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def warn_set_scm_is_deprecated
|
112
|
+
$stderr.puts(<<-MESSAGE)
|
113
|
+
[Deprecation Notice] `set :scm, #{scm_name.inspect}` is deprecated.
|
114
|
+
To ensure your project is compatible with future versions of Capistrano,
|
115
|
+
remove the :scm setting and instead add these lines to your Capfile after
|
116
|
+
`require "capistrano/deploy"`:
|
117
|
+
|
118
|
+
require "capistrano/scm/#{scm_name}"
|
119
|
+
install_plugin #{built_in_scm_plugin_class_name}
|
120
|
+
|
121
|
+
MESSAGE
|
122
|
+
end
|
123
|
+
|
124
|
+
def warn_add_git_to_capfile
|
125
|
+
$stderr.puts(<<-MESSAGE)
|
126
|
+
[Deprecation Notice] Future versions of Capistrano will not load the Git SCM
|
127
|
+
plugin by default. To silence this deprecation warning, add the following to
|
128
|
+
your Capfile after `require "capistrano/deploy"`:
|
129
|
+
|
130
|
+
require "capistrano/scm/git"
|
131
|
+
install_plugin Capistrano::SCM::Git
|
132
|
+
|
133
|
+
MESSAGE
|
134
|
+
end
|
135
|
+
|
136
|
+
def warn_third_party_scm_must_be_upgraded
|
137
|
+
$stderr.puts(<<-MESSAGE)
|
138
|
+
[Deprecation Notice] `set :scm, #{scm_name.inspect}` is deprecated.
|
139
|
+
To ensure this custom SCM will work with future versions of Capistrano,
|
140
|
+
please upgrade it to a version that uses the new SCM plugin mechanism
|
141
|
+
documented here:
|
142
|
+
|
143
|
+
http://capistranorb.com/documentation/advanced-features/custom-scm
|
144
|
+
|
145
|
+
MESSAGE
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require "set"
|
2
|
+
module Capistrano
|
3
|
+
class Configuration
|
4
|
+
class Server < SSHKit::Host
|
5
|
+
extend Forwardable
|
6
|
+
def_delegators :properties, :roles, :fetch, :set
|
7
|
+
|
8
|
+
def self.[](host)
|
9
|
+
host.is_a?(Server) ? host : new(host)
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_roles(roles)
|
13
|
+
Array(roles).each { |role| add_role(role) }
|
14
|
+
self
|
15
|
+
end
|
16
|
+
alias roles= add_roles
|
17
|
+
|
18
|
+
def add_role(role)
|
19
|
+
roles.add role.to_sym
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def has_role?(role)
|
24
|
+
roles.include? role.to_sym
|
25
|
+
end
|
26
|
+
|
27
|
+
def select?(options)
|
28
|
+
options.each do |k, v|
|
29
|
+
callable = v.respond_to?(:call) ? v : ->(server) { server.fetch(v) }
|
30
|
+
result = \
|
31
|
+
case k
|
32
|
+
when :filter, :select
|
33
|
+
callable.call(self)
|
34
|
+
when :exclude
|
35
|
+
!callable.call(self)
|
36
|
+
else
|
37
|
+
fetch(k) == v
|
38
|
+
end
|
39
|
+
return false unless result
|
40
|
+
end
|
41
|
+
|
42
|
+
true
|
43
|
+
end
|
44
|
+
|
45
|
+
def primary
|
46
|
+
self if fetch(:primary)
|
47
|
+
end
|
48
|
+
|
49
|
+
def with(properties)
|
50
|
+
properties.each { |key, value| add_property(key, value) }
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
def properties
|
55
|
+
@properties ||= Properties.new
|
56
|
+
end
|
57
|
+
|
58
|
+
def netssh_options
|
59
|
+
@netssh_options ||= super.merge(fetch(:ssh_options) || {})
|
60
|
+
end
|
61
|
+
|
62
|
+
def roles_array
|
63
|
+
roles.to_a
|
64
|
+
end
|
65
|
+
|
66
|
+
def matches?(other)
|
67
|
+
# This matching logic must stay in sync with `Servers#add_host`.
|
68
|
+
hostname == other.hostname && port == other.port
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def add_property(key, value)
|
74
|
+
if respond_to?("#{key}=")
|
75
|
+
send("#{key}=", value)
|
76
|
+
else
|
77
|
+
set(key, value)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class Properties
|
82
|
+
def initialize
|
83
|
+
@properties = {}
|
84
|
+
end
|
85
|
+
|
86
|
+
def set(key, value)
|
87
|
+
pval = @properties[key]
|
88
|
+
if pval.is_a?(Hash) && value.is_a?(Hash)
|
89
|
+
pval.merge!(value)
|
90
|
+
elsif pval.is_a?(Set) && value.is_a?(Set)
|
91
|
+
pval.merge(value)
|
92
|
+
elsif pval.is_a?(Array) && value.is_a?(Array)
|
93
|
+
pval.concat value
|
94
|
+
else
|
95
|
+
@properties[key] = value
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def fetch(key)
|
100
|
+
@properties[key]
|
101
|
+
end
|
102
|
+
|
103
|
+
def respond_to_missing?(method, _include_all=false)
|
104
|
+
@properties.key?(method) || super
|
105
|
+
end
|
106
|
+
|
107
|
+
def roles
|
108
|
+
@roles ||= Set.new
|
109
|
+
end
|
110
|
+
|
111
|
+
def keys
|
112
|
+
@properties.keys
|
113
|
+
end
|
114
|
+
|
115
|
+
# rubocop:disable Style/MethodMissing
|
116
|
+
def method_missing(key, value=nil)
|
117
|
+
if value
|
118
|
+
set(lvalue(key), value)
|
119
|
+
else
|
120
|
+
fetch(key)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
# rubocop:enable Style/MethodMissing
|
124
|
+
|
125
|
+
def to_h
|
126
|
+
@properties
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def lvalue(key)
|
132
|
+
key.to_s.chomp("=").to_sym
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -1,115 +1,75 @@
|
|
1
|
+
require "set"
|
2
|
+
require "capistrano/configuration"
|
3
|
+
require "capistrano/configuration/filter"
|
4
|
+
|
1
5
|
module Capistrano
|
2
6
|
class Configuration
|
3
|
-
|
4
|
-
|
5
|
-
# The options hash accepts the same arguments as #find_servers, and any
|
6
|
-
# preexisting options there will take precedence over the options in
|
7
|
-
# the task.
|
8
|
-
def find_servers_for_task(task, options={})
|
9
|
-
find_servers(task.options.merge(options))
|
10
|
-
end
|
7
|
+
class Servers
|
8
|
+
include Enumerable
|
11
9
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
# Additionally, if the HOSTS environment variable is set, it will take
|
22
|
-
# precedence over any other options. Similarly, the ROLES environment
|
23
|
-
# variable will take precedence over other options. If both HOSTS and
|
24
|
-
# ROLES are given, HOSTS wins.
|
25
|
-
#
|
26
|
-
# Yet additionally, if the HOSTFILTER environment variable is set, it
|
27
|
-
# will limit the result to hosts found in that (comma-separated) list.
|
28
|
-
#
|
29
|
-
# If the HOSTROLEFILTER environment variable is set, it will limit the
|
30
|
-
# result to hosts found in that (comma-separated) list of roles
|
31
|
-
#
|
32
|
-
# Usage:
|
33
|
-
#
|
34
|
-
# # return all known servers
|
35
|
-
# servers = find_servers
|
36
|
-
#
|
37
|
-
# # find all servers in the app role that are not exempted from
|
38
|
-
# # deployment
|
39
|
-
# servers = find_servers :roles => :app,
|
40
|
-
# :except => { :no_release => true }
|
41
|
-
#
|
42
|
-
# # returns the given hosts, translated to ServerDefinition objects
|
43
|
-
# servers = find_servers :hosts => "jamis@example.host.com"
|
44
|
-
def find_servers(options={})
|
45
|
-
return [] if options.key?(:hosts) && (options[:hosts].nil? || [] == options[:hosts])
|
46
|
-
return [] if options.key?(:roles) && (options[:roles].nil? || [] == options[:roles])
|
47
|
-
|
48
|
-
hosts = server_list_from(ENV['HOSTS'] || options[:hosts])
|
49
|
-
|
50
|
-
if hosts.any?
|
51
|
-
if options[:skip_hostfilter]
|
52
|
-
hosts.uniq
|
53
|
-
else
|
54
|
-
filter_server_list(hosts.uniq)
|
55
|
-
end
|
10
|
+
def add_host(host, properties={})
|
11
|
+
new_host = Server[host]
|
12
|
+
new_host.port = properties[:port] if properties.key?(:port)
|
13
|
+
# This matching logic must stay in sync with `Server#matches?`.
|
14
|
+
key = ServerKey.new(new_host.hostname, new_host.port)
|
15
|
+
existing = servers_by_key[key]
|
16
|
+
if existing
|
17
|
+
existing.user = new_host.user if new_host.user
|
18
|
+
existing.with(properties)
|
56
19
|
else
|
57
|
-
|
58
|
-
roles = roles & Array(options[:roles]) if preserve_roles && !options[:roles].nil?
|
59
|
-
|
60
|
-
only = options[:only] || {}
|
61
|
-
except = options[:except] || {}
|
62
|
-
|
63
|
-
servers = roles.inject([]) { |list, role| list.concat(self.roles[role]) }
|
64
|
-
servers = servers.select { |server| only.all? { |key,value| server.options[key] == value } }
|
65
|
-
servers = servers.reject { |server| except.any? { |key,value| server.options[key] == value } }
|
66
|
-
|
67
|
-
if options[:skip_hostfilter]
|
68
|
-
servers.uniq
|
69
|
-
else
|
70
|
-
filter_server_list(servers.uniq)
|
71
|
-
end
|
20
|
+
servers_by_key[key] = new_host.with(properties)
|
72
21
|
end
|
73
22
|
end
|
74
23
|
|
75
|
-
|
24
|
+
# rubocop:disable Security/MarshalLoad
|
25
|
+
def add_role(role, hosts, options={})
|
26
|
+
options_deepcopy = Marshal.dump(options.merge(roles: role))
|
27
|
+
Array(hosts).each { |host| add_host(host, Marshal.load(options_deepcopy)) }
|
28
|
+
end
|
29
|
+
# rubocop:enable Security/MarshalLoad
|
76
30
|
|
77
|
-
def
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
31
|
+
def roles_for(names)
|
32
|
+
options = extract_options(names)
|
33
|
+
s = Filter.new(:role, names).filter(servers_by_key.values)
|
34
|
+
s.select { |server| server.select?(options) }
|
35
|
+
end
|
36
|
+
|
37
|
+
def role_properties_for(rolenames)
|
38
|
+
roles = rolenames.to_set
|
39
|
+
rps = Set.new unless block_given?
|
40
|
+
roles_for(rolenames).each do |host|
|
41
|
+
host.roles.intersection(roles).each do |role|
|
42
|
+
[host.properties.fetch(role)].flatten(1).each do |props|
|
43
|
+
if block_given?
|
44
|
+
yield host, role, props
|
45
|
+
else
|
46
|
+
rps << (props || {}).merge(role: role, hostname: host.hostname)
|
47
|
+
end
|
89
48
|
end
|
90
|
-
end
|
91
|
-
servers.select { |server| filters.include?(server) }
|
49
|
+
end
|
92
50
|
end
|
51
|
+
block_given? ? nil : rps
|
93
52
|
end
|
94
53
|
|
95
|
-
def
|
96
|
-
hosts =
|
97
|
-
hosts
|
98
|
-
hosts.map { |s| String === s ? ServerDefinition.new(s.strip) : s }
|
54
|
+
def fetch_primary(role)
|
55
|
+
hosts = roles_for([role])
|
56
|
+
hosts.find(&:primary) || hosts.first
|
99
57
|
end
|
100
58
|
|
101
|
-
def
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
59
|
+
def each
|
60
|
+
servers_by_key.values.each { |server| yield server }
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
ServerKey = Struct.new(:hostname, :port)
|
66
|
+
|
67
|
+
def servers_by_key
|
68
|
+
@servers_by_key ||= {}
|
109
69
|
end
|
110
70
|
|
111
|
-
def
|
112
|
-
|
71
|
+
def extract_options(array)
|
72
|
+
array.last.is_a?(::Hash) ? array.pop : {}
|
113
73
|
end
|
114
74
|
end
|
115
75
|
end
|