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,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
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module DSL
|
5
|
+
module Env
|
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?
|
12
|
+
|
13
|
+
def roles(*names)
|
14
|
+
env.roles_for(names.flatten)
|
15
|
+
end
|
16
|
+
|
17
|
+
def role_properties(*names, &block)
|
18
|
+
env.role_properties_for(names, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def release_roles(*names)
|
22
|
+
if names.last.is_a? Hash
|
23
|
+
names.last[:exclude] = :no_release
|
24
|
+
else
|
25
|
+
names << { exclude: :no_release }
|
26
|
+
end
|
27
|
+
roles(*names)
|
28
|
+
end
|
29
|
+
|
30
|
+
def env
|
31
|
+
Configuration.env
|
32
|
+
end
|
33
|
+
|
34
|
+
def release_timestamp
|
35
|
+
env.timestamp.strftime("%Y%m%d%H%M%S")
|
36
|
+
end
|
37
|
+
|
38
|
+
def asset_timestamp
|
39
|
+
env.timestamp.strftime("%Y%m%d%H%M.%S")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require "pathname"
|
2
|
+
module Capistrano
|
3
|
+
module DSL
|
4
|
+
module Paths
|
5
|
+
def deploy_to
|
6
|
+
fetch(:deploy_to)
|
7
|
+
end
|
8
|
+
|
9
|
+
def deploy_path
|
10
|
+
Pathname.new(deploy_to)
|
11
|
+
end
|
12
|
+
|
13
|
+
def current_path
|
14
|
+
deploy_path.join(fetch(:current_directory, "current"))
|
15
|
+
end
|
16
|
+
|
17
|
+
def releases_path
|
18
|
+
deploy_path.join(fetch(:releases_directory, "releases"))
|
19
|
+
end
|
20
|
+
|
21
|
+
def release_path
|
22
|
+
fetch(:release_path) { current_path }
|
23
|
+
end
|
24
|
+
|
25
|
+
def set_release_path(timestamp=now)
|
26
|
+
set(:release_timestamp, timestamp)
|
27
|
+
set(:release_path, releases_path.join(timestamp))
|
28
|
+
end
|
29
|
+
|
30
|
+
def stage_config_path
|
31
|
+
Pathname.new fetch(:stage_config_path, "config/deploy")
|
32
|
+
end
|
33
|
+
|
34
|
+
def deploy_config_path
|
35
|
+
Pathname.new fetch(:deploy_config_path, "config/deploy.rb")
|
36
|
+
end
|
37
|
+
|
38
|
+
def repo_url
|
39
|
+
fetch(:repo_url)
|
40
|
+
end
|
41
|
+
|
42
|
+
def repo_path
|
43
|
+
Pathname.new(fetch(:repo_path, ->() { deploy_path.join("repo") }))
|
44
|
+
end
|
45
|
+
|
46
|
+
def shared_path
|
47
|
+
deploy_path.join(fetch(:shared_directory, "shared"))
|
48
|
+
end
|
49
|
+
|
50
|
+
def revision_log
|
51
|
+
deploy_path.join("revisions.log")
|
52
|
+
end
|
53
|
+
|
54
|
+
def now
|
55
|
+
env.timestamp.strftime("%Y%m%d%H%M%S")
|
56
|
+
end
|
57
|
+
|
58
|
+
def asset_timestamp
|
59
|
+
env.timestamp.strftime("%Y%m%d%H%M.%S")
|
60
|
+
end
|
61
|
+
|
62
|
+
def linked_dirs(parent)
|
63
|
+
paths = fetch(:linked_dirs)
|
64
|
+
join_paths(parent, paths)
|
65
|
+
end
|
66
|
+
|
67
|
+
def linked_files(parent)
|
68
|
+
paths = fetch(:linked_files)
|
69
|
+
join_paths(parent, paths)
|
70
|
+
end
|
71
|
+
|
72
|
+
def linked_file_dirs(parent)
|
73
|
+
map_dirnames(linked_files(parent))
|
74
|
+
end
|
75
|
+
|
76
|
+
def linked_dir_parents(parent)
|
77
|
+
map_dirnames(linked_dirs(parent))
|
78
|
+
end
|
79
|
+
|
80
|
+
def join_paths(parent, paths)
|
81
|
+
paths.map { |path| parent.join(path) }
|
82
|
+
end
|
83
|
+
|
84
|
+
def map_dirnames(paths)
|
85
|
+
paths.map(&:dirname).uniq
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Capistrano
|
2
|
+
module DSL
|
3
|
+
module Stages
|
4
|
+
RESERVED_NAMES = %w(deploy doctor install).freeze
|
5
|
+
private_constant :RESERVED_NAMES
|
6
|
+
|
7
|
+
def stages
|
8
|
+
names = Dir[stage_definitions].map { |f| File.basename(f, ".rb") }
|
9
|
+
assert_valid_stage_names(names)
|
10
|
+
names
|
11
|
+
end
|
12
|
+
|
13
|
+
def stage_definitions
|
14
|
+
stage_config_path.join("*.rb")
|
15
|
+
end
|
16
|
+
|
17
|
+
def stage_set?
|
18
|
+
!!fetch(:stage, false)
|
19
|
+
end
|
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
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require "capistrano/upload_task"
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module TaskEnhancements
|
5
|
+
def before(task, prerequisite, *args, &block)
|
6
|
+
prerequisite = Rake::Task.define_task(prerequisite, *args, &block) if block_given?
|
7
|
+
Rake::Task[task].enhance [prerequisite]
|
8
|
+
end
|
9
|
+
|
10
|
+
def after(task, post_task, *args, &block)
|
11
|
+
Rake::Task.define_task(post_task, *args, &block) if block_given?
|
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
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def define_remote_file_task(task, target_roles)
|
21
|
+
Capistrano::UploadTask.define_task(task) do |t|
|
22
|
+
prerequisite_file = t.prerequisites.first
|
23
|
+
file = shared_path.join(t.name)
|
24
|
+
|
25
|
+
on roles(target_roles) do
|
26
|
+
unless test "[ -f #{file.to_s.shellescape} ]"
|
27
|
+
info "Uploading #{prerequisite_file} to #{file}"
|
28
|
+
upload! File.open(prerequisite_file), file
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def ensure_stage
|
35
|
+
Rake::Task.define_task(:ensure_stage) do
|
36
|
+
unless stage_set?
|
37
|
+
puts t(:stage_not_set)
|
38
|
+
exit 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def tasks_without_stage_dependency
|
44
|
+
stages + default_tasks
|
45
|
+
end
|
46
|
+
|
47
|
+
def default_tasks
|
48
|
+
%w{install}
|
49
|
+
end
|
50
|
+
|
51
|
+
def exit_deploy_because_of_exception(ex)
|
52
|
+
warn t(:deploy_failed, ex: ex.message)
|
53
|
+
invoke "deploy:failed"
|
54
|
+
exit(false)
|
55
|
+
end
|
56
|
+
|
57
|
+
def deploying?
|
58
|
+
fetch(:deploying, false)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,95 @@
|
|
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"
|
6
|
+
|
7
|
+
module Capistrano
|
8
|
+
module DSL
|
9
|
+
include TaskEnhancements
|
10
|
+
include Env
|
11
|
+
include Paths
|
12
|
+
include Stages
|
13
|
+
|
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)
|
33
|
+
end
|
34
|
+
|
35
|
+
def t(key, options={})
|
36
|
+
I18n.t(key, **options.merge(scope: :capistrano))
|
37
|
+
end
|
38
|
+
|
39
|
+
def scm
|
40
|
+
fetch(:scm)
|
41
|
+
end
|
42
|
+
|
43
|
+
def sudo(*args)
|
44
|
+
execute :sudo, *args
|
45
|
+
end
|
46
|
+
|
47
|
+
def revision_log_message
|
48
|
+
fetch(:revision_log_message,
|
49
|
+
t(:revision_log_message,
|
50
|
+
branch: fetch(:branch),
|
51
|
+
user: local_user,
|
52
|
+
sha: fetch(:current_revision),
|
53
|
+
release: fetch(:release_timestamp)))
|
54
|
+
end
|
55
|
+
|
56
|
+
def rollback_log_message
|
57
|
+
t(:rollback_log_message, user: local_user, release: fetch(:rollback_timestamp))
|
58
|
+
end
|
59
|
+
|
60
|
+
def local_user
|
61
|
+
fetch(:local_user)
|
62
|
+
end
|
63
|
+
|
64
|
+
def lock(locked_version)
|
65
|
+
VersionValidator.new(locked_version).verify
|
66
|
+
end
|
67
|
+
|
68
|
+
# rubocop:disable Security/MarshalLoad
|
69
|
+
def on(hosts, options={}, &block)
|
70
|
+
subset_copy = Marshal.dump(Configuration.env.filter(hosts))
|
71
|
+
SSHKit::Coordinator.new(Marshal.load(subset_copy)).each(options, &block)
|
72
|
+
end
|
73
|
+
# rubocop:enable Security/MarshalLoad
|
74
|
+
|
75
|
+
def run_locally(&block)
|
76
|
+
SSHKit::Backend::Local.new(&block).run
|
77
|
+
end
|
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
|
93
|
+
end
|
94
|
+
end
|
95
|
+
extend Capistrano::DSL
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "i18n"
|
2
|
+
|
3
|
+
en = {
|
4
|
+
starting: "Starting",
|
5
|
+
capified: "Capified",
|
6
|
+
start: "Start",
|
7
|
+
update: "Update",
|
8
|
+
finalize: "Finalise",
|
9
|
+
finishing: "Finishing",
|
10
|
+
finished: "Finished",
|
11
|
+
stage_not_set: "Stage not set, please call something such as `cap production deploy`, where production is a stage you have defined.",
|
12
|
+
written_file: "create %{file}",
|
13
|
+
question: "Please enter %{key}: ",
|
14
|
+
question_default: "Please enter %{key} (%{default_value}): ",
|
15
|
+
question_prompt: "%{key}: ",
|
16
|
+
question_prompt_default: "%{key} (%{default_value}): ",
|
17
|
+
keeping_releases: "Keeping %{keep_releases} of %{releases} deployed releases on %{host}",
|
18
|
+
skip_cleanup: "Skipping cleanup of invalid releases on %{host}; unexpected foldername found (should be timestamp)",
|
19
|
+
wont_delete_current_release: "Current release was marked for being removed but it's going to be skipped on %{host}",
|
20
|
+
no_current_release: "There is no current release present on %{host}",
|
21
|
+
no_old_releases: "No old releases (keeping newest %{keep_releases}) on %{host}",
|
22
|
+
linked_file_does_not_exist: "linked file %{file} does not exist on %{host}",
|
23
|
+
cannot_rollback: "There are no older releases to rollback to",
|
24
|
+
cannot_found_rollback_release: "Cannot rollback because release %{release} does not exist",
|
25
|
+
mirror_exists: "The repository mirror is at %{at}",
|
26
|
+
revision_log_message: "Branch %{branch} (at %{sha}) deployed as release %{release} by %{user}",
|
27
|
+
rollback_log_message: "%{user} rolled back to release %{release}",
|
28
|
+
deploy_failed: "The deploy has failed with an error: %{ex}",
|
29
|
+
console: {
|
30
|
+
welcome: "capistrano console - enter command to execute on %{stage}",
|
31
|
+
bye: "bye"
|
32
|
+
},
|
33
|
+
error: {
|
34
|
+
invalid_stage_name: '"%{name}" is a reserved word and cannot be used as a stage. Rename "%{path}" to something else.',
|
35
|
+
user: {
|
36
|
+
does_not_exist: "User %{user} does not exists",
|
37
|
+
cannot_switch: "Cannot switch to user %{user}"
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
I18n.backend.store_translations(:en, capistrano: en)
|
43
|
+
|
44
|
+
if I18n.respond_to?(:enforce_available_locales=)
|
45
|
+
I18n.enforce_available_locales = true
|
46
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Capistrano
|
2
|
+
# This module extends a Rake::Task to freeze it to prevent it from being
|
3
|
+
# enhanced. This is used to prevent users from enhancing a task at the wrong
|
4
|
+
# point of Capistrano's boot process, which can happen if a Capistrano plugin
|
5
|
+
# is loaded in deploy.rb by mistake (instead of in the Capfile).
|
6
|
+
#
|
7
|
+
# Usage:
|
8
|
+
#
|
9
|
+
# task = Rake.application["load:defaults"]
|
10
|
+
# task.invoke
|
11
|
+
# task.extend(Capistrano::ImmutableTask) # prevent further modifications
|
12
|
+
#
|
13
|
+
module ImmutableTask
|
14
|
+
def self.extended(task)
|
15
|
+
task.freeze
|
16
|
+
end
|
17
|
+
|
18
|
+
def enhance(*args, &block)
|
19
|
+
$stderr.puts <<-MESSAGE
|
20
|
+
ERROR: #{name} has already been invoked and can no longer be modified.
|
21
|
+
Check that you haven't loaded a Capistrano plugin in deploy.rb or a stage
|
22
|
+
(e.g. deploy/production.rb) by mistake.
|
23
|
+
Plugins must be loaded in the Capfile to initialize properly.
|
24
|
+
MESSAGE
|
25
|
+
|
26
|
+
# This will raise a frozen object error
|
27
|
+
super(*args, &block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
load File.expand_path(File.join(File.dirname(__FILE__), "tasks/install.rake"))
|