capistrano 3.4.0 → 3.17.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +129 -0
  3. data/.github/issue_template.md +19 -0
  4. data/.github/pull_request_template.md +22 -0
  5. data/.github/release-drafter.yml +17 -0
  6. data/.github/workflows/push.yml +12 -0
  7. data/.gitignore +8 -5
  8. data/.rubocop.yml +62 -0
  9. data/CHANGELOG.md +1 -307
  10. data/CONTRIBUTING.md +63 -93
  11. data/DEVELOPMENT.md +127 -0
  12. data/Dangerfile +1 -0
  13. data/Gemfile +40 -3
  14. data/LICENSE.txt +1 -1
  15. data/README.md +127 -44
  16. data/RELEASING.md +17 -0
  17. data/Rakefile +13 -2
  18. data/UPGRADING-3.7.md +86 -0
  19. data/bin/cap +1 -1
  20. data/capistrano.gemspec +21 -24
  21. data/features/deploy.feature +35 -1
  22. data/features/doctor.feature +11 -0
  23. data/features/installation.feature +8 -3
  24. data/features/stage_failure.feature +9 -0
  25. data/features/step_definitions/assertions.rb +51 -18
  26. data/features/step_definitions/cap_commands.rb +9 -0
  27. data/features/step_definitions/setup.rb +53 -9
  28. data/features/subdirectory.feature +9 -0
  29. data/features/support/env.rb +5 -5
  30. data/features/support/remote_command_helpers.rb +12 -6
  31. data/features/support/vagrant_helpers.rb +17 -11
  32. data/lib/Capfile +1 -1
  33. data/lib/capistrano/all.rb +10 -10
  34. data/lib/capistrano/application.rb +47 -34
  35. data/lib/capistrano/configuration/empty_filter.rb +9 -0
  36. data/lib/capistrano/configuration/filter.rb +17 -47
  37. data/lib/capistrano/configuration/host_filter.rb +29 -0
  38. data/lib/capistrano/configuration/null_filter.rb +9 -0
  39. data/lib/capistrano/configuration/plugin_installer.rb +51 -0
  40. data/lib/capistrano/configuration/question.rb +31 -9
  41. data/lib/capistrano/configuration/role_filter.rb +29 -0
  42. data/lib/capistrano/configuration/scm_resolver.rb +149 -0
  43. data/lib/capistrano/configuration/server.rb +29 -23
  44. data/lib/capistrano/configuration/servers.rb +21 -14
  45. data/lib/capistrano/configuration/validated_variables.rb +110 -0
  46. data/lib/capistrano/configuration/variables.rb +112 -0
  47. data/lib/capistrano/configuration.rb +91 -44
  48. data/lib/capistrano/defaults.rb +26 -4
  49. data/lib/capistrano/deploy.rb +1 -1
  50. data/lib/capistrano/doctor/environment_doctor.rb +19 -0
  51. data/lib/capistrano/doctor/gems_doctor.rb +45 -0
  52. data/lib/capistrano/doctor/output_helpers.rb +79 -0
  53. data/lib/capistrano/doctor/servers_doctor.rb +105 -0
  54. data/lib/capistrano/doctor/variables_doctor.rb +74 -0
  55. data/lib/capistrano/doctor.rb +6 -0
  56. data/lib/capistrano/dotfile.rb +1 -2
  57. data/lib/capistrano/dsl/env.rb +9 -47
  58. data/lib/capistrano/dsl/paths.rb +11 -25
  59. data/lib/capistrano/dsl/stages.rb +14 -2
  60. data/lib/capistrano/dsl/task_enhancements.rb +7 -12
  61. data/lib/capistrano/dsl.rb +47 -16
  62. data/lib/capistrano/framework.rb +1 -1
  63. data/lib/capistrano/i18n.rb +32 -24
  64. data/lib/capistrano/immutable_task.rb +30 -0
  65. data/lib/capistrano/install.rb +1 -1
  66. data/lib/capistrano/plugin.rb +95 -0
  67. data/lib/capistrano/proc_helpers.rb +13 -0
  68. data/lib/capistrano/scm/git.rb +100 -0
  69. data/lib/capistrano/scm/hg.rb +55 -0
  70. data/lib/capistrano/scm/plugin.rb +13 -0
  71. data/lib/capistrano/scm/svn.rb +56 -0
  72. data/lib/capistrano/scm/tasks/git.rake +73 -0
  73. data/lib/capistrano/scm/tasks/hg.rake +53 -0
  74. data/lib/capistrano/scm/tasks/svn.rake +53 -0
  75. data/lib/capistrano/scm.rb +7 -20
  76. data/lib/capistrano/setup.rb +20 -6
  77. data/lib/capistrano/tasks/console.rake +4 -8
  78. data/lib/capistrano/tasks/deploy.rake +105 -73
  79. data/lib/capistrano/tasks/doctor.rake +24 -0
  80. data/lib/capistrano/tasks/framework.rake +13 -14
  81. data/lib/capistrano/tasks/install.rake +14 -15
  82. data/lib/capistrano/templates/Capfile +21 -10
  83. data/lib/capistrano/templates/deploy.rb.erb +17 -26
  84. data/lib/capistrano/templates/stage.rb.erb +9 -9
  85. data/lib/capistrano/upload_task.rb +1 -1
  86. data/lib/capistrano/version.rb +1 -1
  87. data/lib/capistrano/version_validator.rb +5 -10
  88. data/spec/integration/dsl_spec.rb +289 -240
  89. data/spec/integration_spec_helper.rb +3 -5
  90. data/spec/lib/capistrano/application_spec.rb +23 -39
  91. data/spec/lib/capistrano/configuration/empty_filter_spec.rb +17 -0
  92. data/spec/lib/capistrano/configuration/filter_spec.rb +83 -85
  93. data/spec/lib/capistrano/configuration/host_filter_spec.rb +71 -0
  94. data/spec/lib/capistrano/configuration/null_filter_spec.rb +17 -0
  95. data/spec/lib/capistrano/configuration/plugin_installer_spec.rb +98 -0
  96. data/spec/lib/capistrano/configuration/question_spec.rb +58 -26
  97. data/spec/lib/capistrano/configuration/role_filter_spec.rb +80 -0
  98. data/spec/lib/capistrano/configuration/scm_resolver_spec.rb +55 -0
  99. data/spec/lib/capistrano/configuration/server_spec.rb +106 -113
  100. data/spec/lib/capistrano/configuration/servers_spec.rb +129 -145
  101. data/spec/lib/capistrano/configuration_spec.rb +224 -63
  102. data/spec/lib/capistrano/doctor/environment_doctor_spec.rb +44 -0
  103. data/spec/lib/capistrano/doctor/gems_doctor_spec.rb +67 -0
  104. data/spec/lib/capistrano/doctor/output_helpers_spec.rb +47 -0
  105. data/spec/lib/capistrano/doctor/servers_doctor_spec.rb +86 -0
  106. data/spec/lib/capistrano/doctor/variables_doctor_spec.rb +89 -0
  107. data/spec/lib/capistrano/dsl/paths_spec.rb +97 -59
  108. data/spec/lib/capistrano/dsl/task_enhancements_spec.rb +57 -37
  109. data/spec/lib/capistrano/dsl_spec.rb +84 -11
  110. data/spec/lib/capistrano/immutable_task_spec.rb +31 -0
  111. data/spec/lib/capistrano/plugin_spec.rb +84 -0
  112. data/spec/lib/capistrano/scm/git_spec.rb +184 -0
  113. data/spec/lib/capistrano/scm/hg_spec.rb +109 -0
  114. data/spec/lib/capistrano/scm/svn_spec.rb +137 -0
  115. data/spec/lib/capistrano/scm_spec.rb +7 -8
  116. data/spec/lib/capistrano/upload_task_spec.rb +7 -7
  117. data/spec/lib/capistrano/version_validator_spec.rb +61 -46
  118. data/spec/lib/capistrano_spec.rb +2 -3
  119. data/spec/spec_helper.rb +21 -8
  120. data/spec/support/Vagrantfile +9 -10
  121. data/spec/support/tasks/database.rake +3 -3
  122. data/spec/support/tasks/fail.rake +4 -3
  123. data/spec/support/tasks/failed.rake +2 -2
  124. data/spec/support/tasks/plugin.rake +6 -0
  125. data/spec/support/tasks/root.rake +4 -4
  126. data/spec/support/test_app.rb +64 -39
  127. metadata +100 -55
  128. data/.travis.yml +0 -13
  129. data/features/remote_file_task.feature +0 -14
  130. data/lib/capistrano/git.rb +0 -46
  131. data/lib/capistrano/hg.rb +0 -43
  132. data/lib/capistrano/svn.rb +0 -38
  133. data/lib/capistrano/tasks/git.rake +0 -81
  134. data/lib/capistrano/tasks/hg.rake +0 -52
  135. data/lib/capistrano/tasks/svn.rake +0 -52
  136. data/spec/lib/capistrano/git_spec.rb +0 -81
  137. data/spec/lib/capistrano/hg_spec.rb +0 -81
  138. data/spec/lib/capistrano/svn_spec.rb +0 -79
