capistrano 3.4.0 → 3.17.1

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 (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