capistrano 3.4.0 → 3.17.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.circleci/config.yml +129 -0
- data/.github/issue_template.md +19 -0
- data/.github/pull_request_template.md +22 -0
- data/.github/release-drafter.yml +17 -0
- data/.github/workflows/push.yml +12 -0
- data/.gitignore +8 -5
- data/.rubocop.yml +62 -0
- data/CHANGELOG.md +1 -307
- data/CONTRIBUTING.md +63 -93
- data/DEVELOPMENT.md +127 -0
- data/Dangerfile +1 -0
- data/Gemfile +40 -3
- data/LICENSE.txt +1 -1
- data/README.md +127 -44
- data/RELEASING.md +17 -0
- data/Rakefile +13 -2
- data/UPGRADING-3.7.md +86 -0
- data/bin/cap +1 -1
- data/capistrano.gemspec +21 -24
- data/features/deploy.feature +35 -1
- data/features/doctor.feature +11 -0
- data/features/installation.feature +8 -3
- data/features/stage_failure.feature +9 -0
- data/features/step_definitions/assertions.rb +51 -18
- data/features/step_definitions/cap_commands.rb +9 -0
- data/features/step_definitions/setup.rb +53 -9
- data/features/subdirectory.feature +9 -0
- data/features/support/env.rb +5 -5
- data/features/support/remote_command_helpers.rb +12 -6
- data/features/support/vagrant_helpers.rb +17 -11
- data/lib/Capfile +1 -1
- data/lib/capistrano/all.rb +10 -10
- data/lib/capistrano/application.rb +47 -34
- data/lib/capistrano/configuration/empty_filter.rb +9 -0
- data/lib/capistrano/configuration/filter.rb +17 -47
- 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 +31 -9
- data/lib/capistrano/configuration/role_filter.rb +29 -0
- data/lib/capistrano/configuration/scm_resolver.rb +149 -0
- data/lib/capistrano/configuration/server.rb +29 -23
- data/lib/capistrano/configuration/servers.rb +21 -14
- data/lib/capistrano/configuration/validated_variables.rb +110 -0
- data/lib/capistrano/configuration/variables.rb +112 -0
- data/lib/capistrano/configuration.rb +91 -44
- data/lib/capistrano/defaults.rb +26 -4
- data/lib/capistrano/deploy.rb +1 -1
- 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 +1 -2
- data/lib/capistrano/dsl/env.rb +9 -47
- data/lib/capistrano/dsl/paths.rb +11 -25
- data/lib/capistrano/dsl/stages.rb +14 -2
- data/lib/capistrano/dsl/task_enhancements.rb +7 -12
- data/lib/capistrano/dsl.rb +47 -16
- data/lib/capistrano/framework.rb +1 -1
- data/lib/capistrano/i18n.rb +32 -24
- data/lib/capistrano/immutable_task.rb +30 -0
- data/lib/capistrano/install.rb +1 -1
- data/lib/capistrano/plugin.rb +95 -0
- data/lib/capistrano/proc_helpers.rb +13 -0
- data/lib/capistrano/scm/git.rb +100 -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 +73 -0
- data/lib/capistrano/scm/tasks/hg.rake +53 -0
- data/lib/capistrano/scm/tasks/svn.rake +53 -0
- data/lib/capistrano/scm.rb +7 -20
- data/lib/capistrano/setup.rb +20 -6
- data/lib/capistrano/tasks/console.rake +4 -8
- data/lib/capistrano/tasks/deploy.rake +105 -73
- data/lib/capistrano/tasks/doctor.rake +24 -0
- data/lib/capistrano/tasks/framework.rake +13 -14
- data/lib/capistrano/tasks/install.rake +14 -15
- data/lib/capistrano/templates/Capfile +21 -10
- data/lib/capistrano/templates/deploy.rb.erb +17 -26
- data/lib/capistrano/templates/stage.rb.erb +9 -9
- data/lib/capistrano/upload_task.rb +1 -1
- data/lib/capistrano/version.rb +1 -1
- data/lib/capistrano/version_validator.rb +5 -10
- data/spec/integration/dsl_spec.rb +289 -240
- data/spec/integration_spec_helper.rb +3 -5
- data/spec/lib/capistrano/application_spec.rb +23 -39
- data/spec/lib/capistrano/configuration/empty_filter_spec.rb +17 -0
- data/spec/lib/capistrano/configuration/filter_spec.rb +83 -85
- 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 +58 -26
- data/spec/lib/capistrano/configuration/role_filter_spec.rb +80 -0
- data/spec/lib/capistrano/configuration/scm_resolver_spec.rb +55 -0
- data/spec/lib/capistrano/configuration/server_spec.rb +106 -113
- data/spec/lib/capistrano/configuration/servers_spec.rb +129 -145
- data/spec/lib/capistrano/configuration_spec.rb +224 -63
- 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 +97 -59
- data/spec/lib/capistrano/dsl/task_enhancements_spec.rb +57 -37
- data/spec/lib/capistrano/dsl_spec.rb +84 -11
- 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 +184 -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 +7 -8
- data/spec/lib/capistrano/upload_task_spec.rb +7 -7
- data/spec/lib/capistrano/version_validator_spec.rb +61 -46
- data/spec/lib/capistrano_spec.rb +2 -3
- data/spec/spec_helper.rb +21 -8
- data/spec/support/Vagrantfile +9 -10
- data/spec/support/tasks/database.rake +3 -3
- data/spec/support/tasks/fail.rake +4 -3
- data/spec/support/tasks/failed.rake +2 -2
- data/spec/support/tasks/plugin.rake +6 -0
- data/spec/support/tasks/root.rake +4 -4
- data/spec/support/test_app.rb +64 -39
- metadata +100 -55
- data/.travis.yml +0 -13
- data/features/remote_file_task.feature +0 -14
- data/lib/capistrano/git.rb +0 -46
- data/lib/capistrano/hg.rb +0 -43
- data/lib/capistrano/svn.rb +0 -38
- data/lib/capistrano/tasks/git.rake +0 -81
- data/lib/capistrano/tasks/hg.rake +0 -52
- data/lib/capistrano/tasks/svn.rake +0 -52
- data/spec/lib/capistrano/git_spec.rb +0 -81
- data/spec/lib/capistrano/hg_spec.rb +0 -81
- data/spec/lib/capistrano/svn_spec.rb +0 -79
@@ -0,0 +1,19 @@
|
|
1
|
+
require "capistrano/doctor/output_helpers"
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module Doctor
|
5
|
+
class EnvironmentDoctor
|
6
|
+
include Capistrano::Doctor::OutputHelpers
|
7
|
+
|
8
|
+
def call
|
9
|
+
title("Environment")
|
10
|
+
puts <<-OUT.gsub(/^\s+/, "")
|
11
|
+
Ruby #{RUBY_DESCRIPTION}
|
12
|
+
Rubygems #{Gem::VERSION}
|
13
|
+
Bundler #{defined?(Bundler::VERSION) ? Bundler::VERSION : 'N/A'}
|
14
|
+
Command #{$PROGRAM_NAME} #{ARGV.join(' ')}
|
15
|
+
OUT
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "capistrano/doctor/output_helpers"
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module Doctor
|
5
|
+
# Prints table of all Capistrano-related gems and their version numbers. If
|
6
|
+
# there is a newer version of a gem available, call attention to it.
|
7
|
+
class GemsDoctor
|
8
|
+
include Capistrano::Doctor::OutputHelpers
|
9
|
+
|
10
|
+
def call
|
11
|
+
title("Gems")
|
12
|
+
table(all_gem_names) do |gem, row|
|
13
|
+
row.yellow if update_available?(gem)
|
14
|
+
row << gem
|
15
|
+
row << installed_gem_version(gem)
|
16
|
+
row << "(update available)" if update_available?(gem)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def installed_gem_version(gem_name)
|
23
|
+
Gem.loaded_specs[gem_name].version
|
24
|
+
end
|
25
|
+
|
26
|
+
def update_available?(gem_name)
|
27
|
+
latest = Gem.latest_version_for(gem_name)
|
28
|
+
return false if latest.nil?
|
29
|
+
latest > installed_gem_version(gem_name)
|
30
|
+
end
|
31
|
+
|
32
|
+
def all_gem_names
|
33
|
+
core_gem_names + plugin_gem_names
|
34
|
+
end
|
35
|
+
|
36
|
+
def core_gem_names
|
37
|
+
%w(capistrano airbrussh rake sshkit net-ssh) & Gem.loaded_specs.keys
|
38
|
+
end
|
39
|
+
|
40
|
+
def plugin_gem_names
|
41
|
+
(Gem.loaded_specs.keys - ["capistrano"]).grep(/capistrano/).sort
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Capistrano
|
2
|
+
module Doctor
|
3
|
+
# Helper methods for pretty-printing doctor output to stdout. All output
|
4
|
+
# (other than `title`) is indented by four spaces to facilitate copying and
|
5
|
+
# pasting this output into e.g. GitHub or Stack Overflow to achieve code
|
6
|
+
# formatting.
|
7
|
+
module OutputHelpers
|
8
|
+
class Row
|
9
|
+
attr_reader :color
|
10
|
+
attr_reader :values
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@values = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def <<(value)
|
17
|
+
values << value
|
18
|
+
end
|
19
|
+
|
20
|
+
def yellow
|
21
|
+
@color = :yellow
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Prints a table for a given array of records. For each record, the block
|
26
|
+
# is yielded two arguments: the record and a Row object. To print values
|
27
|
+
# for that record, add values using `row << "some value"`. A row can
|
28
|
+
# optionally be highlighted in yellow using `row.yellow`.
|
29
|
+
def table(records, &block)
|
30
|
+
return if records.empty?
|
31
|
+
rows = collect_rows(records, &block)
|
32
|
+
col_widths = calculate_column_widths(rows)
|
33
|
+
|
34
|
+
rows.each do |row|
|
35
|
+
line = row.values.each_with_index.map do |value, col|
|
36
|
+
value.to_s.ljust(col_widths[col])
|
37
|
+
end.join(" ").rstrip
|
38
|
+
line = color.colorize(line, row.color) if row.color
|
39
|
+
puts line
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Prints a title in blue with surrounding newlines.
|
44
|
+
def title(text)
|
45
|
+
# Use $stdout directly to bypass the indentation that our `puts` does.
|
46
|
+
$stdout.puts(color.colorize("\n#{text}\n", :blue))
|
47
|
+
end
|
48
|
+
|
49
|
+
# Prints text in yellow.
|
50
|
+
def warning(text)
|
51
|
+
puts color.colorize(text, :yellow)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Override `Kernel#puts` to prepend four spaces to each line.
|
55
|
+
def puts(string=nil)
|
56
|
+
$stdout.puts(string.to_s.gsub(/^/, " "))
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def collect_rows(records)
|
62
|
+
records.map do |rec|
|
63
|
+
Row.new.tap { |row| yield(rec, row) }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def calculate_column_widths(rows)
|
68
|
+
num_columns = rows.map { |row| row.values.length }.max
|
69
|
+
Array.new(num_columns) do |col|
|
70
|
+
rows.map { |row| row.values[col].to_s.length }.max
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def color
|
75
|
+
@color ||= SSHKit::Color.new($stdout)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require "capistrano/doctor/output_helpers"
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module Doctor
|
5
|
+
class ServersDoctor
|
6
|
+
include Capistrano::Doctor::OutputHelpers
|
7
|
+
|
8
|
+
def initialize(env=Capistrano::Configuration.env)
|
9
|
+
@servers = env.servers.to_a
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
title("Servers (#{servers.size})")
|
14
|
+
rwc = RoleWhitespaceChecker.new(servers)
|
15
|
+
|
16
|
+
table(servers) do |server, row|
|
17
|
+
sd = ServerDecorator.new(server)
|
18
|
+
|
19
|
+
row << sd.uri_form
|
20
|
+
row << sd.roles
|
21
|
+
row << sd.properties
|
22
|
+
row.yellow if rwc.any_has_whitespace?(server.roles)
|
23
|
+
end
|
24
|
+
|
25
|
+
if rwc.whitespace_roles.any?
|
26
|
+
warning "\nWhitespace detected in role(s) #{rwc.whitespace_roles_decorated}. " \
|
27
|
+
"This might be a result of a mistyped \"%w()\" array literal."
|
28
|
+
end
|
29
|
+
puts
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :servers
|
35
|
+
|
36
|
+
class RoleWhitespaceChecker
|
37
|
+
attr_reader :whitespace_roles, :servers
|
38
|
+
|
39
|
+
def initialize(servers)
|
40
|
+
@servers = servers
|
41
|
+
@whitespace_roles = find_whitespace_roles
|
42
|
+
end
|
43
|
+
|
44
|
+
def any_has_whitespace?(roles)
|
45
|
+
roles.any? { |role| include_whitespace?(role) }
|
46
|
+
end
|
47
|
+
|
48
|
+
def include_whitespace?(role)
|
49
|
+
role =~ /\s/
|
50
|
+
end
|
51
|
+
|
52
|
+
def whitespace_roles_decorated
|
53
|
+
whitespace_roles.map(&:inspect).join(", ")
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def find_whitespace_roles
|
59
|
+
servers.map(&:roles).flat_map(&:to_a).uniq
|
60
|
+
.select { |role| include_whitespace?(role) }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class ServerDecorator
|
65
|
+
def initialize(server)
|
66
|
+
@server = server
|
67
|
+
end
|
68
|
+
|
69
|
+
def uri_form
|
70
|
+
[
|
71
|
+
server.user,
|
72
|
+
server.user && "@",
|
73
|
+
server.hostname,
|
74
|
+
server.port && ":",
|
75
|
+
server.port
|
76
|
+
].compact.join
|
77
|
+
end
|
78
|
+
|
79
|
+
def roles
|
80
|
+
server.roles.to_a.inspect
|
81
|
+
end
|
82
|
+
|
83
|
+
def properties
|
84
|
+
return "" unless server.properties.keys.any?
|
85
|
+
pretty_inspect(server.properties.to_h)
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
attr_reader :server
|
91
|
+
|
92
|
+
# Hashes with proper padding
|
93
|
+
def pretty_inspect(element)
|
94
|
+
return element.inspect unless element.is_a?(Hash)
|
95
|
+
|
96
|
+
pairs_string = element.keys.map do |key|
|
97
|
+
[pretty_inspect(key), pretty_inspect(element.fetch(key))].join(" => ")
|
98
|
+
end.join(", ")
|
99
|
+
|
100
|
+
"{ #{pairs_string} }"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require "capistrano/doctor/output_helpers"
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module Doctor
|
5
|
+
# Prints a table of all Capistrano variables and their current values. If
|
6
|
+
# there are unrecognized variables, print warnings for them.
|
7
|
+
class VariablesDoctor
|
8
|
+
# These are keys that are recognized by Capistrano, but do not have values
|
9
|
+
# set by default.
|
10
|
+
WHITELIST = %i(
|
11
|
+
application
|
12
|
+
current_directory
|
13
|
+
linked_dirs
|
14
|
+
linked_files
|
15
|
+
releases_directory
|
16
|
+
repo_url
|
17
|
+
repo_tree
|
18
|
+
shared_directory
|
19
|
+
).freeze
|
20
|
+
private_constant :WHITELIST
|
21
|
+
|
22
|
+
include Capistrano::Doctor::OutputHelpers
|
23
|
+
|
24
|
+
def initialize(env=Capistrano::Configuration.env)
|
25
|
+
@env = env
|
26
|
+
end
|
27
|
+
|
28
|
+
def call
|
29
|
+
title("Variables")
|
30
|
+
values = inspect_all_values
|
31
|
+
|
32
|
+
table(variables.keys.sort_by(&:to_s)) do |key, row|
|
33
|
+
row.yellow if suspicious_keys.include?(key)
|
34
|
+
row << key.inspect
|
35
|
+
row << values[key]
|
36
|
+
end
|
37
|
+
|
38
|
+
puts if suspicious_keys.any?
|
39
|
+
|
40
|
+
suspicious_keys.sort_by(&:to_s).each do |key|
|
41
|
+
warning("#{key.inspect} is not a recognized Capistrano setting "\
|
42
|
+
"(#{location(key)})")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
attr_reader :env
|
49
|
+
|
50
|
+
def variables
|
51
|
+
env.variables
|
52
|
+
end
|
53
|
+
|
54
|
+
def inspect_all_values
|
55
|
+
variables.keys.each_with_object({}) do |key, inspected|
|
56
|
+
inspected[key] = if env.is_question?(key)
|
57
|
+
"<ask>"
|
58
|
+
else
|
59
|
+
variables.peek(key).inspect
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def suspicious_keys
|
65
|
+
(variables.untrusted_keys & variables.unused_keys) - WHITELIST
|
66
|
+
end
|
67
|
+
|
68
|
+
def location(key)
|
69
|
+
loc = variables.source_locations(key).first
|
70
|
+
loc && loc.sub(/^#{Regexp.quote(Dir.pwd)}/, "").sub(/:in.*/, "")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/capistrano/dotfile.rb
CHANGED
data/lib/capistrano/dsl/env.rb
CHANGED
@@ -1,47 +1,14 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
1
3
|
module Capistrano
|
2
4
|
module DSL
|
3
5
|
module Env
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
env.fetch(key, default, &block)
|
11
|
-
end
|
12
|
-
|
13
|
-
def any?(key)
|
14
|
-
value = fetch(key)
|
15
|
-
if value && value.respond_to?(:any?)
|
16
|
-
value.any?
|
17
|
-
else
|
18
|
-
!fetch(key).nil?
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def set(key, value)
|
23
|
-
env.set(key, value)
|
24
|
-
end
|
25
|
-
|
26
|
-
def set_if_empty(key, value)
|
27
|
-
env.set_if_empty(key, value)
|
28
|
-
end
|
29
|
-
|
30
|
-
def delete(key)
|
31
|
-
env.delete(key)
|
32
|
-
end
|
33
|
-
|
34
|
-
def ask(key, value, options={})
|
35
|
-
env.ask(key, value, options)
|
36
|
-
end
|
37
|
-
|
38
|
-
def role(name, servers, options={})
|
39
|
-
env.role(name, servers, options)
|
40
|
-
end
|
41
|
-
|
42
|
-
def server(name, properties={})
|
43
|
-
env.server(name, properties)
|
44
|
-
end
|
6
|
+
extend Forwardable
|
7
|
+
def_delegators :env,
|
8
|
+
:configure_backend, :fetch, :set, :set_if_empty, :delete,
|
9
|
+
:ask, :role, :server, :primary, :validate, :append,
|
10
|
+
:remove, :dry_run?, :install_plugin, :any?, :is_question?,
|
11
|
+
:configure_scm, :scm_plugin_installed?
|
45
12
|
|
46
13
|
def roles(*names)
|
47
14
|
env.roles_for(names.flatten)
|
@@ -53,17 +20,13 @@ module Capistrano
|
|
53
20
|
|
54
21
|
def release_roles(*names)
|
55
22
|
if names.last.is_a? Hash
|
56
|
-
names.last
|
23
|
+
names.last[:exclude] = :no_release
|
57
24
|
else
|
58
25
|
names << { exclude: :no_release }
|
59
26
|
end
|
60
27
|
roles(*names)
|
61
28
|
end
|
62
29
|
|
63
|
-
def primary(role)
|
64
|
-
env.primary(role)
|
65
|
-
end
|
66
|
-
|
67
30
|
def env
|
68
31
|
Configuration.env
|
69
32
|
end
|
@@ -75,7 +38,6 @@ module Capistrano
|
|
75
38
|
def asset_timestamp
|
76
39
|
env.timestamp.strftime("%Y%m%d%H%M.%S")
|
77
40
|
end
|
78
|
-
|
79
41
|
end
|
80
42
|
end
|
81
43
|
end
|
data/lib/capistrano/dsl/paths.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
|
-
require
|
1
|
+
require "pathname"
|
2
2
|
module Capistrano
|
3
3
|
module DSL
|
4
4
|
module Paths
|
5
|
-
|
6
5
|
def deploy_to
|
7
6
|
fetch(:deploy_to)
|
8
7
|
end
|
@@ -12,15 +11,15 @@ module Capistrano
|
|
12
11
|
end
|
13
12
|
|
14
13
|
def current_path
|
15
|
-
deploy_path.join(
|
14
|
+
deploy_path.join(fetch(:current_directory, "current"))
|
16
15
|
end
|
17
16
|
|
18
17
|
def releases_path
|
19
|
-
deploy_path.join(
|
18
|
+
deploy_path.join(fetch(:releases_directory, "releases"))
|
20
19
|
end
|
21
20
|
|
22
21
|
def release_path
|
23
|
-
fetch(:release_path
|
22
|
+
fetch(:release_path) { current_path }
|
24
23
|
end
|
25
24
|
|
26
25
|
def set_release_path(timestamp=now)
|
@@ -29,40 +28,27 @@ module Capistrano
|
|
29
28
|
end
|
30
29
|
|
31
30
|
def stage_config_path
|
32
|
-
Pathname.new fetch(:stage_config_path,
|
31
|
+
Pathname.new fetch(:stage_config_path, "config/deploy")
|
33
32
|
end
|
34
33
|
|
35
34
|
def deploy_config_path
|
36
|
-
Pathname.new fetch(:deploy_config_path,
|
35
|
+
Pathname.new fetch(:deploy_config_path, "config/deploy.rb")
|
37
36
|
end
|
38
37
|
|
39
38
|
def repo_url
|
40
|
-
|
41
|
-
require 'uri'
|
42
|
-
if fetch(:git_http_username) and fetch(:git_http_password)
|
43
|
-
URI.parse(fetch(:repo_url)).tap do |repo_uri|
|
44
|
-
repo_uri.user = fetch(:git_http_username)
|
45
|
-
repo_uri.password = CGI.escape(fetch(:git_http_password))
|
46
|
-
end.to_s
|
47
|
-
elsif fetch(:git_http_username)
|
48
|
-
URI.parse(fetch(:repo_url)).tap do |repo_uri|
|
49
|
-
repo_uri.user = fetch(:git_http_username)
|
50
|
-
end.to_s
|
51
|
-
else
|
52
|
-
fetch(:repo_url)
|
53
|
-
end
|
39
|
+
fetch(:repo_url)
|
54
40
|
end
|
55
41
|
|
56
42
|
def repo_path
|
57
|
-
Pathname.new(fetch(:repo_path, ->(){deploy_path.join(
|
43
|
+
Pathname.new(fetch(:repo_path, ->() { deploy_path.join("repo") }))
|
58
44
|
end
|
59
45
|
|
60
46
|
def shared_path
|
61
|
-
deploy_path.join(
|
47
|
+
deploy_path.join(fetch(:shared_directory, "shared"))
|
62
48
|
end
|
63
49
|
|
64
50
|
def revision_log
|
65
|
-
deploy_path.join(
|
51
|
+
deploy_path.join("revisions.log")
|
66
52
|
end
|
67
53
|
|
68
54
|
def now
|
@@ -96,7 +82,7 @@ module Capistrano
|
|
96
82
|
end
|
97
83
|
|
98
84
|
def map_dirnames(paths)
|
99
|
-
paths.map
|
85
|
+
paths.map(&:dirname).uniq
|
100
86
|
end
|
101
87
|
end
|
102
88
|
end
|
@@ -1,19 +1,31 @@
|
|
1
1
|
module Capistrano
|
2
2
|
module DSL
|
3
3
|
module Stages
|
4
|
+
RESERVED_NAMES = %w(deploy doctor install).freeze
|
5
|
+
private_constant :RESERVED_NAMES
|
4
6
|
|
5
7
|
def stages
|
6
|
-
Dir[stage_definitions].map { |f| File.basename(f,
|
8
|
+
names = Dir[stage_definitions].map { |f| File.basename(f, ".rb") }
|
9
|
+
assert_valid_stage_names(names)
|
10
|
+
names
|
7
11
|
end
|
8
12
|
|
9
13
|
def stage_definitions
|
10
|
-
stage_config_path.join(
|
14
|
+
stage_config_path.join("*.rb")
|
11
15
|
end
|
12
16
|
|
13
17
|
def stage_set?
|
14
18
|
!!fetch(:stage, false)
|
15
19
|
end
|
16
20
|
|
21
|
+
private
|
22
|
+
|
23
|
+
def assert_valid_stage_names(names)
|
24
|
+
invalid = names.find { |n| RESERVED_NAMES.include?(n) }
|
25
|
+
return if invalid.nil?
|
26
|
+
|
27
|
+
raise t("error.invalid_stage_name", name: invalid, path: stage_config_path.join("#{invalid}.rb"))
|
28
|
+
end
|
17
29
|
end
|
18
30
|
end
|
19
31
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "capistrano/upload_task"
|
2
2
|
|
3
3
|
module Capistrano
|
4
4
|
module TaskEnhancements
|
@@ -9,17 +9,14 @@ module Capistrano
|
|
9
9
|
|
10
10
|
def after(task, post_task, *args, &block)
|
11
11
|
Rake::Task.define_task(post_task, *args, &block) if block_given?
|
12
|
-
|
13
|
-
|
14
|
-
post_task.
|
12
|
+
task = Rake::Task[task]
|
13
|
+
task.enhance do
|
14
|
+
post = Rake.application.lookup(post_task, task.scope)
|
15
|
+
raise ArgumentError, "Task #{post_task.inspect} not found" unless post
|
16
|
+
post.invoke
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
18
|
-
def remote_file(task)
|
19
|
-
target_roles = task.delete(:roles) { :all }
|
20
|
-
define_remote_file_task(task, target_roles)
|
21
|
-
end
|
22
|
-
|
23
20
|
def define_remote_file_task(task, target_roles)
|
24
21
|
Capistrano::UploadTask.define_task(task) do |t|
|
25
22
|
prerequisite_file = t.prerequisites.first
|
@@ -31,7 +28,6 @@ module Capistrano
|
|
31
28
|
upload! File.open(prerequisite_file), file
|
32
29
|
end
|
33
30
|
end
|
34
|
-
|
35
31
|
end
|
36
32
|
end
|
37
33
|
|
@@ -54,13 +50,12 @@ module Capistrano
|
|
54
50
|
|
55
51
|
def exit_deploy_because_of_exception(ex)
|
56
52
|
warn t(:deploy_failed, ex: ex.message)
|
57
|
-
invoke
|
53
|
+
invoke "deploy:failed"
|
58
54
|
exit(false)
|
59
55
|
end
|
60
56
|
|
61
57
|
def deploying?
|
62
58
|
fetch(:deploying, false)
|
63
59
|
end
|
64
|
-
|
65
60
|
end
|
66
61
|
end
|
data/lib/capistrano/dsl.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require 'capistrano/configuration/filter'
|
1
|
+
require "capistrano/dsl/task_enhancements"
|
2
|
+
require "capistrano/dsl/paths"
|
3
|
+
require "capistrano/dsl/stages"
|
4
|
+
require "capistrano/dsl/env"
|
5
|
+
require "capistrano/configuration/filter"
|
7
6
|
|
8
7
|
module Capistrano
|
9
8
|
module DSL
|
@@ -12,12 +11,29 @@ module Capistrano
|
|
12
11
|
include Paths
|
13
12
|
include Stages
|
14
13
|
|
15
|
-
def invoke(
|
16
|
-
Rake::Task[
|
14
|
+
def invoke(task_name, *args)
|
15
|
+
task = Rake::Task[task_name]
|
16
|
+
# NOTE: We access instance variable since the accessor was only added recently. Once Capistrano depends on rake 11+, we can revert the following line
|
17
|
+
if task && task.instance_variable_get(:@already_invoked)
|
18
|
+
file, line, = caller.first.split(":")
|
19
|
+
colors = SSHKit::Color.new($stderr)
|
20
|
+
$stderr.puts colors.colorize("Skipping task `#{task_name}'.", :yellow)
|
21
|
+
$stderr.puts "Capistrano tasks may only be invoked once. Since task `#{task}' was previously invoked, invoke(\"#{task_name}\") at #{file}:#{line} will be skipped."
|
22
|
+
$stderr.puts "If you really meant to run this task again, use invoke!(\"#{task_name}\")"
|
23
|
+
$stderr.puts colors.colorize("THIS BEHAVIOR MAY CHANGE IN A FUTURE VERSION OF CAPISTRANO. Please join the conversation here if this affects you.", :red)
|
24
|
+
$stderr.puts colors.colorize("https://github.com/capistrano/capistrano/issues/1686", :red)
|
25
|
+
end
|
26
|
+
task.invoke(*args)
|
27
|
+
end
|
28
|
+
|
29
|
+
def invoke!(task_name, *args)
|
30
|
+
task = Rake::Task[task_name]
|
31
|
+
task.reenable
|
32
|
+
task.invoke(*args)
|
17
33
|
end
|
18
34
|
|
19
35
|
def t(key, options={})
|
20
|
-
I18n.t(key, options.merge(scope: :capistrano))
|
36
|
+
I18n.t(key, **options.merge(scope: :capistrano))
|
21
37
|
end
|
22
38
|
|
23
39
|
def scm
|
@@ -30,12 +46,11 @@ module Capistrano
|
|
30
46
|
|
31
47
|
def revision_log_message
|
32
48
|
fetch(:revision_log_message,
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
)
|
49
|
+
t(:revision_log_message,
|
50
|
+
branch: fetch(:branch),
|
51
|
+
user: local_user,
|
52
|
+
sha: fetch(:current_revision),
|
53
|
+
release: fetch(:release_timestamp)))
|
39
54
|
end
|
40
55
|
|
41
56
|
def rollback_log_message
|
@@ -50,15 +65,31 @@ module Capistrano
|
|
50
65
|
VersionValidator.new(locked_version).verify
|
51
66
|
end
|
52
67
|
|
68
|
+
# rubocop:disable Security/MarshalLoad
|
53
69
|
def on(hosts, options={}, &block)
|
54
70
|
subset_copy = Marshal.dump(Configuration.env.filter(hosts))
|
55
71
|
SSHKit::Coordinator.new(Marshal.load(subset_copy)).each(options, &block)
|
56
72
|
end
|
73
|
+
# rubocop:enable Security/MarshalLoad
|
57
74
|
|
58
75
|
def run_locally(&block)
|
59
76
|
SSHKit::Backend::Local.new(&block).run
|
60
77
|
end
|
61
78
|
|
79
|
+
# Catch common beginner mistake and give a helpful error message on stderr
|
80
|
+
def execute(*)
|
81
|
+
file, line, = caller.first.split(":")
|
82
|
+
colors = SSHKit::Color.new($stderr)
|
83
|
+
$stderr.puts colors.colorize("Warning: `execute' should be wrapped in an `on' scope in #{file}:#{line}.", :red)
|
84
|
+
$stderr.puts
|
85
|
+
$stderr.puts " task :example do"
|
86
|
+
$stderr.puts colors.colorize(" on roles(:app) do", :yellow)
|
87
|
+
$stderr.puts " execute 'whoami'"
|
88
|
+
$stderr.puts colors.colorize(" end", :yellow)
|
89
|
+
$stderr.puts " end"
|
90
|
+
$stderr.puts
|
91
|
+
raise NoMethodError, "undefined method `execute' for main:Object"
|
92
|
+
end
|
62
93
|
end
|
63
94
|
end
|
64
|
-
|
95
|
+
extend Capistrano::DSL
|
data/lib/capistrano/framework.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
load File.expand_path("../tasks/framework.rake", __FILE__)
|
2
|
-
require
|
2
|
+
require "capistrano/install"
|