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
@@ -1,121 +0,0 @@
1
- require 'capistrano/recipes/deploy/scm/base'
2
- require 'yaml'
3
-
4
- module Capistrano
5
- module Deploy
6
- module SCM
7
-
8
- # Implements the Capistrano SCM interface for the Subversion revision
9
- # control system (http://subversion.tigris.org).
10
- class Subversion < Base
11
- # Sets the default command name for this SCM. Users may override this
12
- # by setting the :scm_command variable.
13
- default_command "svn"
14
-
15
- # Subversion understands 'HEAD' to refer to the latest revision in the
16
- # repository.
17
- def head
18
- "HEAD"
19
- end
20
-
21
- # Returns the command that will check out the given revision to the
22
- # given destination.
23
- def checkout(revision, destination)
24
- scm :checkout, arguments, verbose, authentication, "-r#{revision}", repository, destination
25
- end
26
-
27
- # Returns the command that will do an "svn update" to the given
28
- # revision, for the working copy at the given destination.
29
- def sync(revision, destination)
30
- scm :update, arguments, verbose, authentication, "-r#{revision}", destination
31
- end
32
-
33
- # Returns the command that will do an "svn export" of the given revision
34
- # to the given destination.
35
- def export(revision, destination)
36
- scm :export, arguments, verbose, authentication, "-r#{revision}", repository, destination
37
- end
38
-
39
- # Returns the command that will do an "svn diff" for the two revisions.
40
- def diff(from, to=nil)
41
- scm :diff, repository, authentication, "-r#{from}:#{to || head}"
42
- end
43
-
44
- # Returns an "svn log" command for the two revisions.
45
- def log(from, to=nil)
46
- scm :log, repository, authentication, "-r#{from}:#{to || head}"
47
- end
48
-
49
- # Attempts to translate the given revision identifier to a "real"
50
- # revision. If the identifier is an integer, it will simply be returned.
51
- # Otherwise, this will yield a string of the commands it needs to be
52
- # executed (svn info), and will extract the revision from the response.
53
- def query_revision(revision)
54
- return revision if revision =~ /^\d+$/
55
- command = scm(:info, arguments, repository, authentication, "-r#{revision}")
56
- result = yield(command)
57
- yaml = YAML.load(result)
58
- raise "tried to run `#{command}' and got unexpected result #{result.inspect}" unless Hash === yaml
59
- [ (yaml['Last Changed Rev'] || 0).to_i, (yaml['Revision'] || 0).to_i ].max
60
- end
61
-
62
- # Increments the given revision number and returns it.
63
- def next_revision(revision)
64
- revision.to_i + 1
65
- end
66
-
67
- # Determines what the response should be for a particular bit of text
68
- # from the SCM. Password prompts, connection requests, passphrases,
69
- # etc. are handled here.
70
- def handle_data(state, stream, text)
71
- host = state[:channel][:host]
72
- logger.info "[#{host} :: #{stream}] #{text}"
73
- case text
74
- when /\bpassword.*:/i
75
- # subversion is prompting for a password
76
- "#{scm_password_prompt}\n"
77
- when %r{\(yes/no\)}
78
- # subversion is asking whether or not to connect
79
- "yes\n"
80
- when /passphrase/i
81
- # subversion is asking for the passphrase for the user's key
82
- "#{variable(:scm_passphrase)}\n"
83
- when /The entry \'(.+?)\' is no longer a directory/
84
- raise Capistrano::Error, "subversion can't update because directory '#{$1}' was replaced. Please add it to svn:ignore."
85
- when /accept \(t\)emporarily/
86
- # subversion is asking whether to accept the certificate
87
- "t\n"
88
- end
89
- end
90
-
91
- private
92
-
93
- # If a username is configured for the SCM, return the command-line
94
- # switches for that. Note that we don't need to return the password
95
- # switch, since Capistrano will check for that prompt in the output
96
- # and will respond appropriately.
97
- def authentication
98
- username = variable(:scm_username)
99
- return "" unless username
100
- result = "--username #{variable(:scm_username)} "
101
- result << "--password #{variable(:scm_password)} " unless variable(:scm_auth_cache) || variable(:scm_prefer_prompt)
102
- result << "--no-auth-cache " unless variable(:scm_auth_cache)
103
- result
104
- end
105
-
106
- # If verbose output is requested, return nil, otherwise return the
107
- # command-line switch for "quiet" ("-q").
108
- def verbose
109
- variable(:scm_verbose) ? nil : "-q"
110
- end
111
-
112
- def scm_password_prompt
113
- @scm_password_prompt ||= variable(:scm_password) ||
114
- variable(:password) ||
115
- Capistrano::CLI.password_prompt("Subversion password: ")
116
- end
117
- end
118
-
119
- end
120
- end
121
- end
@@ -1,19 +0,0 @@
1
- module Capistrano
2
- module Deploy
3
- module SCM
4
- def self.new(scm, config={})
5
- scm_file = "capistrano/recipes/deploy/scm/#{scm}"
6
- require(scm_file)
7
-
8
- scm_const = scm.to_s.capitalize.gsub(/_(.)/) { $1.upcase }
9
- if const_defined?(scm_const)
10
- const_get(scm_const).new(config)
11
- else
12
- raise Capistrano::Error, "could not find `#{name}::#{scm_const}' in `#{scm_file}'"
13
- end
14
- rescue LoadError
15
- raise Capistrano::Error, "could not find any SCM named `#{scm}'"
16
- end
17
- end
18
- end
19
- end
@@ -1,88 +0,0 @@
1
- require 'benchmark'
2
- require 'capistrano/recipes/deploy/dependencies'
3
-
4
- module Capistrano
5
- module Deploy
6
- module Strategy
7
-
8
- # This class defines the abstract interface for all Capistrano
9
- # deployment strategies. Subclasses must implement at least the
10
- # #deploy! method.
11
- class Base
12
- attr_reader :configuration
13
-
14
- # Instantiates a strategy with a reference to the given configuration.
15
- def initialize(config={})
16
- @configuration = config
17
- end
18
-
19
- # Executes the necessary commands to deploy the revision of the source
20
- # code identified by the +revision+ variable. Additionally, this
21
- # should write the value of the +revision+ variable to a file called
22
- # REVISION, in the base of the deployed revision. This file is used by
23
- # other tasks, to perform diffs and such.
24
- def deploy!
25
- raise NotImplementedError, "`deploy!' is not implemented by #{self.class.name}"
26
- end
27
-
28
- # Performs a check on the remote hosts to determine whether everything
29
- # is setup such that a deploy could succeed.
30
- def check!
31
- Dependencies.new(configuration) do |d|
32
- d.remote.directory(configuration[:releases_path]).or("`#{configuration[:releases_path]}' does not exist. Please run `cap deploy:setup'.")
33
- d.remote.writable(configuration[:deploy_to]).or("You do not have permissions to write to `#{configuration[:deploy_to]}'.")
34
- d.remote.writable(configuration[:releases_path]).or("You do not have permissions to write to `#{configuration[:releases_path]}'.")
35
- end
36
- end
37
-
38
- protected
39
-
40
- # This is to allow helper methods like "run" and "put" to be more
41
- # easily accessible to strategy implementations.
42
- def method_missing(sym, *args, &block)
43
- if configuration.respond_to?(sym)
44
- configuration.send(sym, *args, &block)
45
- else
46
- super
47
- end
48
- end
49
-
50
- # A wrapper for Kernel#system that logs the command being executed.
51
- def system(*args)
52
- cmd = args.join(' ')
53
- result = nil
54
- if RUBY_PLATFORM =~ /win32/
55
- cmd = cmd.split(/\s+/).collect {|w| w.match(/^[\w+]+:\/\//) ? w : w.gsub('/', '\\') }.join(' ') # Split command by spaces, change / by \\ unless element is a some+thing://
56
- cmd.gsub!(/^cd /,'cd /D ') # Replace cd with cd /D
57
- cmd.gsub!(/&& cd /,'&& cd /D ') # Replace cd with cd /D
58
- logger.trace "executing locally: #{cmd}"
59
- elapsed = Benchmark.realtime do
60
- result = super(cmd)
61
- end
62
- else
63
- logger.trace "executing locally: #{cmd}"
64
- elapsed = Benchmark.realtime do
65
- result = super
66
- end
67
- end
68
-
69
- logger.trace "command finished in #{(elapsed * 1000).round}ms"
70
- result
71
- end
72
-
73
- private
74
-
75
- def logger
76
- @logger ||= configuration[:logger] || Capistrano::Logger.new(:output => STDOUT)
77
- end
78
-
79
- # The revision to deploy. Must return a real revision identifier,
80
- # and not a pseudo-id.
81
- def revision
82
- configuration[:real_revision]
83
- end
84
- end
85
-
86
- end
87
- end
88
- end
@@ -1,20 +0,0 @@
1
- require 'capistrano/recipes/deploy/strategy/remote'
2
-
3
- module Capistrano
4
- module Deploy
5
- module Strategy
6
-
7
- # Implements the deployment strategy which does an SCM checkout on each
8
- # target host. This is the default deployment strategy for Capistrano.
9
- class Checkout < Remote
10
- protected
11
-
12
- # Returns the SCM's checkout command for the revision to deploy.
13
- def command
14
- @command ||= source.checkout(revision, configuration[:release_path])
15
- end
16
- end
17
-
18
- end
19
- end
20
- end
@@ -1,224 +0,0 @@
1
- require 'capistrano/recipes/deploy/strategy/base'
2
- require 'fileutils'
3
- require 'tempfile' # Dir.tmpdir
4
-
5
- module Capistrano
6
- module Deploy
7
- module Strategy
8
-
9
- # This class implements the strategy for deployments which work
10
- # by preparing the source code locally, compressing it, copying the
11
- # file to each target host, and uncompressing it to the deployment
12
- # directory.
13
- #
14
- # By default, the SCM checkout command is used to obtain the local copy
15
- # of the source code. If you would rather use the export operation,
16
- # you can set the :copy_strategy variable to :export.
17
- #
18
- # set :copy_strategy, :export
19
- #
20
- # For even faster deployments, you can set the :copy_cache variable to
21
- # true. This will cause deployments to do a new checkout of your
22
- # repository to a new directory, and then copy that checkout. Subsequent
23
- # deploys will just resync that copy, rather than doing an entirely new
24
- # checkout. Additionally, you can specify file patterns to exclude from
25
- # the copy when using :copy_cache; just set the :copy_exclude variable
26
- # to a file glob (or an array of globs).
27
- #
28
- # set :copy_cache, true
29
- # set :copy_exclude, ".git/*"
30
- #
31
- # Note that :copy_strategy is ignored when :copy_cache is set. Also, if
32
- # you want the copy cache put somewhere specific, you can set the variable
33
- # to the path you want, instead of merely 'true':
34
- #
35
- # set :copy_cache, "/tmp/caches/myapp"
36
- #
37
- # This deployment strategy also supports a special variable,
38
- # :copy_compression, which must be one of :gzip, :bz2, or
39
- # :zip, and which specifies how the source should be compressed for
40
- # transmission to each host.
41
- class Copy < Base
42
- # Obtains a copy of the source code locally (via the #command method),
43
- # compresses it to a single file, copies that file to all target
44
- # servers, and uncompresses it on each of them into the deployment
45
- # directory.
46
- def deploy!
47
- if copy_cache
48
- if File.exists?(copy_cache)
49
- logger.debug "refreshing local cache to revision #{revision} at #{copy_cache}"
50
- system(source.sync(revision, copy_cache))
51
- else
52
- logger.debug "preparing local cache at #{copy_cache}"
53
- system(source.checkout(revision, copy_cache))
54
- end
55
-
56
- # Check the return code of last system command and rollback if not 0
57
- unless $? == 0
58
- raise Capistrano::Error, "shell command failed with return code #{$?}"
59
- end
60
-
61
- FileUtils.mkdir_p(destination)
62
-
63
- logger.debug "copying cache to deployment staging area #{destination}"
64
- Dir.chdir(copy_cache) do
65
- queue = Dir.glob("*", File::FNM_DOTMATCH)
66
- while queue.any?
67
- item = queue.shift
68
- name = File.basename(item)
69
-
70
- next if name == "." || name == ".."
71
- next if copy_exclude.any? { |pattern| File.fnmatch(pattern, item) }
72
-
73
- if File.symlink?(item)
74
- FileUtils.ln_s(File.readlink(item), File.join(destination, item))
75
- elsif File.directory?(item)
76
- queue += Dir.glob("#{item}/*", File::FNM_DOTMATCH)
77
- FileUtils.mkdir(File.join(destination, item))
78
- else
79
- FileUtils.ln(item, File.join(destination, item))
80
- end
81
- end
82
- end
83
- else
84
- logger.debug "getting (via #{copy_strategy}) revision #{revision} to #{destination}"
85
- system(command)
86
-
87
- if copy_exclude.any?
88
- logger.debug "processing exclusions..."
89
- if copy_exclude.any?
90
- copy_exclude.each do |pattern|
91
- delete_list = Dir.glob(File.join(destination, pattern), File::FNM_DOTMATCH)
92
- # avoid the /.. trap that deletes the parent directories
93
- delete_list.delete_if { |dir| dir =~ /\/\.\.$/ }
94
- FileUtils.rm_rf(delete_list.compact)
95
- end
96
- end
97
- end
98
- end
99
-
100
- File.open(File.join(destination, "REVISION"), "w") { |f| f.puts(revision) }
101
-
102
- logger.trace "compressing #{destination} to #{filename}"
103
- Dir.chdir(copy_dir) { system(compress(File.basename(destination), File.basename(filename)).join(" ")) }
104
-
105
- distribute!
106
- ensure
107
- FileUtils.rm filename rescue nil
108
- FileUtils.rm_rf destination rescue nil
109
- end
110
-
111
- def check!
112
- super.check do |d|
113
- d.local.command(source.local.command) if source.local.command
114
- d.local.command(compress(nil, nil).first)
115
- d.remote.command(decompress(nil).first)
116
- end
117
- end
118
-
119
- # Returns the location of the local copy cache, if the strategy should
120
- # use a local cache + copy instead of a new checkout/export every
121
- # time. Returns +nil+ unless :copy_cache has been set. If :copy_cache
122
- # is +true+, a default cache location will be returned.
123
- def copy_cache
124
- @copy_cache ||= configuration[:copy_cache] == true ?
125
- File.expand_path(configuration[:application], Dir.tmpdir) :
126
- File.expand_path(configuration[:copy_cache], Dir.pwd) rescue nil
127
- end
128
-
129
- private
130
-
131
- # Specify patterns to exclude from the copy. This is only valid
132
- # when using a local cache.
133
- def copy_exclude
134
- @copy_exclude ||= Array(configuration.fetch(:copy_exclude, []))
135
- end
136
-
137
- # Returns the basename of the release_path, which will be used to
138
- # name the local copy and archive file.
139
- def destination
140
- @destination ||= File.join(copy_dir, File.basename(configuration[:release_path]))
141
- end
142
-
143
- # Returns the value of the :copy_strategy variable, defaulting to
144
- # :checkout if it has not been set.
145
- def copy_strategy
146
- @copy_strategy ||= configuration.fetch(:copy_strategy, :checkout)
147
- end
148
-
149
- # Should return the command(s) necessary to obtain the source code
150
- # locally.
151
- def command
152
- @command ||= case copy_strategy
153
- when :checkout
154
- source.checkout(revision, destination)
155
- when :export
156
- source.export(revision, destination)
157
- end
158
- end
159
-
160
- # Returns the name of the file that the source code will be
161
- # compressed to.
162
- def filename
163
- @filename ||= File.join(copy_dir, "#{File.basename(destination)}.#{compression.extension}")
164
- end
165
-
166
- # The directory to which the copy should be checked out
167
- def copy_dir
168
- @copy_dir ||= File.expand_path(configuration[:copy_dir] || Dir.tmpdir, Dir.pwd)
169
- end
170
-
171
- # The directory on the remote server to which the archive should be
172
- # copied
173
- def remote_dir
174
- @remote_dir ||= configuration[:copy_remote_dir] || "/tmp"
175
- end
176
-
177
- # The location on the remote server where the file should be
178
- # temporarily stored.
179
- def remote_filename
180
- @remote_filename ||= File.join(remote_dir, File.basename(filename))
181
- end
182
-
183
- # A struct for representing the specifics of a compression type.
184
- # Commands are arrays, where the first element is the utility to be
185
- # used to perform the compression or decompression.
186
- Compression = Struct.new(:extension, :compress_command, :decompress_command)
187
-
188
- # The compression method to use, defaults to :gzip.
189
- def compression
190
- remote_tar = configuration[:copy_remote_tar] || 'tar'
191
- local_tar = configuration[:copy_local_tar] || 'tar'
192
-
193
- type = configuration[:copy_compression] || :gzip
194
- case type
195
- when :gzip, :gz then Compression.new("tar.gz", [local_tar, 'chzf'], [remote_tar, 'xzf'])
196
- when :bzip2, :bz2 then Compression.new("tar.bz2", [local_tar, 'chjf'], [remote_tar, 'xjf'])
197
- when :zip then Compression.new("zip", %w(zip -qr), %w(unzip -q))
198
- else raise ArgumentError, "invalid compression type #{type.inspect}"
199
- end
200
- end
201
-
202
- # Returns the command necessary to compress the given directory
203
- # into the given file.
204
- def compress(directory, file)
205
- compression.compress_command + [file, directory]
206
- end
207
-
208
- # Returns the command necessary to decompress the given file,
209
- # relative to the current working directory. It must also
210
- # preserve the directory structure in the file.
211
- def decompress(file)
212
- compression.decompress_command + [file]
213
- end
214
-
215
- # Distributes the file to the remote servers
216
- def distribute!
217
- upload(filename, remote_filename)
218
- run "cd #{configuration[:releases_path]} && #{decompress(remote_filename).join(" ")} && rm #{remote_filename}"
219
- end
220
- end
221
-
222
- end
223
- end
224
- end
@@ -1,20 +0,0 @@
1
- require 'capistrano/recipes/deploy/strategy/remote'
2
-
3
- module Capistrano
4
- module Deploy
5
- module Strategy
6
-
7
- # Implements the deployment strategy which does an SCM export on each
8
- # target host.
9
- class Export < Remote
10
- protected
11
-
12
- # Returns the SCM's export command for the revision to deploy.
13
- def command
14
- @command ||= source.export(revision, configuration[:release_path])
15
- end
16
- end
17
-
18
- end
19
- end
20
- end
@@ -1,52 +0,0 @@
1
- require 'capistrano/recipes/deploy/strategy/base'
2
-
3
- module Capistrano
4
- module Deploy
5
- module Strategy
6
-
7
- # An abstract superclass, which forms the base for all deployment
8
- # strategies which work by grabbing the code from the repository directly
9
- # from remote host. This includes deploying by checkout (the default),
10
- # and deploying by export.
11
- class Remote < Base
12
- # Executes the SCM command for this strategy and writes the REVISION
13
- # mark file to each host.
14
- def deploy!
15
- scm_run "#{command} && #{mark}"
16
- end
17
-
18
- def check!
19
- super.check do |d|
20
- d.remote.command(source.command)
21
- end
22
- end
23
-
24
- protected
25
-
26
- # Runs the given command, filtering output back through the
27
- # #handle_data filter of the SCM implementation.
28
- def scm_run(command)
29
- run(command) do |ch,stream,text|
30
- ch[:state] ||= { :channel => ch }
31
- output = source.handle_data(ch[:state], stream, text)
32
- ch.send_data(output) if output
33
- end
34
- end
35
-
36
- # An abstract method which must be overridden in subclasses, to
37
- # return the actual SCM command(s) which must be executed on each
38
- # target host in order to perform the deployment.
39
- def command
40
- raise NotImplementedError, "`command' is not implemented by #{self.class.name}"
41
- end
42
-
43
- # Returns the command which will write the identifier of the
44
- # revision being deployed to the REVISION file on each host.
45
- def mark
46
- "(echo #{revision} > #{configuration[:release_path]}/REVISION)"
47
- end
48
- end
49
-
50
- end
51
- end
52
- end
@@ -1,57 +0,0 @@
1
- require 'capistrano/recipes/deploy/strategy/remote'
2
-
3
- module Capistrano
4
- module Deploy
5
- module Strategy
6
-
7
- # Implements the deployment strategy that keeps a cached checkout of
8
- # the source code on each remote server. Each deploy simply updates the
9
- # cached checkout, and then does a copy from the cached copy to the
10
- # final deployment location.
11
- class RemoteCache < Remote
12
- # Executes the SCM command for this strategy and writes the REVISION
13
- # mark file to each host.
14
- def deploy!
15
- update_repository_cache
16
- copy_repository_cache
17
- end
18
-
19
- def check!
20
- super.check do |d|
21
- d.remote.command("rsync") unless copy_exclude.empty?
22
- d.remote.writable(shared_path)
23
- end
24
- end
25
-
26
- private
27
-
28
- def repository_cache
29
- File.join(shared_path, configuration[:repository_cache] || "cached-copy")
30
- end
31
-
32
- def update_repository_cache
33
- logger.trace "updating the cached checkout on all servers"
34
- command = "if [ -d #{repository_cache} ]; then " +
35
- "#{source.sync(revision, repository_cache)}; " +
36
- "else #{source.checkout(revision, repository_cache)}; fi"
37
- scm_run(command)
38
- end
39
-
40
- def copy_repository_cache
41
- logger.trace "copying the cached version to #{configuration[:release_path]}"
42
- if copy_exclude.empty?
43
- run "cp -RPp #{repository_cache} #{configuration[:release_path]} && #{mark}"
44
- else
45
- exclusions = copy_exclude.map { |e| "--exclude=\"#{e}\"" }.join(' ')
46
- run "rsync -lrpt #{exclusions} #{repository_cache}/ #{configuration[:release_path]} && #{mark}"
47
- end
48
- end
49
-
50
- def copy_exclude
51
- @copy_exclude ||= Array(configuration.fetch(:copy_exclude, []))
52
- end
53
- end
54
-
55
- end
56
- end
57
- end
@@ -1,19 +0,0 @@
1
- module Capistrano
2
- module Deploy
3
- module Strategy
4
- def self.new(strategy, config={})
5
- strategy_file = "capistrano/recipes/deploy/strategy/#{strategy}"
6
- require(strategy_file)
7
-
8
- strategy_const = strategy.to_s.capitalize.gsub(/_(.)/) { $1.upcase }
9
- if const_defined?(strategy_const)
10
- const_get(strategy_const).new(config)
11
- else
12
- raise Capistrano::Error, "could not find `#{name}::#{strategy_const}' in `#{strategy_file}'"
13
- end
14
- rescue LoadError
15
- raise Capistrano::Error, "could not find any strategy named `#{strategy}'"
16
- end
17
- end
18
- end
19
- end
@@ -1,53 +0,0 @@
1
-
2
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4
-
5
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
6
-
7
- <head>
8
- <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
9
- <title>System down for maintenance</title>
10
-
11
- <style type="text/css">
12
- div.outer {
13
- position: absolute;
14
- left: 50%;
15
- top: 50%;
16
- width: 500px;
17
- height: 300px;
18
- margin-left: -260px;
19
- margin-top: -150px;
20
- }
21
-
22
- .DialogBody {
23
- margin: 0;
24
- padding: 10px;
25
- text-align: left;
26
- border: 1px solid #ccc;
27
- border-right: 1px solid #999;
28
- border-bottom: 1px solid #999;
29
- background-color: #fff;
30
- }
31
-
32
- body { background-color: #fff; }
33
- </style>
34
- </head>
35
-
36
- <body>
37
-
38
- <div class="outer">
39
- <div class="DialogBody" style="text-align: center;">
40
- <div style="text-align: center; width: 200px; margin: 0 auto;">
41
- <p style="color: red; font-size: 16px; line-height: 20px;">
42
- The system is down for <%= reason ? reason : "maintenance" %>
43
- as of <%= Time.now.strftime("%H:%M %Z") %>.
44
- </p>
45
- <p style="color: #666;">
46
- It'll be back <%= deadline ? deadline : "shortly" %>.
47
- </p>
48
- </div>
49
- </div>
50
- </div>
51
-
52
- </body>
53
- </html>