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.
- checksums.yaml +5 -5
- data/.circleci/config.yml +129 -0
- data/.github/issue_template.md +19 -0
- data/.github/pull_request_template.md +22 -0
- data/.github/release-drafter.yml +17 -0
- data/.github/workflows/push.yml +12 -0
- data/.gitignore +8 -5
- data/.rubocop.yml +62 -0
- data/CHANGELOG.md +1 -307
- data/CONTRIBUTING.md +63 -93
- data/DEVELOPMENT.md +127 -0
- data/Dangerfile +1 -0
- data/Gemfile +40 -3
- data/LICENSE.txt +1 -1
- data/README.md +127 -44
- data/RELEASING.md +17 -0
- data/Rakefile +13 -2
- data/UPGRADING-3.7.md +86 -0
- data/bin/cap +1 -1
- data/capistrano.gemspec +21 -24
- data/features/deploy.feature +35 -1
- data/features/doctor.feature +11 -0
- data/features/installation.feature +8 -3
- data/features/stage_failure.feature +9 -0
- data/features/step_definitions/assertions.rb +51 -18
- data/features/step_definitions/cap_commands.rb +9 -0
- data/features/step_definitions/setup.rb +53 -9
- data/features/subdirectory.feature +9 -0
- data/features/support/env.rb +5 -5
- data/features/support/remote_command_helpers.rb +12 -6
- data/features/support/vagrant_helpers.rb +17 -11
- data/lib/Capfile +1 -1
- data/lib/capistrano/all.rb +10 -10
- data/lib/capistrano/application.rb +47 -34
- data/lib/capistrano/configuration/empty_filter.rb +9 -0
- data/lib/capistrano/configuration/filter.rb +17 -47
- data/lib/capistrano/configuration/host_filter.rb +29 -0
- data/lib/capistrano/configuration/null_filter.rb +9 -0
- data/lib/capistrano/configuration/plugin_installer.rb +51 -0
- data/lib/capistrano/configuration/question.rb +31 -9
- data/lib/capistrano/configuration/role_filter.rb +29 -0
- data/lib/capistrano/configuration/scm_resolver.rb +149 -0
- data/lib/capistrano/configuration/server.rb +29 -23
- data/lib/capistrano/configuration/servers.rb +21 -14
- data/lib/capistrano/configuration/validated_variables.rb +110 -0
- data/lib/capistrano/configuration/variables.rb +112 -0
- data/lib/capistrano/configuration.rb +91 -44
- data/lib/capistrano/defaults.rb +26 -4
- data/lib/capistrano/deploy.rb +1 -1
- data/lib/capistrano/doctor/environment_doctor.rb +19 -0
- data/lib/capistrano/doctor/gems_doctor.rb +45 -0
- data/lib/capistrano/doctor/output_helpers.rb +79 -0
- data/lib/capistrano/doctor/servers_doctor.rb +105 -0
- data/lib/capistrano/doctor/variables_doctor.rb +74 -0
- data/lib/capistrano/doctor.rb +6 -0
- data/lib/capistrano/dotfile.rb +1 -2
- data/lib/capistrano/dsl/env.rb +9 -47
- data/lib/capistrano/dsl/paths.rb +11 -25
- data/lib/capistrano/dsl/stages.rb +14 -2
- data/lib/capistrano/dsl/task_enhancements.rb +7 -12
- data/lib/capistrano/dsl.rb +47 -16
- data/lib/capistrano/framework.rb +1 -1
- data/lib/capistrano/i18n.rb +32 -24
- data/lib/capistrano/immutable_task.rb +30 -0
- data/lib/capistrano/install.rb +1 -1
- data/lib/capistrano/plugin.rb +95 -0
- data/lib/capistrano/proc_helpers.rb +13 -0
- data/lib/capistrano/scm/git.rb +100 -0
- data/lib/capistrano/scm/hg.rb +55 -0
- data/lib/capistrano/scm/plugin.rb +13 -0
- data/lib/capistrano/scm/svn.rb +56 -0
- data/lib/capistrano/scm/tasks/git.rake +73 -0
- data/lib/capistrano/scm/tasks/hg.rake +53 -0
- data/lib/capistrano/scm/tasks/svn.rake +53 -0
- data/lib/capistrano/scm.rb +7 -20
- data/lib/capistrano/setup.rb +20 -6
- data/lib/capistrano/tasks/console.rake +4 -8
- data/lib/capistrano/tasks/deploy.rake +105 -73
- data/lib/capistrano/tasks/doctor.rake +24 -0
- data/lib/capistrano/tasks/framework.rake +13 -14
- data/lib/capistrano/tasks/install.rake +14 -15
- data/lib/capistrano/templates/Capfile +21 -10
- data/lib/capistrano/templates/deploy.rb.erb +17 -26
- data/lib/capistrano/templates/stage.rb.erb +9 -9
- data/lib/capistrano/upload_task.rb +1 -1
- data/lib/capistrano/version.rb +1 -1
- data/lib/capistrano/version_validator.rb +5 -10
- data/spec/integration/dsl_spec.rb +289 -240
- data/spec/integration_spec_helper.rb +3 -5
- data/spec/lib/capistrano/application_spec.rb +23 -39
- data/spec/lib/capistrano/configuration/empty_filter_spec.rb +17 -0
- data/spec/lib/capistrano/configuration/filter_spec.rb +83 -85
- data/spec/lib/capistrano/configuration/host_filter_spec.rb +71 -0
- data/spec/lib/capistrano/configuration/null_filter_spec.rb +17 -0
- data/spec/lib/capistrano/configuration/plugin_installer_spec.rb +98 -0
- data/spec/lib/capistrano/configuration/question_spec.rb +58 -26
- data/spec/lib/capistrano/configuration/role_filter_spec.rb +80 -0
- data/spec/lib/capistrano/configuration/scm_resolver_spec.rb +55 -0
- data/spec/lib/capistrano/configuration/server_spec.rb +106 -113
- data/spec/lib/capistrano/configuration/servers_spec.rb +129 -145
- data/spec/lib/capistrano/configuration_spec.rb +224 -63
- data/spec/lib/capistrano/doctor/environment_doctor_spec.rb +44 -0
- data/spec/lib/capistrano/doctor/gems_doctor_spec.rb +67 -0
- data/spec/lib/capistrano/doctor/output_helpers_spec.rb +47 -0
- data/spec/lib/capistrano/doctor/servers_doctor_spec.rb +86 -0
- data/spec/lib/capistrano/doctor/variables_doctor_spec.rb +89 -0
- data/spec/lib/capistrano/dsl/paths_spec.rb +97 -59
- data/spec/lib/capistrano/dsl/task_enhancements_spec.rb +57 -37
- data/spec/lib/capistrano/dsl_spec.rb +84 -11
- data/spec/lib/capistrano/immutable_task_spec.rb +31 -0
- data/spec/lib/capistrano/plugin_spec.rb +84 -0
- data/spec/lib/capistrano/scm/git_spec.rb +184 -0
- data/spec/lib/capistrano/scm/hg_spec.rb +109 -0
- data/spec/lib/capistrano/scm/svn_spec.rb +137 -0
- data/spec/lib/capistrano/scm_spec.rb +7 -8
- data/spec/lib/capistrano/upload_task_spec.rb +7 -7
- data/spec/lib/capistrano/version_validator_spec.rb +61 -46
- data/spec/lib/capistrano_spec.rb +2 -3
- data/spec/spec_helper.rb +21 -8
- data/spec/support/Vagrantfile +9 -10
- data/spec/support/tasks/database.rake +3 -3
- data/spec/support/tasks/fail.rake +4 -3
- data/spec/support/tasks/failed.rake +2 -2
- data/spec/support/tasks/plugin.rake +6 -0
- data/spec/support/tasks/root.rake +4 -4
- data/spec/support/test_app.rb +64 -39
- metadata +100 -55
- data/.travis.yml +0 -13
- data/features/remote_file_task.feature +0 -14
- data/lib/capistrano/git.rb +0 -46
- data/lib/capistrano/hg.rb +0 -43
- data/lib/capistrano/svn.rb +0 -38
- data/lib/capistrano/tasks/git.rake +0 -81
- data/lib/capistrano/tasks/hg.rake +0 -52
- data/lib/capistrano/tasks/svn.rake +0 -52
- data/spec/lib/capistrano/git_spec.rb +0 -81
- data/spec/lib/capistrano/hg_spec.rb +0 -81
- data/spec/lib/capistrano/svn_spec.rb +0 -79
data/lib/capistrano/i18n.rb
CHANGED
|
@@ -1,37 +1,45 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "i18n"
|
|
2
2
|
|
|
3
3
|
en = {
|
|
4
|
-
starting:
|
|
5
|
-
capified:
|
|
6
|
-
start:
|
|
7
|
-
update:
|
|
8
|
-
finalize:
|
|
9
|
-
finishing:
|
|
10
|
-
finished:
|
|
11
|
-
stage_not_set:
|
|
12
|
-
written_file:
|
|
13
|
-
question:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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:
|
|
24
|
-
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:
|
|
29
|
-
cannot_switch:
|
|
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,
|
|
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
|
data/lib/capistrano/install.rb
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
load File.expand_path(File.join(File.dirname(__FILE__),
|
|
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
|