edploy 2.0.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.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +92 -0
- data/README.rdoc.fast_remote_cache +48 -0
- data/Rakefile +1 -0
- data/TODO.TXT +17 -0
- data/bin/dploy +15 -0
- data/bin/dploygen +39 -0
- data/bin/dployify +29 -0
- data/edploy.gemspec +21 -0
- data/lib/capistrano/ext/mailer.rb +90 -0
- data/lib/capistrano/ext/multistage.rb +59 -0
- data/lib/capistrano/ext/output_catcher.rb +97 -0
- data/lib/capistrano/ext/output_hooks.rb +54 -0
- data/lib/capistrano/recipes/deploy/strategy/fast_remote_cache.rb +44 -0
- data/lib/capistrano/recipes/deploy/strategy/utilities/copy.rb +53 -0
- data/lib/edploy/environment_capistrano.rb +19 -0
- data/lib/edploy/recipes/apache.rb +8 -0
- data/lib/edploy/recipes/bundle_install.rb +15 -0
- data/lib/edploy/recipes/fast_remote_cache.rb +43 -0
- data/lib/edploy/recipes/fast_remote_cache_extensions.rb +11 -0
- data/lib/edploy/recipes/hooks.rb +24 -0
- data/lib/edploy/recipes/production.rb +56 -0
- data/lib/edploy/recipes/rails.rb +5 -0
- data/lib/edploy/recipes/setup_project.rb +26 -0
- data/lib/edploy/recipes/smart_deploy.rb +47 -0
- data/lib/edploy/recipes/templates.rb +60 -0
- data/lib/edploy/recipes/web_disable_enable.rb +32 -0
- data/lib/edploy.rb +17 -0
- data/lib/edployify/configuration.rb +140 -0
- data/lib/edployify/preferences.rb +176 -0
- data/lib/edployify/project.rb +69 -0
- data/lib/edployify/template.rb +84 -0
- data/lib/edployify.rb +6 -0
- data/lib/edployscripts/archive.rb +27 -0
- data/lib/edployscripts/environment_scripts.rb +47 -0
- data/lib/edployscripts/file_handling.rb +28 -0
- data/lib/edployscripts/git.rb +27 -0
- data/lib/edployscripts.rb +6 -0
- data/templates/config/edploy/copy/extract/.gitkeep +0 -0
- data/templates/config/edploy/copy/init_scripts/.gitkeep +0 -0
- data/templates/config/edploy/copy/project_files/.gitkeep +0 -0
- data/templates/config/edploy/scripts/after_deploy_setup/.gitkeep +0 -0
- data/templates/config/edploy/scripts/after_deploy_symlink/passenger/clear_file_cache.erb +7 -0
- data/templates/config/edploy/scripts/after_deploy_update_code/make_symlinks.erb +74 -0
- data/templates/config/edploy/scripts/edploygen/01_bundle_install.erb +5 -0
- data/templates/config/edploy/scripts/edploygen/01_prepare_servers.post.erb +12 -0
- data/templates/config/edploy/scripts/edploygen/02_whenever_configs.erb +36 -0
- data/templates/config/edploy/templates/passenger/activate.rb.erb +2 -0
- data/templates/config/edploy/templates/passenger/after_config.rb.erb +2 -0
- data/templates/config/edploy/templates/passenger/apache_vhost.erb.erb +107 -0
- data/templates/config/edploy/templates/passenger/config.rb.erb +3 -0
- data/templates/config/edploy/templates/passenger/deactivate.rb.erb +1 -0
- data/templates/config/edploy/whenever/generic.rb.erb +12 -0
- metadata +113 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
# ---------------------------------------------------------------------------
|
2
|
+
# A simple copy script for doing hard links and symbolic links instead of
|
3
|
+
# explicit copies. Some OS's will already have a utility to do this, but
|
4
|
+
# some won't; this file suffices in either case.
|
5
|
+
#
|
6
|
+
# Usage: ruby copy.rb <source> <target> <exclude> ...
|
7
|
+
#
|
8
|
+
# The <source> directory is recursively descended, and hard links to all of
|
9
|
+
# the files are created in corresponding locations under <target>. Symbolic
|
10
|
+
# links in <source> map to symbolic links in <target> that point to the same
|
11
|
+
# destination.
|
12
|
+
#
|
13
|
+
# All arguments after <target> are taken to be exclude patterns. Any file
|
14
|
+
# or directory in <source> that matches any of those patterns will be
|
15
|
+
# skipped, and will thus not be present in <target>.
|
16
|
+
# ---------------------------------------------------------------------------
|
17
|
+
# This file is distributed under the terms of the MIT license by 37signals,
|
18
|
+
# LLC, and is copyright (c) 2008 by the same. See the LICENSE file distributed
|
19
|
+
# with this file for the complete text of the license.
|
20
|
+
# ---------------------------------------------------------------------------
|
21
|
+
require 'fileutils'
|
22
|
+
|
23
|
+
from = ARGV.shift or abort "need source directory"
|
24
|
+
to = ARGV.shift or abort "need target directory"
|
25
|
+
|
26
|
+
exclude = ARGV
|
27
|
+
|
28
|
+
from = File.expand_path(from)
|
29
|
+
to = File.expand_path(to)
|
30
|
+
|
31
|
+
Dir.chdir(from) do
|
32
|
+
FileUtils.mkdir_p(to)
|
33
|
+
queue = Dir.glob("*", File::FNM_DOTMATCH)
|
34
|
+
while queue.any?
|
35
|
+
item = queue.shift
|
36
|
+
name = File.basename(item)
|
37
|
+
|
38
|
+
next if name == "." || name == ".."
|
39
|
+
next if exclude.any? { |pattern| File.fnmatch(pattern, item) }
|
40
|
+
|
41
|
+
source = File.join(from, item)
|
42
|
+
target = File.join(to, item)
|
43
|
+
|
44
|
+
if File.symlink?(item)
|
45
|
+
FileUtils.ln_s(File.readlink(source), target)
|
46
|
+
elsif File.directory?(item)
|
47
|
+
queue += Dir.glob("#{item}/*", File::FNM_DOTMATCH)
|
48
|
+
FileUtils.mkdir_p(target, :mode => File.stat(item).mode)
|
49
|
+
else
|
50
|
+
FileUtils.ln(source, target)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
if ENV['BUNDLE_GEMFILE'].nil? || ENV['BUNDLE_BIN_PATH'].nil?
|
2
|
+
abort "You should run this with bundle exec!"
|
3
|
+
elsif !File.exists?(File.join(Dir.getwd, 'Capfile'))
|
4
|
+
abort "You should run this from the rails root!"
|
5
|
+
end
|
6
|
+
|
7
|
+
set :rails_root, Dir.getwd
|
8
|
+
|
9
|
+
require 'Syck'
|
10
|
+
|
11
|
+
Syck.load_file(File.join(rails_root, 'config', 'edploy', 'edploy.yml')).each do |key, value|
|
12
|
+
if key.to_sym == :ssh_options
|
13
|
+
value.each do |ssh_option, value|
|
14
|
+
ssh_options[ssh_option.to_sym] = value
|
15
|
+
end
|
16
|
+
else
|
17
|
+
set key.to_sym, value
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
set :bundle_path, "vendor/bundle"
|
2
|
+
set :bundle_without, "development test"
|
3
|
+
|
4
|
+
namespace :edploy do
|
5
|
+
after 'deploy:update_code', 'edploy:bundle_install'
|
6
|
+
task :bundle_install do
|
7
|
+
commands = []
|
8
|
+
[ bundle_path, ".bundle" ].uniq.each do |link_path|
|
9
|
+
commands << "mkdir -p #{shared_path}/#{link_path}"
|
10
|
+
commands << "ln -nfs #{shared_path}/#{link_path} #{latest_release}/#{link_path}"
|
11
|
+
end
|
12
|
+
commands << "cd #{latest_release} ; bundle install --path #{shared_path}/#{bundle_path} --local --without #{bundle_without} || bundle install --path #{shared_path}/#{bundle_path} --without #{bundle_without}"
|
13
|
+
run commands.join(' ; ')
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# ---------------------------------------------------------------------------
|
2
|
+
# This is a recipe definition file for Capistrano. The tasks are documented
|
3
|
+
# below.
|
4
|
+
# ---------------------------------------------------------------------------
|
5
|
+
# This file is distributed under the terms of the MIT license by 37signals,
|
6
|
+
# LLC, and is copyright (c) 2008 by the same. See the LICENSE file distributed
|
7
|
+
# with this file for the complete text of the license.
|
8
|
+
# ---------------------------------------------------------------------------
|
9
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
10
|
+
|
11
|
+
namespace :fast_remote_cache do
|
12
|
+
|
13
|
+
desc <<-DESC
|
14
|
+
Perform any setup required by fast_remote_cache. This is called
|
15
|
+
automatically after deploy:setup, but may be invoked manually to configure
|
16
|
+
a new machine. It is also necessary to invoke when you are switching to the
|
17
|
+
fast_remote_cache strategy for the first time.
|
18
|
+
DESC
|
19
|
+
task :setup, :except => { :no_release => true } do
|
20
|
+
if deploy_via == :fast_remote_cache
|
21
|
+
strategy.setup!
|
22
|
+
else
|
23
|
+
logger.important "you're including the fast_remote_cache strategy, but not using it!"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
desc <<-DESC
|
28
|
+
Updates the remote cache. This is handy for either priming a new box so
|
29
|
+
the cache is all set for the first deploy, or for preparing for a large
|
30
|
+
deploy by making sure the cache is updated before the deploy goes through.
|
31
|
+
Either way, this will happen automatically as part of a deploy; this task
|
32
|
+
is purely convenience for giving admins more control over the deployment.
|
33
|
+
DESC
|
34
|
+
task :prepare, :except => { :no_release => true } do
|
35
|
+
if deploy_via == :fast_remote_cache
|
36
|
+
strategy.prepare!
|
37
|
+
else
|
38
|
+
logger.important "#{current_task.fully_qualified_name} only works with the fast_remote_cache strategy"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
after "deploy:setup", "fast_remote_cache:setup"
|
@@ -0,0 +1,11 @@
|
|
1
|
+
namespace :edploy do
|
2
|
+
before 'fast_remote_cache:prepare', 'edploy:gc'
|
3
|
+
task :gc do
|
4
|
+
run "cd #{shared_path}/cached-copy ; git gc"
|
5
|
+
end
|
6
|
+
|
7
|
+
after 'fast_remote_cache:prepare', 'edploy:pre_bundle'
|
8
|
+
task :pre_bundle do
|
9
|
+
run "cd #{shared_path}/cached-copy ; bundle install --path #{shared_path}/vendor/bundle --local --without development test || bundle install --path #{shared_path}/vendor/bundle --without development test"
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
namespace :edploy do
|
2
|
+
|
3
|
+
%w(deploy:update_code deploy:symlink deploy:setup).each do |task_name|
|
4
|
+
[ :before, :after ].each do |milestone|
|
5
|
+
|
6
|
+
subdir = "#{milestone}_#{task_name.gsub(/:/, '_')}"
|
7
|
+
Dir[File.join(rails_root, 'config', 'edploy', 'scripts', subdir, "**", "*")].sort.each do |full_entry|
|
8
|
+
next if File.directory?(full_entry)
|
9
|
+
|
10
|
+
entry = full_entry[File.join(rails_root, 'config', 'edploy', 'scripts', subdir, "/").length..-1]
|
11
|
+
roles = (entry.include?('/') ? File.dirname(entry).split('_').map(&:to_sym) : nil)
|
12
|
+
options = {}
|
13
|
+
options[:roles] = roles if roles
|
14
|
+
script_name = File.basename(entry).to_sym
|
15
|
+
|
16
|
+
self.send(milestone, task_name, "edploy:#{script_name}")
|
17
|
+
task script_name, options do
|
18
|
+
run "cd #{latest_release} ; RAILS_ENV=#{rails_env} PROJECT_PATH=#{latest_release} DEPLOY_USER=#{user} DEPLOY_GROUP=#{group} bundle exec config/edploy/scripts/#{subdir}/#{entry}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
after 'production', 'setup_production'
|
2
|
+
|
3
|
+
task :setup_production do
|
4
|
+
set :branch, "production"
|
5
|
+
set :rails_env, 'production'
|
6
|
+
|
7
|
+
EVEN_PASSENGER_HOSTS = find_servers(:roles => :passenger).each_with_index.map { |s, i| i % 2 == 1 ? s : nil }.compact
|
8
|
+
ODD_PASSENGER_HOSTS = find_servers(:roles => :passenger).each_with_index.map { |s, i| i % 2 == 0 ? s : nil }.compact
|
9
|
+
EVEN_DB_HOSTS = find_servers(:roles => :db).each_with_index.map { |s, i| i % 2 == 1 ? s : nil }.compact
|
10
|
+
ODD_DB_HOSTS = find_servers(:roles => :db).each_with_index.map { |s, i| i % 2 == 0 ? s : nil }.compact
|
11
|
+
|
12
|
+
def filter_hosts(hostfilter)
|
13
|
+
old_hostfilter = ENV['HOSTFILTER']
|
14
|
+
ENV['HOSTFILTER'] = hostfilter.to_s
|
15
|
+
yield
|
16
|
+
if old_hostfilter.nil?
|
17
|
+
ENV.delete('HOSTFILTER')
|
18
|
+
else
|
19
|
+
ENV['HOSTFILTER'] = old_hostfilter
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
namespace :deploy do
|
24
|
+
desc "phased deploy of app on production"
|
25
|
+
task :zero do
|
26
|
+
[ ODD_PASSENGER_HOSTS + ODD_DB_HOSTS, EVEN_PASSENGER_HOSTS + EVEN_DB_HOSTS ].each do |hostlist|
|
27
|
+
filter_hosts(hostlist.join(',')) do
|
28
|
+
top.deploy.zero_downtime
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
task :zero_downtime do
|
34
|
+
top.deploy.update
|
35
|
+
top.deploy.restart
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
namespace :edploy do
|
41
|
+
namespace :apache do
|
42
|
+
desc "phased restart of apache on production"
|
43
|
+
task :restart, :roles => :passenger do
|
44
|
+
[ ODD_PASSENGER_HOSTS, EVEN_PASSENGER_HOSTS ].each do |hostlist|
|
45
|
+
filter_hosts(hostlist.join(',')) do
|
46
|
+
top.deploy.apache.actual_restart
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
task :actual_restart, :roles => :passenger do
|
52
|
+
run "apache2ctl configtest && sudo /etc/init.d/apache2 restart"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path('../../../edployscripts/archive', __FILE__)
|
2
|
+
require File.expand_path('../../../edployscripts/file_handling', __FILE__)
|
3
|
+
|
4
|
+
namespace :edploy do
|
5
|
+
|
6
|
+
after 'deploy:setup', 'edploy:setup_project'
|
7
|
+
task :setup_project do
|
8
|
+
extract_path = File.expand_path('../../config/copy/extract', __FILE__)
|
9
|
+
init_scripts_path = File.expand_path('../../config/copy/init_scripts', __FILE__)
|
10
|
+
|
11
|
+
Edploy::FileHandling.iterate_dir_items(extract_path) do |dirname, basename, relative_entry, fqpn|
|
12
|
+
Edploy::FileHandling.upload_file(fqpn, "#{shared_path}/tmp") do |tmp_file|
|
13
|
+
target_dir = dirname.gsub(/HOME/, '~')
|
14
|
+
Edploy::Archive.extract tmp_file, target_dir, :remove => true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
Edploy::FileHandling.iterate_dir_items(init_scripts_path) do |dirname, basename, relative_entry, fqpn|
|
19
|
+
Edploy::FileHandling.upload_file(fqpn, "#{shared_path}/tmp") do |tmp_file|
|
20
|
+
script_name = "#{application}_#{stage}_#{basename}"
|
21
|
+
system("sudo sh -c 'test -f /etc/init.d/#{script_name} || { cp #{tmp_file} /etc/init.d/#{script_name} ; chmod 755 /etc/init.d/#{script_name} ; update-rc.d #{script_name} defaults ; }'")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
namespace :deploy do
|
2
|
+
|
3
|
+
desc <<-DESC
|
4
|
+
Deploys your project. Does smart deploy if this is activated.
|
5
|
+
DESC
|
6
|
+
task :default do
|
7
|
+
if exists?(:smart_deploy) && smart_deploy
|
8
|
+
top.deploy.smart
|
9
|
+
else
|
10
|
+
top.deploy.code
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
desc <<-DESC
|
15
|
+
Deploys your project. This calls both `update' and `restart'. Note that \
|
16
|
+
this will generally only work for applications that have already been deployed \
|
17
|
+
once. For a "cold" deploy, you'll want to take a look at the `deploy:cold' \
|
18
|
+
task, which handles the cold start specifically.
|
19
|
+
DESC
|
20
|
+
task :code do
|
21
|
+
update
|
22
|
+
restart
|
23
|
+
end
|
24
|
+
|
25
|
+
desc <<-DESC
|
26
|
+
Deploys your project. Automagically figures out if deploy:setup, deploy:cold, \
|
27
|
+
deploy:migrations or deploy:default is needed.
|
28
|
+
DESC
|
29
|
+
task :smart do
|
30
|
+
project_is_setup = (capture("find #{deploy_to} -mindepth 1 -maxdepth 1 -type d \\( -name 'releases' -o -name 'shared' \\) 2>/dev/null | wc -l").to_i == 2)
|
31
|
+
top.deploy.setup unless project_is_setup
|
32
|
+
at_least_one_release_exists = capture("find #{releases_path} -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l").to_i > 0
|
33
|
+
unless at_least_one_release_exists
|
34
|
+
top.deploy.cold
|
35
|
+
else
|
36
|
+
remote_migrations = capture("find #{latest_release}/db/migrate -type f -name '*.rb' -exec basename {} .rb \\; 2>/dev/null || true").split("\n")
|
37
|
+
local_migrations = `find db/migrate -type f -name '*.rb' -exec basename {} .rb \\; 2>/dev/null || true`.split("\n")
|
38
|
+
pending_migrations = !(local_migrations - remote_migrations).empty?
|
39
|
+
if pending_migrations
|
40
|
+
top.deploy.migrations
|
41
|
+
else
|
42
|
+
top.deploy.code
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'fileutils'
|
3
|
+
def render_template(local_template)
|
4
|
+
template_name = File.basename(local_template)
|
5
|
+
file_name = File.basename(template_name, '.erb')
|
6
|
+
app = File.basename(File.dirname(local_template))
|
7
|
+
path = File.join(deploy_to, app, file_name)
|
8
|
+
|
9
|
+
template = ERB.new(IO.read(local_template))
|
10
|
+
rendered_template = template.result(binding)
|
11
|
+
|
12
|
+
tmp_path = File.join('/tmp/', "#{File.basename(path)}-$CAPISTRANO:HOST$")
|
13
|
+
put(rendered_template, tmp_path, :mode => 0644)
|
14
|
+
send run_method, <<-CMD
|
15
|
+
sh -c "install -m#{sprintf("%3o",0644)} #{tmp_path} #{path} &&
|
16
|
+
rm -f #{tmp_path}"
|
17
|
+
CMD
|
18
|
+
end
|
19
|
+
|
20
|
+
TEMPLATES = {}
|
21
|
+
Dir[File.expand_path("../../config/templates/*", __FILE__)].each do |app|
|
22
|
+
TEMPLATES[File.basename(app).to_sym] = {
|
23
|
+
:templates => Dir[File.join(app, '*.erb')],
|
24
|
+
:config => File.join(app, 'config.rb'),
|
25
|
+
:after_config => File.join(app, 'after_config.rb'),
|
26
|
+
:activate => File.join(app, 'activate.rb'),
|
27
|
+
:deactivate => File.join(app, 'deactivate.rb'),
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
TEMPLATES.each do |application, data|
|
32
|
+
eval File.read(data[:config]) if File.exists?(data[:config])
|
33
|
+
|
34
|
+
namespace :edploy do
|
35
|
+
namespace application do
|
36
|
+
after 'deploy:setup', "edploy:#{application}:config"
|
37
|
+
desc "Push #{application} config files to server"
|
38
|
+
task :config, :roles => application do
|
39
|
+
data[:templates].each do |template|
|
40
|
+
render_template(template)
|
41
|
+
end
|
42
|
+
eval File.read(data[:after_config]) if File.exists?(data[:after_config])
|
43
|
+
end
|
44
|
+
|
45
|
+
if File.exists?(data[:activate])
|
46
|
+
desc "Activate #{application}"
|
47
|
+
task :activate, :roles => application do
|
48
|
+
eval File.read(data[:activate])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
if File.exists?(data[:deactivate])
|
53
|
+
desc "Deactivate #{application}"
|
54
|
+
task :deactivate, :roles => application do
|
55
|
+
eval File.read(data[:deactivate])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
namespace :edploy do
|
2
|
+
namespace :web do
|
3
|
+
namespace :disable do
|
4
|
+
before 'deploy', 'edploy:web:disable:maintenance'
|
5
|
+
before 'deploy:migrations', 'edploy:web:disable:maintenance'
|
6
|
+
task :maintenance, :roles => :passenger do
|
7
|
+
on_rollback { run "rm -f #{shared_path}/system/maintenance.html" }
|
8
|
+
run "cp #{current_path}/config/edploy/copy/project_files/#{stage}/$(hostname)/public/maintenance.html #{shared_path}/system/ 2>/dev/null || cp #{current_path}/config/edploy/copy/project_files/#{stage}/public/maintenance.html #{shared_path}/system/ 2>/dev/null || cp #{current_path}/public/maintenance.html #{shared_path}/system/ 2>/dev/null"
|
9
|
+
end
|
10
|
+
|
11
|
+
before 'deploy:zero_downtime', 'edploy:web:disable:zero_downtime'
|
12
|
+
task :zero_downtime, :roles => :passenger do
|
13
|
+
run "mv /var/www/check.txt /var/www/check2.txt 2>/dev/null || true"
|
14
|
+
# sudo "/sbin/iptables -D INPUT -p tcp -s 95.170.77.132/26 -m state --state NEW --dport 443 -j ACCEPT 2>/dev/null || true"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
namespace :enable do
|
19
|
+
after 'deploy', 'edploy:web:enable:maintenance'
|
20
|
+
after 'deploy:migrations', 'edploy:web:enable:maintenance'
|
21
|
+
task :maintenance, :roles => :passenger do
|
22
|
+
run "rm -f #{shared_path}/system/maintenance.html"
|
23
|
+
end
|
24
|
+
|
25
|
+
after 'deploy:zero_downtime', 'edploy:web:enable:zero_downtime'
|
26
|
+
task :zero_downtime, :roles => :passenger do
|
27
|
+
run "mv /var/www/check2.txt /var/www/check.txt 2>/dev/null || true"
|
28
|
+
# sudo "/sbin/iptables -A INPUT -p tcp -s 95.170.77.132/26 -m state --state NEW --dport 443 -j ACCEPT"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/edploy.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Copyright (c) 2009-2012 by Ewout Vonk. All rights reserved.
|
2
|
+
|
3
|
+
# prevent loading when called by Bundler, only load when called by capistrano
|
4
|
+
if caller.any? { |callstack_line| callstack_line =~ /^Capfile:/ }
|
5
|
+
unless Capistrano::Configuration.respond_to?(:instance)
|
6
|
+
abort "edploy requires Capistrano 2"
|
7
|
+
end
|
8
|
+
|
9
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
10
|
+
load File.expand_path('../edploy/environment_capistrano.rb', __FILE__)
|
11
|
+
load File.expand_path('../capistrano/ext/multistage.rb', __FILE__)
|
12
|
+
# load File.expand_path('../capistrano/ext/mailer.rb', __FILE__)
|
13
|
+
# load File.expand_path('../capistrano/ext/output_catcher.rb', __FILE__)
|
14
|
+
# load File.expand_path('../capistrano/ext/output_hooks.rb', __FILE__)
|
15
|
+
Dir[File.expand_path('../edploy/recipes/*.rb', __FILE__)].each { |plugin| load(plugin) }
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'highline'
|
2
|
+
require 'yaml'
|
3
|
+
require 'fileutils'
|
4
|
+
# work around problem where HighLine detects an eof on $stdin and raises an err
|
5
|
+
HighLine.track_eof = false
|
6
|
+
|
7
|
+
module Edployify
|
8
|
+
|
9
|
+
class Configuration
|
10
|
+
|
11
|
+
class << self
|
12
|
+
|
13
|
+
def configure
|
14
|
+
instance.configure
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_binding
|
18
|
+
instance.get_binding
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def instance
|
24
|
+
@@instance ||= self.new
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_binding
|
30
|
+
binding
|
31
|
+
end
|
32
|
+
|
33
|
+
CONFIGURATION_KEYS = {
|
34
|
+
:application => { :default => Proc.new { |c| File.basename(::RAILS_ROOT).gsub(/[^A-Za-z0-9_]/, '_').gsub(/_+/, '_') }, :type => Symbol },
|
35
|
+
:domain => { :default => Proc.new { |c| "#{c[:application]}.com" } },
|
36
|
+
:scm => { :default => :git, :type => Symbol },
|
37
|
+
:git_shallow_clone => { :default => true, :boolean => true },
|
38
|
+
:repository => { :default => Proc.new { |c| "git@HOSTNAME:#{c[:application]}.git" } },
|
39
|
+
:git_enable_submodules => { :default => false, :boolean => true },
|
40
|
+
:deploy_via => { :default => :fast_remote_cache, :type => Symbol },
|
41
|
+
:deploy_to => { :default => Proc.new { |c| "/apps/#{c[:application]}" } },
|
42
|
+
:user => { :default => 'deploy' },
|
43
|
+
:group => { :default => 'deploy' },
|
44
|
+
:normalize_asset_timestamps => { :default => false, :boolean => true },
|
45
|
+
:paranoid => { :ssh_option => true, :default => false, :boolean => true },
|
46
|
+
:forward_agent => { :ssh_option => true, :default => true, :boolean => true },
|
47
|
+
:notify_email => { :default => Proc.new { |c| "support@#{c[:application]}.com" } }
|
48
|
+
}
|
49
|
+
|
50
|
+
def configure
|
51
|
+
CONFIGURATION_KEYS.each do |variable, options|
|
52
|
+
if self.respond_to?(:"ask_#{variable}")
|
53
|
+
self.send(:"ask_#{variable}", variable, options)
|
54
|
+
elsif options[:ssh_option]
|
55
|
+
ask_ssh_option(variable, options)
|
56
|
+
else
|
57
|
+
ask_value(variable, options)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def ask_repository(variable, options = {})
|
65
|
+
default = base[variable]
|
66
|
+
unless default
|
67
|
+
preset = Edployify::Preferences.request_preset(:use)
|
68
|
+
project = highline.ask("Git project name (without .git): ") { |q| q.default = config[:application] if config[:application] }
|
69
|
+
default = preset.sub(/\{PROJECT\}/, project)
|
70
|
+
options[:default] = default
|
71
|
+
end
|
72
|
+
ask_value(variable, options)
|
73
|
+
end
|
74
|
+
|
75
|
+
def ask_ssh_option(variable, options = {})
|
76
|
+
ask_value(variable, options.merge(:base => config[:ssh_options]))
|
77
|
+
end
|
78
|
+
|
79
|
+
def ask_value(variable, options = {})
|
80
|
+
base = options[:base] || config
|
81
|
+
default = base[variable] || options[:default]
|
82
|
+
if default.is_a?(Proc)
|
83
|
+
default = default.call(config)
|
84
|
+
end
|
85
|
+
|
86
|
+
variable_prompt_name = variable.to_s.gsub(/(^|_)[A-Za-z0-9]/, &:upcase).gsub(/_/, ' ')
|
87
|
+
question_prompt = "#{variable_prompt_name} " # add trailing space so user input happens on the same line
|
88
|
+
|
89
|
+
value = if options[:boolean]
|
90
|
+
highline.agree(question_prompt) do |q|
|
91
|
+
q.default = (default ? "y" : "n") unless default.nil?
|
92
|
+
q.readline = true
|
93
|
+
end
|
94
|
+
else
|
95
|
+
arguments = [question_prompt]
|
96
|
+
arguments << options[:type] if options[:type]
|
97
|
+
highline.ask(*arguments) do |q|
|
98
|
+
q.default = default if default
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
base[variable] = value
|
103
|
+
write_file
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
|
108
|
+
def config
|
109
|
+
unless @config
|
110
|
+
edploy_yml = File.join(::RAILS_ROOT, 'config', 'edploy', 'edploy.yml')
|
111
|
+
FileUtils.touch edploy_yml
|
112
|
+
$edploy_yml = File.open(edploy_yml, "r+")
|
113
|
+
at_exit do
|
114
|
+
$edploy_yml.close unless $edploy_yml.closed?
|
115
|
+
end
|
116
|
+
config_contents = $edploy_yml.read
|
117
|
+
@config = config_contents.length == 0 ? {} : YAML::load(config_contents)
|
118
|
+
$edploy_yml.rewind
|
119
|
+
@config[:ssh_options] = {}
|
120
|
+
end
|
121
|
+
@config
|
122
|
+
end
|
123
|
+
|
124
|
+
def write_file
|
125
|
+
$edploy_yml.write YAML::dump(config)
|
126
|
+
$edploy_yml.truncate $edploy_yml.pos
|
127
|
+
$edploy_yml.rewind
|
128
|
+
end
|
129
|
+
|
130
|
+
def highline
|
131
|
+
@highline ||= HighLine.new
|
132
|
+
end
|
133
|
+
|
134
|
+
def method_missing(method, *args, &block)
|
135
|
+
config[method.to_sym] || config[method.to_s] || super
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|