@@ -1,37 +1,45 @@
1
- require 'i18n'
1
+ require "i18n"
2
2
 
3
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} (%{default_value}): ',
14
- keeping_releases: 'Keeping %{keep_releases} of %{releases} deployed releases on %{host}',
15
- no_old_releases: 'No old releases (keeping newest %{keep_releases}) on %{host}',
16
- linked_file_does_not_exist: 'linked file %{file} does not exist on %{host}',
17
- cannot_rollback: 'There are no older releases to rollback to',
18
- mirror_exists: 'The repository mirror is at %{at}',
19
- revision_log_message: 'Branch %{branch} (at %{sha}) deployed as release %{release} by %{user}',
20
- rollback_log_message: '%{user} rolled back to release %{release}',
21
- deploy_failed: 'The deploy has failed with an error: %{ex}',
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}",
22
29
  console: {
23
- welcome: 'capistrano console - enter command to execute on %{stage}',
24
- bye: 'bye'
30
+ welcome: "capistrano console - enter command to execute on %{stage}",
31
+ bye: "bye"
25
32
  },
26
33
  error: {
34
+ invalid_stage_name: '"%{name}" is a reserved word and cannot be used as a stage. Rename "%{path}" to something else.',
27
35
  user: {
28
- does_not_exist: 'User %{user} does not exists',
29
- cannot_switch: 'Cannot switch to user %{user}'
36
+ does_not_exist: "User %{user} does not exists",
37
+ cannot_switch: "Cannot switch to user %{user}"
30
38
  }
31
39
  }
