capistrano-ext-projectdx 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/capistrano/ext/projectdx/all.rb +14 -0
- data/lib/capistrano/ext/projectdx/cache.rb +8 -0
- data/lib/capistrano/ext/projectdx/campfire.rb +59 -0
- data/lib/capistrano/ext/projectdx/docs.rb +15 -0
- data/lib/capistrano/ext/projectdx/git_branch.rb +60 -0
- data/lib/capistrano/ext/projectdx/misc.rb +35 -0
- data/lib/capistrano/ext/projectdx/passenger.rb +27 -0
- data/lib/capistrano/ext/projectdx/projectdx.rb +72 -0
- data/lib/capistrano/ext/projectdx/time.rb +29 -0
- data/lib/capistrano/ext/projectdx/web.rb +53 -0
- data/lib/capistrano/ext/projectdx.rb +18 -0
- metadata +80 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
# we have to call this something else so
|
2
|
+
# we do not keep loading this file over and over
|
3
|
+
Capistrano::Configuration.instance.load do
|
4
|
+
load_paths << File.dirname(__FILE__)
|
5
|
+
load('projectdx.rb')
|
6
|
+
load('campfire.rb')
|
7
|
+
load('git_branch.rb')
|
8
|
+
load('misc.rb')
|
9
|
+
load('time.rb')
|
10
|
+
load('web.rb')
|
11
|
+
load('passenger.rb')
|
12
|
+
load('docs.rb')
|
13
|
+
load('cache.rb')
|
14
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
namespace :cache do
|
2
|
+
desc "Empty out shared cachedir and the cached javascript and css"
|
3
|
+
task :clean, :roles => :web do
|
4
|
+
run "shopt -s nullglob; cd #{current_path} && for i in ./public/javascripts/cache_*.js; do /bin/rm ${i}; done"
|
5
|
+
run "shopt -s nullglob; cd #{current_path} && for i in ./public/stylesheets/cache_*.css; do /bin/rm ${i}; done"
|
6
|
+
run "shopt -s nullglob; cd #{shared_path} && /bin/rm -rf cache/*"
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
namespace :misc do
|
2
|
+
def send_to_campfire(message)
|
3
|
+
begin
|
4
|
+
gem 'tinder'
|
5
|
+
rescue Gem::LoadError
|
6
|
+
puts "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
7
|
+
puts ""
|
8
|
+
puts "not notifying because tinder not installed. Message is: '#{message}'"
|
9
|
+
puts ""
|
10
|
+
puts "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
11
|
+
return
|
12
|
+
end
|
13
|
+
require 'tinder'
|
14
|
+
# for some reason, ssl isn't working.
|
15
|
+
begin
|
16
|
+
campfire = Tinder::Campfire.new(campfire_host, :ssl => true)
|
17
|
+
campfire.login(campfire_login, campfire_password)
|
18
|
+
rescue => e
|
19
|
+
puts "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
20
|
+
puts ""
|
21
|
+
puts "Unable to login to campfire. Error is: '#{e}'"
|
22
|
+
puts "login: #{campfire_host}, #{campfire_login}, #{campfire_password}"
|
23
|
+
puts ""
|
24
|
+
puts "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
25
|
+
return
|
26
|
+
end
|
27
|
+
begin
|
28
|
+
room = campfire.find_room_by_name(campfire_room)
|
29
|
+
rescue => e
|
30
|
+
logger.error("Trouble initalizing campfire room #{campfire_room}")
|
31
|
+
return
|
32
|
+
end
|
33
|
+
begin
|
34
|
+
room.speak(message)
|
35
|
+
rescue => e
|
36
|
+
puts "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
37
|
+
puts ""
|
38
|
+
puts "Unable to send message to campfire. Message is: '#{message}'"
|
39
|
+
puts ""
|
40
|
+
puts "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
41
|
+
return
|
42
|
+
end
|
43
|
+
end
|
44
|
+
desc "[internal] Send campfire notifications on success"
|
45
|
+
task :send_success, :on_error => :continue do
|
46
|
+
t=end_time
|
47
|
+
time_msg=t.nil? ? '' : " in #{t} minutes"
|
48
|
+
send_to_campfire("#{Etc.getpwnam(Etc.getlogin)['gecos'].split.first} tried to deploy branch #{branch} to #{stage}. It succeeded#{time_msg}! :D")
|
49
|
+
end
|
50
|
+
|
51
|
+
desc "[internal] send notifications in case the deploy fails"
|
52
|
+
task :rollback_notification, :on_error => :continue do
|
53
|
+
on_rollback {
|
54
|
+
t=end_time
|
55
|
+
time_msg=t.nil? ? '' : " after #{t} minutes"
|
56
|
+
send_to_campfire("#{Etc.getpwnam(Etc.getlogin)['gecos'].split.first} tried to deploy branch #{branch} to #{stage}. It failed#{time_msg}. :.(")
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Capistrano::Configuration.instance.load do
|
2
|
+
namespace :deploy do
|
3
|
+
namespace :docs do
|
4
|
+
desc "update docs directory"
|
5
|
+
task :default do
|
6
|
+
run "cd #{current_path} && rake doc:local RDOC_DIR=#{docsdir}"
|
7
|
+
end
|
8
|
+
desc "force rebuild of docs directory"
|
9
|
+
task :rebuild do
|
10
|
+
run "/bin/rm -rf #{docsdir}"
|
11
|
+
top.deploy.docs.default
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
Capistrano::Configuration.instance.load do
|
2
|
+
def changed_in_git(filename)
|
3
|
+
`git diff --name-only`.grep(/^#{filename}$/).length > 0 ? true : false
|
4
|
+
end
|
5
|
+
|
6
|
+
def commit_of_rev(branch)
|
7
|
+
x=`git rev-parse --revs-only #{branch}`.chomp
|
8
|
+
return nil if x.empty?
|
9
|
+
return x
|
10
|
+
end
|
11
|
+
|
12
|
+
def commit_in_remote_branch?(commit,branch)
|
13
|
+
return false if commit.nil?
|
14
|
+
if %x{git branch -r --contains #{commit}}.grep(/^\s*origin\/#{branch}/).empty?
|
15
|
+
puts ""
|
16
|
+
puts "no rev matches #{commit} in the remote #{branch} branch(es)"
|
17
|
+
return false
|
18
|
+
end
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
def valid_commit?(commit)
|
23
|
+
return false if commit.nil?
|
24
|
+
if [ :production ].include? stage
|
25
|
+
return false unless commit_in_remote_branch?(commit,'production')
|
26
|
+
elsif [ :custbeta ].include? stage
|
27
|
+
return false unless commit_in_remote_branch?(commit,'custbeta')
|
28
|
+
end
|
29
|
+
return true
|
30
|
+
end
|
31
|
+
|
32
|
+
# returns the actual branch name, if it exists. nil if it does not
|
33
|
+
def remote_branch_name(branch)
|
34
|
+
return nil if branch.nil?
|
35
|
+
rem_branch = `git branch -r`.grep(/^\s*origin\/(v|)#{branch}$/)[0]
|
36
|
+
return nil if rem_branch.nil?
|
37
|
+
return rem_branch.sub(/^\s*origin\//, '').chomp
|
38
|
+
end
|
39
|
+
|
40
|
+
release = nil;
|
41
|
+
set :release_number do
|
42
|
+
commit=nil;
|
43
|
+
release=ENV[ 'DEPLOY_VERSION' ] if ENV[ 'DEPLOY_VERSION' ]
|
44
|
+
release=ENV['BUILD_VCS_NUMBER'][0,12] if ENV['BUILD_VCS_NUMBER']
|
45
|
+
commit = commit_of_rev(release)
|
46
|
+
while not valid_commit?(commit) do
|
47
|
+
release=Capistrano::CLI.ui.ask( 'Enter release number to deploy: ' )
|
48
|
+
commit=commit_of_rev(release)
|
49
|
+
end
|
50
|
+
commit
|
51
|
+
end
|
52
|
+
|
53
|
+
set :branch do
|
54
|
+
release_number
|
55
|
+
end
|
56
|
+
|
57
|
+
set :release_commit do
|
58
|
+
branch
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
namespace :misc do
|
2
|
+
desc "[internal] Send campfire notifications on success"
|
3
|
+
task :send_success, :on_error => :continue do
|
4
|
+
t=end_time
|
5
|
+
time_msg=t.nil? ? '' : " in #{t} minutes"
|
6
|
+
send_to_campfire("#{Etc.getpwnam(Etc.getlogin)['gecos'].split.first} tried to deploy branch #{branch} to #{stage}. It succeeded#{time_msg}! :D")
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "[internal] send notifications in case the deploy fails"
|
10
|
+
task :rollback_notification, :on_error => :continue do
|
11
|
+
on_rollback {
|
12
|
+
t=end_time
|
13
|
+
time_msg=t.nil? ? '' : " after #{t} minutes"
|
14
|
+
send_to_campfire("#{Etc.getpwnam(Etc.getlogin)['gecos'].split.first} tried to deploy branch #{branch} to #{stage}. It failed#{time_msg}. :.(")
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Add trigers on migration to restore database from production state. Used for running stage deployments with optional restore."
|
20
|
+
task :restoredb do
|
21
|
+
before "deploy:migrate", "deploy:db:reset_nobackup"
|
22
|
+
after "deploy:db:reset_nobackup", "deploy:tables"
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "Do full deploy of table updates"
|
26
|
+
task :full do
|
27
|
+
before "deploy:migrate", "deploy:tables"
|
28
|
+
end
|
29
|
+
|
30
|
+
namespace :rake do
|
31
|
+
desc "Allow running of remote rake tasks"
|
32
|
+
task :invoke do
|
33
|
+
run "cd #{deploy_to}/current && rake #{ENV['task']} RAILS_ENV=#{rails_env}"
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Capistrano::Configuration.instance.load do
|
2
|
+
namespace :deploy do
|
3
|
+
# these can be changed when passenger is on production
|
4
|
+
desc "Stop task is a no-op with passenger"
|
5
|
+
task :stop, :roles => :app do ; end
|
6
|
+
|
7
|
+
%w(start restart).each do |name|
|
8
|
+
desc "#{name} passenger on application"
|
9
|
+
task name, :roles => :app do
|
10
|
+
top.passenger.restart
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
namespace :passenger do
|
15
|
+
desc "Restart Passenger"
|
16
|
+
task :restart, :rols => :app do
|
17
|
+
run "touch #{current_path}/tmp/restart.txt"
|
18
|
+
if [ :production ].include? stage
|
19
|
+
run "curl -s -o /dev/null http://sonomacountyenergyaction.org/customers/2/geometries;true"
|
20
|
+
run "curl -s -o /dev/null http://sonomacountyenergyaction.org/customers/1/geometries;true"
|
21
|
+
else
|
22
|
+
run "curl -s -o /dev/null http:/sonoma.`hostname`/customers/2/geometries;true"
|
23
|
+
run "curl -s -o /dev/null http:/sonoma.`hostname`/customers/1/geometries;true"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
Capistrano::Configuration.instance.load do
|
2
|
+
namespace :deploy do
|
3
|
+
desc "update selinux context"
|
4
|
+
task :selinux do
|
5
|
+
run "if [ -d #{release_path} ]; then
|
6
|
+
chcon -R -t httpd_sys_content_t #{release_path} ;
|
7
|
+
fi;
|
8
|
+
if [ -d #{current_path}/ ]; then
|
9
|
+
chcon -R -t httpd_sys_content_t #{current_path}/;
|
10
|
+
fi"
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "install database.yml, and other things "
|
14
|
+
task :local_config do
|
15
|
+
run "cp #{release_path}/config/database.deploy.yml #{release_path}/config/database.yml"
|
16
|
+
case stage
|
17
|
+
when :alpha
|
18
|
+
run "rsync -a #{release_path}/features/ #{release_path}/public/features/"
|
19
|
+
run %Q{ /bin/ls -1 #{release_path}/public/features/ | /bin/awk -v dq='"' 'BEGIN{print "<!DOCTYPE HTML PUBLIC " dq "-//W3C//DTD HTML 4.01//EN" dq "\n" dq "http://www.w3.org/TR/html4/strict.dtd"dq">\n<body><table>"} /feature$/ {print "<tr><td><a href="dq $1 dq ">" $1 "</a></td></tr>"} END{print "</table></body>"}' > #{release_path}/public/features/index.html}
|
20
|
+
end
|
21
|
+
run "mkdir -p #{shared_path}/cache"
|
22
|
+
run "/bin/ln -nsf #{release_path}/../../shared/cache #{release_path}/public/cache"
|
23
|
+
#run "/bin/ln -nsf #{release_path} #{release_path}/../latest"
|
24
|
+
#run "/bin/ln -nsf #{shared_path}/config/database.yml #{release_path}/config/database.yml"
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Write Version file on server"
|
28
|
+
task :write_version_file, :roles => :web do
|
29
|
+
output=%Q{
|
30
|
+
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
31
|
+
"http://www.w3.org/TR/html4/strict.dtd">
|
32
|
+
<body>
|
33
|
+
<p>Release Branch: #{release_number}</p>
|
34
|
+
<p>Release Commit: #{release_commit}</p>
|
35
|
+
<p>Deployed on: #{Time.now.strftime('%m/%d/%Y at %H:%M %Z')}</p>
|
36
|
+
</body>
|
37
|
+
}
|
38
|
+
put(output, "#{current_path}/public/version.html")
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "make some directories we like to have"
|
42
|
+
task :make_shared_dirs do
|
43
|
+
run "mkdir -p #{deploy_to}/shared/system"
|
44
|
+
run "mkdir -p #{deploy_to}/shared/config"
|
45
|
+
run "mkdir -p #{deploy_to}/shared/log/old"
|
46
|
+
run "mkdir -p #{deploy_to}/shared/pids"
|
47
|
+
run "mkdir -p #{deploy_to}/releases"
|
48
|
+
run "mkdir -p '#{shared_path}/config/payment_gateways'"
|
49
|
+
end
|
50
|
+
|
51
|
+
desc "remove old submodules from vendors directory"
|
52
|
+
task :cleanup_vendor do
|
53
|
+
run "cd #{deploy_to}/shared/cached-copy && git clean -dxf vendor"
|
54
|
+
end
|
55
|
+
|
56
|
+
before "deploy:update_code", "deploy:cleanup_vendor"
|
57
|
+
before "deploy:rollback:revision", "deploy:rollback_migrations"
|
58
|
+
|
59
|
+
desc "Rolls back database to migration level of the previously deployed release"
|
60
|
+
task :rollback_migrations, :roles => :db, :only => { :primary => true } do
|
61
|
+
if releases.length < 2
|
62
|
+
abort "could not rollback the code because there is no prior release"
|
63
|
+
else
|
64
|
+
rake = fetch(:rake, "rake")
|
65
|
+
rails_env = fetch(:rails_env, "production")
|
66
|
+
migrate_env = fetch(:migrate_env, "")
|
67
|
+
migrate_target = fetch(:migrate_target, :latest)
|
68
|
+
run "cd #{current_path}; #{rake} RAILS_ENV=#{rails_env} #{migrate_env} db:migrate VERSION=`cd #{File.join(previous_release, 'db', 'migrate')} && ls -1 [0-9]*_*.rb | tail -1 | sed -e s/_.*$//`"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end #namespace deploy
|
72
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
def start_time
|
2
|
+
@begin = Time.now()
|
3
|
+
end
|
4
|
+
|
5
|
+
def end_time
|
6
|
+
if @begin.nil?
|
7
|
+
return nil
|
8
|
+
else
|
9
|
+
return to_minutes(Time.now() - @begin)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
namespace :time do
|
14
|
+
desc "[internal] record the current time for later use"
|
15
|
+
task :begin do
|
16
|
+
start_time
|
17
|
+
end
|
18
|
+
desc "[internal] print the time elapsed since time:begin was executed"
|
19
|
+
task :finish do
|
20
|
+
how_long=end_time
|
21
|
+
if how_long.nil?
|
22
|
+
puts "You must run start_time before you can call end_time"
|
23
|
+
else
|
24
|
+
puts ""
|
25
|
+
puts "deploy took: #{end_time} minutes"
|
26
|
+
puts ""
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
namespace :deploy do
|
2
|
+
namespace :web do
|
3
|
+
desc <<-DESC
|
4
|
+
Present a maintenance page to visitors. Disables your application's web \
|
5
|
+
interface by writing a "maintenance.html" file to each web server. The \
|
6
|
+
servers must be configured to detect the presence of this file, and if \
|
7
|
+
it is present, always display it instead of performing the request.
|
8
|
+
|
9
|
+
By default, the maintenance page will just say the site is down for \
|
10
|
+
"maintenance", and will be back "shortly", but you can customize the \
|
11
|
+
page by specifying the REASON environment variable:
|
12
|
+
|
13
|
+
$ cap deploy:web:disable \\
|
14
|
+
REASON="hardware upgrade"
|
15
|
+
|
16
|
+
Further customization will require that you write your own task.
|
17
|
+
DESC
|
18
|
+
#"/home/projectdx/projectdx-cms/current/public/system/maintenance.html"
|
19
|
+
maint_files=["#{shared_path}/system/maintenance.html",
|
20
|
+
]
|
21
|
+
|
22
|
+
task :disable, :roles => :web, :except => { :no_release => true } do
|
23
|
+
require 'erb'
|
24
|
+
on_rollback { maint_files.each do |file|
|
25
|
+
run "if [ -e #{file} ]; then rm #{file}; fi"
|
26
|
+
end
|
27
|
+
}
|
28
|
+
|
29
|
+
reason = ENV['REASON']
|
30
|
+
|
31
|
+
template = File.read("public/maintenance.rhtml")
|
32
|
+
result = ERB.new(template).result(binding)
|
33
|
+
maint_files.each do |file|
|
34
|
+
dir=File.dirname(file)
|
35
|
+
put result, "/tmp/disable_cap", :mode => 0644
|
36
|
+
run "if [ -d #{dir} -a \! -e #{file} ]; then mv /tmp/disable_cap #{file}; fi"
|
37
|
+
run "chcon -t httpd_sys_content_t #{file}; true" # we ignore this since some hosts have home on nfs
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
desc <<-DESC
|
42
|
+
Makes the application web-accessible again. Removes the \
|
43
|
+
"maintenance.html" page generated by deploy:web:disable, which (if your \
|
44
|
+
web servers are configured correctly) will make your application \
|
45
|
+
web-accessible again.
|
46
|
+
DESC
|
47
|
+
task :enable, :roles => :web, :except => { :no_release => true } do
|
48
|
+
maint_files.each do |file|
|
49
|
+
run "if [ -e #{file} ]; then rm #{file}; fi"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'capistrano'
|
2
|
+
Capistrano::Configuration.instance.load do
|
3
|
+
load_paths << File.dirname(__FILE__)+'/projectdx'
|
4
|
+
def to_minutes(seconds)
|
5
|
+
m = (seconds/60).floor
|
6
|
+
s = (seconds - (m * 60)).round
|
7
|
+
# add leading zero to one-digit minute
|
8
|
+
if m < 10
|
9
|
+
m = "0#{m}"
|
10
|
+
end
|
11
|
+
# add leading zero to one-digit second
|
12
|
+
if s < 10
|
13
|
+
s = "0#{s}"
|
14
|
+
end
|
15
|
+
# return formatted time
|
16
|
+
return "#{m}:#{s}"
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: capistrano-ext-projectdx
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Darrell Fuhriman
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-06-16 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Local extensions to capistrano, which others may find useful
|
23
|
+
email:
|
24
|
+
- darrell@renewfund.com
|
25
|
+
executables: []
|
26
|
+
|
27
|
+
extensions: []
|
28
|
+
|
29
|
+
extra_rdoc_files: []
|
30
|
+
|
31
|
+
files:
|
32
|
+
- lib/capistrano/ext/projectdx/all.rb
|
33
|
+
- lib/capistrano/ext/projectdx/cache.rb
|
34
|
+
- lib/capistrano/ext/projectdx/campfire.rb
|
35
|
+
- lib/capistrano/ext/projectdx/docs.rb
|
36
|
+
- lib/capistrano/ext/projectdx/git_branch.rb
|
37
|
+
- lib/capistrano/ext/projectdx/misc.rb
|
38
|
+
- lib/capistrano/ext/projectdx/passenger.rb
|
39
|
+
- lib/capistrano/ext/projectdx/projectdx.rb
|
40
|
+
- lib/capistrano/ext/projectdx/time.rb
|
41
|
+
- lib/capistrano/ext/projectdx/web.rb
|
42
|
+
- lib/capistrano/ext/projectdx.rb
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: http://github.com/projectdx/capistrano-ext-projectdx
|
45
|
+
licenses: []
|
46
|
+
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
hash: 23
|
67
|
+
segments:
|
68
|
+
- 1
|
69
|
+
- 3
|
70
|
+
- 6
|
71
|
+
version: 1.3.6
|
72
|
+
requirements: []
|
73
|
+
|
74
|
+
rubyforge_project: capistrano-ext-projectdx
|
75
|
+
rubygems_version: 1.3.7
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: Local extensions to capistrano, which others may find useful
|
79
|
+
test_files: []
|
80
|
+
|