capistrano 2.8.0 → 3.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. checksums.yaml +7 -0
  2. data/.docker/Dockerfile +7 -0
  3. data/.docker/ssh_key_rsa +49 -0
  4. data/.docker/ssh_key_rsa.pub +1 -0
  5. data/.docker/ubuntu_setup.sh +23 -0
  6. data/.github/issue_template.md +19 -0
  7. data/.github/pull_request_template.md +22 -0
  8. data/.github/release-drafter.yml +25 -0
  9. data/.github/workflows/ci.yml +80 -0
  10. data/.github/workflows/release-drafter.yml +18 -0
  11. data/.gitignore +23 -8
  12. data/.rubocop.yml +62 -0
  13. data/CHANGELOG.md +1 -0
  14. data/CONTRIBUTING.md +63 -0
  15. data/DEVELOPMENT.md +112 -0
  16. data/Gemfile +42 -9
  17. data/LICENSE.txt +21 -0
  18. data/README.md +221 -0
  19. data/RELEASING.md +17 -0
  20. data/Rakefile +17 -8
  21. data/UPGRADING-3.7.md +86 -0
  22. data/bin/cap +2 -3
  23. data/bin/capify +7 -89
  24. data/capistrano.gemspec +29 -43
  25. data/docker-compose.yml +8 -0
  26. data/features/configuration.feature +28 -0
  27. data/features/deploy.feature +92 -0
  28. data/features/deploy_failure.feature +17 -0
  29. data/features/doctor.feature +11 -0
  30. data/features/installation.feature +21 -0
  31. data/features/sshconnect.feature +11 -0
  32. data/features/stage_failure.feature +9 -0
  33. data/features/step_definitions/assertions.rb +162 -0
  34. data/features/step_definitions/cap_commands.rb +21 -0
  35. data/features/step_definitions/setup.rb +91 -0
  36. data/features/subdirectory.feature +9 -0
  37. data/features/support/docker_gateway.rb +53 -0
  38. data/features/support/env.rb +1 -0
  39. data/features/support/remote_command_helpers.rb +29 -0
  40. data/features/support/remote_ssh_helpers.rb +33 -0
  41. data/lib/Capfile +3 -0
  42. data/lib/capistrano/all.rb +17 -0
  43. data/lib/capistrano/application.rb +153 -0
  44. data/lib/capistrano/configuration/empty_filter.rb +9 -0
  45. data/lib/capistrano/configuration/filter.rb +26 -0
  46. data/lib/capistrano/configuration/host_filter.rb +29 -0
  47. data/lib/capistrano/configuration/null_filter.rb +9 -0
  48. data/lib/capistrano/configuration/plugin_installer.rb +51 -0
  49. data/lib/capistrano/configuration/question.rb +76 -0
  50. data/lib/capistrano/configuration/role_filter.rb +29 -0
  51. data/lib/capistrano/configuration/scm_resolver.rb +149 -0
  52. data/lib/capistrano/configuration/server.rb +137 -0
  53. data/lib/capistrano/configuration/servers.rb +56 -96
  54. data/lib/capistrano/configuration/validated_variables.rb +110 -0
  55. data/lib/capistrano/configuration/variables.rb +79 -94
  56. data/lib/capistrano/configuration.rb +178 -33
  57. data/lib/capistrano/console.rb +1 -0
  58. data/lib/capistrano/defaults.rb +36 -0
  59. data/lib/capistrano/deploy.rb +3 -0
  60. data/lib/capistrano/doctor/environment_doctor.rb +19 -0
  61. data/lib/capistrano/doctor/gems_doctor.rb +45 -0
  62. data/lib/capistrano/doctor/output_helpers.rb +79 -0
  63. data/lib/capistrano/doctor/servers_doctor.rb +105 -0
  64. data/lib/capistrano/doctor/variables_doctor.rb +74 -0
  65. data/lib/capistrano/doctor.rb +6 -0
  66. data/lib/capistrano/dotfile.rb +2 -0
  67. data/lib/capistrano/dsl/env.rb +43 -0
  68. data/lib/capistrano/dsl/paths.rb +89 -0
  69. data/lib/capistrano/dsl/stages.rb +31 -0
  70. data/lib/capistrano/dsl/task_enhancements.rb +61 -0
  71. data/lib/capistrano/dsl.rb +95 -0
  72. data/lib/capistrano/framework.rb +2 -0
  73. data/lib/capistrano/i18n.rb +46 -0
  74. data/lib/capistrano/immutable_task.rb +30 -0
  75. data/lib/capistrano/install.rb +1 -0
  76. data/lib/capistrano/plugin.rb +95 -0
  77. data/lib/capistrano/proc_helpers.rb +13 -0
  78. data/lib/capistrano/scm/git.rb +105 -0
  79. data/lib/capistrano/scm/hg.rb +55 -0
  80. data/lib/capistrano/scm/plugin.rb +13 -0
  81. data/lib/capistrano/scm/svn.rb +56 -0
  82. data/lib/capistrano/scm/tasks/git.rake +84 -0
  83. data/lib/capistrano/scm/tasks/hg.rake +53 -0
  84. data/lib/capistrano/scm/tasks/svn.rake +53 -0
  85. data/lib/capistrano/scm.rb +115 -0
  86. data/lib/capistrano/setup.rb +36 -0
  87. data/lib/capistrano/tasks/console.rake +25 -0
  88. data/lib/capistrano/tasks/deploy.rake +280 -0
  89. data/lib/capistrano/tasks/doctor.rake +24 -0
  90. data/lib/capistrano/tasks/framework.rake +67 -0
  91. data/lib/capistrano/tasks/install.rake +41 -0
  92. data/lib/capistrano/templates/Capfile +38 -0
  93. data/lib/capistrano/templates/deploy.rb.erb +39 -0
  94. data/lib/capistrano/templates/stage.rb.erb +61 -0
  95. data/lib/capistrano/upload_task.rb +9 -0
  96. data/lib/capistrano/version.rb +1 -14
  97. data/lib/capistrano/version_validator.rb +32 -0
  98. data/lib/capistrano.rb +0 -3
  99. data/spec/integration/dsl_spec.rb +632 -0
  100. data/spec/integration_spec_helper.rb +5 -0
  101. data/spec/lib/capistrano/application_spec.rb +60 -0
  102. data/spec/lib/capistrano/configuration/empty_filter_spec.rb +17 -0
  103. data/spec/lib/capistrano/configuration/filter_spec.rb +109 -0
  104. data/spec/lib/capistrano/configuration/host_filter_spec.rb +71 -0
  105. data/spec/lib/capistrano/configuration/null_filter_spec.rb +17 -0
  106. data/spec/lib/capistrano/configuration/plugin_installer_spec.rb +98 -0
  107. data/spec/lib/capistrano/configuration/question_spec.rb +92 -0
  108. data/spec/lib/capistrano/configuration/role_filter_spec.rb +80 -0
  109. data/spec/lib/capistrano/configuration/scm_resolver_spec.rb +56 -0
  110. data/spec/lib/capistrano/configuration/server_spec.rb +309 -0
  111. data/spec/lib/capistrano/configuration/servers_spec.rb +331 -0
  112. data/spec/lib/capistrano/configuration_spec.rb +357 -0
  113. data/spec/lib/capistrano/doctor/environment_doctor_spec.rb +44 -0
  114. data/spec/lib/capistrano/doctor/gems_doctor_spec.rb +67 -0
  115. data/spec/lib/capistrano/doctor/output_helpers_spec.rb +47 -0
  116. data/spec/lib/capistrano/doctor/servers_doctor_spec.rb +86 -0
  117. data/spec/lib/capistrano/doctor/variables_doctor_spec.rb +89 -0
  118. data/spec/lib/capistrano/dsl/paths_spec.rb +228 -0
  119. data/spec/lib/capistrano/dsl/task_enhancements_spec.rb +108 -0
  120. data/spec/lib/capistrano/dsl_spec.rb +125 -0
  121. data/spec/lib/capistrano/immutable_task_spec.rb +31 -0
  122. data/spec/lib/capistrano/plugin_spec.rb +84 -0
  123. data/spec/lib/capistrano/scm/git_spec.rb +194 -0
  124. data/spec/lib/capistrano/scm/hg_spec.rb +109 -0
  125. data/spec/lib/capistrano/scm/svn_spec.rb +137 -0
  126. data/spec/lib/capistrano/scm_spec.rb +103 -0
  127. data/spec/lib/capistrano/upload_task_spec.rb +19 -0
  128. data/spec/lib/capistrano/version_validator_spec.rb +118 -0
  129. data/spec/lib/capistrano_spec.rb +7 -0
  130. data/spec/spec_helper.rb +29 -0
  131. data/spec/support/matchers.rb +5 -0
  132. data/spec/support/tasks/database.rake +11 -0
  133. data/spec/support/tasks/fail.rake +8 -0
  134. data/spec/support/tasks/failed.rake +5 -0
  135. data/spec/support/tasks/plugin.rake +6 -0
  136. data/spec/support/tasks/root.rake +11 -0
  137. data/spec/support/test_app.rb +205 -0
  138. metadata +234 -208
  139. data/.rvmrc +0 -1
  140. data/CHANGELOG +0 -954
  141. data/README.mdown +0 -76
  142. data/lib/capistrano/callback.rb +0 -45
  143. data/lib/capistrano/cli/execute.rb +0 -85
  144. data/lib/capistrano/cli/help.rb +0 -125
  145. data/lib/capistrano/cli/help.txt +0 -81
  146. data/lib/capistrano/cli/options.rb +0 -243
  147. data/lib/capistrano/cli/ui.rb +0 -40
  148. data/lib/capistrano/cli.rb +0 -47
  149. data/lib/capistrano/command.rb +0 -286
  150. data/lib/capistrano/configuration/actions/file_transfer.rb +0 -51
  151. data/lib/capistrano/configuration/actions/inspect.rb +0 -46
  152. data/lib/capistrano/configuration/actions/invocation.rb +0 -298
  153. data/lib/capistrano/configuration/callbacks.rb +0 -148
  154. data/lib/capistrano/configuration/connections.rb +0 -230
  155. data/lib/capistrano/configuration/execution.rb +0 -143
  156. data/lib/capistrano/configuration/loading.rb +0 -197
  157. data/lib/capistrano/configuration/namespaces.rb +0 -197
  158. data/lib/capistrano/configuration/roles.rb +0 -73
  159. data/lib/capistrano/errors.rb +0 -19
  160. data/lib/capistrano/ext/string.rb +0 -5
  161. data/lib/capistrano/extensions.rb +0 -57
  162. data/lib/capistrano/logger.rb +0 -59
  163. data/lib/capistrano/processable.rb +0 -53
  164. data/lib/capistrano/recipes/compat.rb +0 -32
  165. data/lib/capistrano/recipes/deploy/assets.rb +0 -57
  166. data/lib/capistrano/recipes/deploy/dependencies.rb +0 -44
  167. data/lib/capistrano/recipes/deploy/local_dependency.rb +0 -54
  168. data/lib/capistrano/recipes/deploy/remote_dependency.rb +0 -111
  169. data/lib/capistrano/recipes/deploy/scm/accurev.rb +0 -169
  170. data/lib/capistrano/recipes/deploy/scm/base.rb +0 -196
  171. data/lib/capistrano/recipes/deploy/scm/bzr.rb +0 -86
  172. data/lib/capistrano/recipes/deploy/scm/cvs.rb +0 -153
  173. data/lib/capistrano/recipes/deploy/scm/darcs.rb +0 -96
  174. data/lib/capistrano/recipes/deploy/scm/git.rb +0 -282
  175. data/lib/capistrano/recipes/deploy/scm/mercurial.rb +0 -137
  176. data/lib/capistrano/recipes/deploy/scm/none.rb +0 -44
  177. data/lib/capistrano/recipes/deploy/scm/perforce.rb +0 -138
  178. data/lib/capistrano/recipes/deploy/scm/subversion.rb +0 -121
  179. data/lib/capistrano/recipes/deploy/scm.rb +0 -19
  180. data/lib/capistrano/recipes/deploy/strategy/base.rb +0 -88
  181. data/lib/capistrano/recipes/deploy/strategy/checkout.rb +0 -20
  182. data/lib/capistrano/recipes/deploy/strategy/copy.rb +0 -224
  183. data/lib/capistrano/recipes/deploy/strategy/export.rb +0 -20
  184. data/lib/capistrano/recipes/deploy/strategy/remote.rb +0 -52
  185. data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +0 -57
  186. data/lib/capistrano/recipes/deploy/strategy.rb +0 -19
  187. data/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +0 -53
  188. data/lib/capistrano/recipes/deploy.rb +0 -568
  189. data/lib/capistrano/recipes/standard.rb +0 -37
  190. data/lib/capistrano/recipes/templates/maintenance.rhtml +0 -53
  191. data/lib/capistrano/role.rb +0 -102
  192. data/lib/capistrano/server_definition.rb +0 -56
  193. data/lib/capistrano/shell.rb +0 -260
  194. data/lib/capistrano/ssh.rb +0 -101
  195. data/lib/capistrano/task_definition.rb +0 -75
  196. data/lib/capistrano/transfer.rb +0 -216
  197. data/rvmrc.sample +0 -1
  198. data/test/cli/execute_test.rb +0 -132
  199. data/test/cli/help_test.rb +0 -165
  200. data/test/cli/options_test.rb +0 -329
  201. data/test/cli/ui_test.rb +0 -28
  202. data/test/cli_test.rb +0 -17
  203. data/test/command_test.rb +0 -289
  204. data/test/configuration/actions/file_transfer_test.rb +0 -61
  205. data/test/configuration/actions/inspect_test.rb +0 -65
  206. data/test/configuration/actions/invocation_test.rb +0 -247
  207. data/test/configuration/callbacks_test.rb +0 -220
  208. data/test/configuration/connections_test.rb +0 -420
  209. data/test/configuration/execution_test.rb +0 -175
  210. data/test/configuration/loading_test.rb +0 -132
  211. data/test/configuration/namespace_dsl_test.rb +0 -311
  212. data/test/configuration/roles_test.rb +0 -144
  213. data/test/configuration/servers_test.rb +0 -183
  214. data/test/configuration/variables_test.rb +0 -190
  215. data/test/configuration_test.rb +0 -88
  216. data/test/deploy/local_dependency_test.rb +0 -76
  217. data/test/deploy/remote_dependency_test.rb +0 -135
  218. data/test/deploy/scm/accurev_test.rb +0 -23
  219. data/test/deploy/scm/base_test.rb +0 -55
  220. data/test/deploy/scm/bzr_test.rb +0 -51
  221. data/test/deploy/scm/darcs_test.rb +0 -37
  222. data/test/deploy/scm/git_test.rb +0 -184
  223. data/test/deploy/scm/mercurial_test.rb +0 -134
  224. data/test/deploy/scm/none_test.rb +0 -35
  225. data/test/deploy/scm/subversion_test.rb +0 -32
  226. data/test/deploy/strategy/copy_test.rb +0 -321
  227. data/test/extensions_test.rb +0 -69
  228. data/test/fixtures/cli_integration.rb +0 -5
  229. data/test/fixtures/config.rb +0 -5
  230. data/test/fixtures/custom.rb +0 -3
  231. data/test/logger_test.rb +0 -123
  232. data/test/recipes_test.rb +0 -25
  233. data/test/role_test.rb +0 -11
  234. data/test/server_definition_test.rb +0 -121
  235. data/test/shell_test.rb +0 -90
  236. data/test/ssh_test.rb +0 -113
  237. data/test/task_definition_test.rb +0 -116
  238. data/test/transfer_test.rb +0 -160
  239. 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,6 @@
1
+ require "capistrano/doctor/environment_doctor"
2
+ require "capistrano/doctor/gems_doctor"
3
+ require "capistrano/doctor/variables_doctor"
4
+ require "capistrano/doctor/servers_doctor"
5
+
6
+ load File.expand_path("../tasks/doctor.rake", __FILE__)
@@ -0,0 +1,2 @@
1
+ dotfile = Pathname.new(File.join(Dir.home, ".capfile"))
2
+ load dotfile if dotfile.file?
@@ -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,2 @@
1
+ load File.expand_path("../tasks/framework.rake", __FILE__)
2
+ require "capistrano/install"
@@ -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"))