32
40
  }
33
41
 
34
- I18n.backend.store_translations(:en, { capistrano: en })
42
+ I18n.backend.store_translations(:en, capistrano: en)
35
43
 
36
44
  if I18n.respond_to?(:enforce_available_locales=)
37
45
  I18n.enforce_available_locales = true
@@ -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
@@ -1 +1 @@
1
- load File.expand_path(File.join(File.dirname(__FILE__),'tasks/install.rake'))
1
+ load File.expand_path(File.join(File.dirname(__FILE__), "tasks/install.rake"))
@@ -0,0 +1,95 @@
1
+ require "capistrano/all"
2
+ require "rake/tasklib"
3
+
4
+ # IMPORTANT: The Capistrano::Plugin system is not yet considered a stable,
5
+ # public API, and is subject to change without notice. Eventually it will be
6
+ # officially documented and supported, but for now, use it at your own risk.
7
+ #
8
+ # Base class for Capistrano plugins. Makes building a Capistrano plugin as easy
9
+ # as writing a `Capistrano::Plugin` subclass and overriding any or all of its
10
+ # three template methods:
11
+ #
12
+ # * set_defaults
13
+ # * register_hooks
14
+ # * define_tasks
15
+ #
16
+ # Within the plugin you can use any methods of the Rake or Capistrano DSLs, like
17
+ # `fetch`, `invoke`, etc. In cases when you need to use SSHKit's backend outside
18
+ # of an `on` block, use the `backend` convenience method. E.g. `backend.test`,
19
+ # `backend.execute`, or `backend.capture`.
20
+ #
21
+ # Package up and distribute your plugin class as a gem and you're good to go!
22
+ #
23
+ # To use a plugin, all a user has to do is install it in the Capfile, like this:
24
+ #
25
+ # # Capfile
26
+ # require "capistrano/superfancy"
27
+ # install_plugin Capistrano::Superfancy
28
+ #
29
+ # Or, to install the plugin without its hooks:
30
+ #
31
+ # # Capfile
32
+ # require "capistrano/superfancy"
33
+ # install_plugin Capistrano::Superfancy, load_hooks: false
34
+ #
35
+ class Capistrano::Plugin < Rake::TaskLib
36
+ include Capistrano::DSL
37
+
38
+ # Implemented by subclasses to provide default values for settings needed by
39
+ # this plugin. Typically done using the `set_if_empty` Capistrano DSL method.
40
+ #
41
+ # Example:
42
+ #
43
+ # def set_defaults
44
+ # set_if_empty :my_plugin_option, true
45
+ # end
46
+ #
47
+ def set_defaults; end
48
+
49
+ # Implemented by subclasses to hook into Capistrano's deployment flow using
50
+ # using the `before` and `after` DSL methods. Note that `register_hooks` will
51
+ # not be called if the user has opted-out of hooks when installing the plugin.
52
+ #
53
+ # Example:
54
+ #
55
+ # def register_hooks
56
+ # after "deploy:updated", "my_plugin:do_something"
57
+ # end
58
+ #
59
+ def register_hooks; end
60
+
61
+ # Implemented by subclasses to define Rake tasks. Typically a plugin will call
62
+ # `eval_rakefile` to load Rake tasks from a separate .rake file.
63
+ #
64
+ # Example:
65
+ #
66
+ # def define_tasks
67
+ # eval_rakefile File.expand_path("../tasks.rake", __FILE__)
68
+ # end
69
+ #
70
+ # For simple tasks, you can define them inline. No need for a separate file.
71
+ #
72
+ # def define_tasks
73
+ # desc "Do something fantastic."
74
+ # task "my_plugin:fantastic" do
75
+ # ...
76
+ # end
77
+ # end
78
+ #
79
+ def define_tasks; end
80
+
81
+ private
82
+
83
+ # Read and eval a .rake file in such a way that `self` within the .rake file
84
+ # refers to this plugin instance. This gives the tasks in the file access to
85
+ # helper methods defined by the plugin.
86
+ def eval_rakefile(path)
87
+ contents = IO.read(path)
88
+ instance_eval(contents, path, 1)
89
+ end
90
+
91
+ # Convenience to access the current SSHKit backend outside of an `on` block.
92
+ def backend
93
+ SSHKit::Backend.current
94
+ end
95
+ end
@@ -0,0 +1,13 @@
1
+ module Capistrano
2
+ module ProcHelpers
3
+ module_function
4
+
5
+ # Tests whether the given object appears to respond to `call` with
6
+ # zero parameters. In Capistrano, such a proc is used to represent a
7
+ # "deferred value". That is, a value that is resolved by invoking `call` at
8
+ # the time it is first needed.
9
+ def callable_without_parameters?(x)
10
+ x.respond_to?(:call) && (!x.respond_to?(:arity) || x.arity.zero?)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,100 @@
1
+ require "capistrano/scm/plugin"
2
+ require "cgi"
3
+ require "securerandom"
4
+ require "shellwords"
5
+ require "uri"
6
+
7
+ class Capistrano::SCM::Git < Capistrano::SCM::Plugin
8
+ def set_defaults
9
+ set_if_empty :git_shallow_clone, false
10
+ set_if_empty :git_wrapper_path, lambda {
11
+ # Use a unique name that won't collide with other deployments, and
12
+ # that cannot be guessed by other processes that have access to /tmp.
13
+ "#{fetch(:tmp_dir)}/git-ssh-#{SecureRandom.hex(10)}.sh"
14
+ }
15
+ set_if_empty :git_environmental_variables, lambda {
16
+ {
17
+ git_askpass: "/bin/echo",
18
+ git_ssh: fetch(:git_wrapper_path)
19
+ }
20
+ }
21
+ set_if_empty :git_max_concurrent_connections, 10
22
+ set_if_empty :git_wait_interval, 0
23
+ end
24
+
25
+ def register_hooks
26
+ after "deploy:new_release_path", "git:create_release"
27
+ before "deploy:check", "git:check"
28
+ before "deploy:set_current_revision", "git:set_current_revision"
29
+ end
30
+
31
+ def define_tasks
32
+ eval_rakefile File.expand_path("../tasks/git.rake", __FILE__)
33
+ end
34
+
35
+ def repo_mirror_exists?
36
+ backend.test " [ -f #{repo_path}/HEAD ] "
37
+ end
38
+
39
+ def check_repo_is_reachable
40
+ git :'ls-remote', git_repo_url, "HEAD"
41
+ end
42
+
43
+ def clone_repo
44
+ if (depth = fetch(:git_shallow_clone))
45
+ git :clone, "--mirror", "--depth", depth, "--no-single-branch", git_repo_url, repo_path.to_s
46
+ else
47
+ git :clone, "--mirror", git_repo_url, repo_path.to_s
48
+ end
49
+ end
50
+
51
+ def update_mirror
52
+ # Update the origin URL if necessary.
53
+ git :remote, "set-url", "origin", git_repo_url
54
+
55
+ # Note: Requires git version 1.9 or greater
56
+ if (depth = fetch(:git_shallow_clone))
57
+ git :fetch, "--depth", depth, "origin", fetch(:branch)
58
+ else
59
+ git :remote, :update, "--prune"
60
+ end
61
+ end
62
+
63
+ def verify_commit
64
+ git :"verify-commit", fetch_revision
65
+ end
66
+
67
+ def archive_to_release_path
68
+ if (tree = fetch(:repo_tree))
69
+ tree = tree.slice %r#^/?(.*?)/?$#, 1
70
+ components = tree.split("/").size
71
+ git :archive, fetch(:branch), tree, "| #{SSHKit.config.command_map[:tar]} -x --strip-components #{components} -f - -C", release_path
72
+ else
73
+ git :archive, fetch(:branch), "| #{SSHKit.config.command_map[:tar]} -x -f - -C", release_path
74
+ end
75
+ end
76
+
77
+ def fetch_revision
78
+ backend.capture(:git, "rev-list --max-count=1 #{fetch(:branch)}")
79
+ end
80
+
81
+ def git(*args)
82
+ args.unshift :git
83
+ backend.execute(*args)
84
+ end
85
+
86
+ def git_repo_url
87
+ if fetch(:git_http_username) && fetch(:git_http_password)
88
+ URI.parse(repo_url).tap do |repo_uri|
89
+ repo_uri.user = fetch(:git_http_username)
90
+ repo_uri.password = CGI.escape(fetch(:git_http_password))
91
+ end.to_s
92
+ elsif fetch(:git_http_username)
93
+ URI.parse(repo_url).tap do |repo_uri|
94
+ repo_uri.user = fetch(:git_http_username)
95
+ end.to_s
96
+ else
97
+ repo_url
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,55 @@
1
+ require "capistrano/scm/plugin"
2
+ require "securerandom"
3
+
4
+ class Capistrano::SCM::Hg < Capistrano::SCM::Plugin
5
+ def register_hooks
6
+ after "deploy:new_release_path", "hg:create_release"
7
+ before "deploy:check", "hg:check"
8
+ before "deploy:set_current_revision", "hg:set_current_revision"
9
+ end
10
+
11
+ def define_tasks
12
+ eval_rakefile File.expand_path("../tasks/hg.rake", __FILE__)
13
+ end
14
+
15
+ def hg(*args)
16
+ args.unshift(:hg)
17
+ backend.execute(*args)
18
+ end
19
+
20
+ def repo_mirror_exists?
21
+ backend.test " [ -d #{repo_path}/.hg ] "
22
+ end
23
+
24
+ def check_repo_is_reachable
25
+ hg "id", repo_url
26
+ end
27
+
28
+ def clone_repo
29
+ hg "clone", "--noupdate", repo_url, repo_path.to_s
30
+ end
31
+
32
+ def update_mirror
33
+ hg "pull"
34
+ end
35
+
36
+ def archive_to_release_path
37
+ if (tree = fetch(:repo_tree))
38
+ tree = tree.slice %r#^/?(.*?)/?$#, 1
39
+ components = tree.split("/").size
40
+ temp_tar = "#{fetch(:tmp_dir)}/#{SecureRandom.hex(10)}.tar"
41
+
42
+ hg "archive -p . -I", tree, "--rev", fetch(:branch), temp_tar
43
+
44
+ backend.execute :mkdir, "-p", release_path
45
+ backend.execute :tar, "-x --strip-components #{components} -f", temp_tar, "-C", release_path
46
+ backend.execute :rm, temp_tar
47
+ else
48
+ hg "archive", release_path, "--rev", fetch(:branch)
49
+ end
50
+ end
51
+
52
+ def fetch_revision
53
+ backend.capture(:hg, "log --rev #{fetch(:branch)} --template \"{node}\n\"")
54
+ end
55
+ end
@@ -0,0 +1,13 @@
1
+ require "capistrano/plugin"
2
+ require "capistrano/scm"
3
+
4
+ # Base class for all built-in and third-party SCM plugins. Notice that this
5
+ # class doesn't really do anything other than provide an `scm?` predicate. This
6
+ # tells Capistrano that the plugin provides SCM functionality. All other plugin
7
+ # features are inherited from Capistrano::Plugin.
8
+ #
9
+ class Capistrano::SCM::Plugin < Capistrano::Plugin
10
+ def scm?
11
+ true
12
+ end
13
+ end
@@ -0,0 +1,56 @@
1
+ require "capistrano/scm/plugin"
2
+
3
+ class Capistrano::SCM::Svn < Capistrano::SCM::Plugin
4
+ def register_hooks
5
+ after "deploy:new_release_path", "svn:create_release"
6
+ before "deploy:check", "svn:check"
7
+ before "deploy:set_current_revision", "svn:set_current_revision"
8
+ end
9
+
10
+ def define_tasks
11
+ eval_rakefile File.expand_path("../tasks/svn.rake", __FILE__)
12
+ end
13
+
14
+ def svn(*args)
15
+ args.unshift(:svn)
16
+ args.push "--username #{fetch(:svn_username)}" if fetch(:svn_username)
17
+ args.push "--password #{fetch(:svn_password)}" if fetch(:svn_password)
18
+ args.push "--revision #{fetch(:svn_revision)}" if fetch(:svn_revision)
19
+ backend.execute(*args)
20
+ end
21
+
22
+ def repo_mirror_exists?
23
+ backend.test " [ -d #{repo_path}/.svn ] "
24
+ end
25
+
26
+ def check_repo_is_reachable
27
+ svn_username = fetch(:svn_username) ? "--username #{fetch(:svn_username)}" : ""
28
+ svn_password = fetch(:svn_password) ? "--password #{fetch(:svn_password)}" : ""
29
+ backend.test :svn, :info, repo_url, svn_username, svn_password
30
+ end
31
+
32
+ def clone_repo
33
+ svn :checkout, repo_url, repo_path.to_s
34
+ end
35
+
36
+ def update_mirror
37
+ # Switch the repository URL if necessary.
38
+ repo_mirror_url = fetch_repo_mirror_url
39
+ svn :switch, repo_url unless repo_mirror_url == repo_url
40
+ svn :update
41
+ end
42
+
43
+ def archive_to_release_path
44
+ svn :export, "--force", ".", release_path
45
+ end
46
+
47
+ def fetch_revision
48
+ backend.capture(:svnversion, repo_path.to_s)
49
+ end
50
+
51
+ def fetch_repo_mirror_url
52
+ backend.capture(:svn, :info, repo_path.to_s).each_line do |line|
53
+ return $1 if /\AURL: (.*)\n\z/ =~ line
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,73 @@
1
+ # This trick lets us access the Git plugin within `on` blocks.
2
+ git_plugin = self
3
+
4
+ namespace :git do
5
+ desc "Upload the git wrapper script, this script guarantees that we can script git without getting an interactive prompt"
6
+ task :wrapper do
7
+ on release_roles(:all), in: :groups, limit: fetch(:git_max_concurrent_connections), wait: fetch(:git_wait_interval) do
8
+ execute :mkdir, "-p", File.dirname(fetch(:git_wrapper_path)).shellescape
9
+ upload! StringIO.new("#!/bin/sh -e\nexec /usr/bin/env ssh -o PasswordAuthentication=no -o StrictHostKeyChecking=no \"$@\"\n"), fetch(:git_wrapper_path)
10
+ execute :chmod, "700", fetch(:git_wrapper_path).shellescape
11
+ end
12
+ end
13
+
14
+ desc "Check that the repository is reachable"
15
+ task check: :'git:wrapper' do
16
+ fetch(:branch)
17
+ on release_roles(:all), in: :groups, limit: fetch(:git_max_concurrent_connections), wait: fetch(:git_wait_interval) do
18
+ with fetch(:git_environmental_variables) do
19
+ git_plugin.check_repo_is_reachable
20
+ end
21
+ end
22
+ end
23
+
24
+ desc "Clone the repo to the cache"
25
+ task clone: :'git:wrapper' do
26
+ on release_roles(:all), in: :groups, limit: fetch(:git_max_concurrent_connections), wait: fetch(:git_wait_interval) do
27
+ if git_plugin.repo_mirror_exists?
28
+ info t(:mirror_exists, at: repo_path)
29
+ else
30
+ within deploy_path do
31
+ with fetch(:git_environmental_variables) do
32
+ git_plugin.clone_repo
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ desc "Update the repo mirror to reflect the origin state"
40
+ task update: :'git:clone' do
41
+ on release_roles(:all), in: :groups, limit: fetch(:git_max_concurrent_connections), wait: fetch(:git_wait_interval) do
42
+ within repo_path do
43
+ with fetch(:git_environmental_variables) do
44
+ git_plugin.update_mirror
45
+ git_plugin.verify_commit if fetch(:git_verify_commit)
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ desc "Copy repo to releases"
52
+ task create_release: :'git:update' do
53
+ on release_roles(:all), in: :groups, limit: fetch(:git_max_concurrent_connections), wait: fetch(:git_wait_interval) do
54
+ with fetch(:git_environmental_variables) do
55
+ within repo_path do
56
+ execute :mkdir, "-p", release_path
57
+ git_plugin.archive_to_release_path
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ desc "Determine the revision that will be deployed"
64
+ task :set_current_revision do
65
+ on release_roles(:all), in: :groups, limit: fetch(:git_max_concurrent_connections), wait: fetch(:git_wait_interval) do
66
+ within repo_path do
67
+ with fetch(:git_environmental_variables) do
68
+ set :current_revision, git_plugin.fetch_revision
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,53 @@
1
+ # TODO: this is nearly identical to git.rake. DRY up?
2
+
3
+ # This trick lets us access the Hg plugin within `on` blocks.
4
+ hg_plugin = self
5
+
6
+ namespace :hg do
7
+ desc "Check that the repo is reachable"
8
+ task :check do
9
+ on release_roles :all do
10
+ hg_plugin.check_repo_is_reachable
11
+ end
12
+ end
13
+
14
+ desc "Clone the repo to the cache"
15
+ task :clone do
16
+ on release_roles :all do
17
+ if hg_plugin.repo_mirror_exists?
18
+ info t(:mirror_exists, at: repo_path)
19
+ else
20
+ within deploy_path do
21
+ hg_plugin.clone_repo
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ desc "Pull changes from the remote repo"
28
+ task update: :'hg:clone' do
29
+ on release_roles :all do
30
+ within repo_path do
31
+ hg_plugin.update_mirror
32
+ end
33
+ end
34
+ end
35
+
36
+ desc "Copy repo to releases"
37
+ task create_release: :'hg:update' do
38
+ on release_roles :all do
39
+ within repo_path do
40
+ hg_plugin.archive_to_release_path
41
+ end
42
+ end
43
+ end
44
+
45
+ desc "Determine the revision that will be deployed"
46
+ task :set_current_revision do
47
+ on release_roles :all do
48
+ within repo_path do
49
+ set :current_revision, hg_plugin.fetch_revision
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,53 @@
1
+ # TODO: this is nearly identical to git.rake. DRY up?
2
+
3
+ # This trick lets us access the Svn plugin within `on` blocks.
4
+ svn_plugin = self
5
+
6
+ namespace :svn do
7
+ desc "Check that the repo is reachable"
8
+ task :check do
9
+ on release_roles :all do
10
+ svn_plugin.check_repo_is_reachable
11
+ end
12
+ end
13
+
14
+ desc "Clone the repo to the cache"
15
+ task :clone do
16
+ on release_roles :all do
17
+ if svn_plugin.repo_mirror_exists?
18
+ info t(:mirror_exists, at: repo_path)
19
+ else
20
+ within deploy_path do
21
+ svn_plugin.clone_repo
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ desc "Pull changes from the remote repo"
28
+ task update: :'svn:clone' do
29
+ on release_roles :all do
30
+ within repo_path do
31
+ svn_plugin.update_mirror
32
+ end
33
+ end
34
+ end
35
+
36
+ desc "Copy repo to releases"
37
+ task create_release: :'svn:update' do
38
+ on release_roles :all do
39
+ within repo_path do
40
+ svn_plugin.archive_to_release_path
41
+ end
42
+ end
43
+ end
44
+
45
+ desc "Determine the revision that will be deployed"
46
+ task :set_current_revision do
47
+ on release_roles :all do
48
+ within repo_path do
49
+ set :current_revision, svn_plugin.fetch_revision
50
+ end
51
+ end
52
+ end
53
+ end