capistrano-scale 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,42 @@
1
+ !.gitignore
2
+ *.gem
3
+ *.rbc
4
+ *.sw[a-p]
5
+ *.tmproj
6
+ *.tmproject
7
+ *.un~
8
+ *~
9
+ .DS_Store
10
+ .Spotlight-V100
11
+ .Trashes
12
+ ._*
13
+ .bundle
14
+ .config
15
+ .directory
16
+ .elc
17
+ .redcar
18
+ .yardoc
19
+ /.emacs.desktop
20
+ /.emacs.desktop.lock
21
+ Desktop.ini
22
+ Gemfile.lock
23
+ Icon?
24
+ InstalledFiles
25
+ Session.vim
26
+ Thumbs.db
27
+ \#*\#
28
+ _yardoc
29
+ auto-save-list
30
+ coverage
31
+ doc/
32
+ lib/bundler/man
33
+ pkg
34
+ pkg/*
35
+ rdoc
36
+ spec/reports
37
+ test/tmp
38
+ test/version_tmp
39
+ tmp
40
+ tmtags
41
+ tramp
42
+ .idea
data/.rvmrc ADDED
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # This is an RVM Project .rvmrc file, used to automatically load the ruby
4
+ # development environment upon cd'ing into the directory
5
+
6
+ # First we specify our desired <ruby>[@<gemset>], the @gemset name is optional.
7
+ # Only full ruby name is supported here, for short names use:
8
+ # echo "rvm use jruby" > .rvmrc
9
+ environment_id="ruby-1.9.3-p194@capistrano-scale"
10
+
11
+ # Uncomment the following lines if you want to verify rvm version per project
12
+ # rvmrc_rvm_version="1.10.2" # 1.10.1 seams as a safe start
13
+ # eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || {
14
+ # echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading."
15
+ # return 1
16
+ # }
17
+
18
+ # Uncomment following line if you want options to be set only for given project.
19
+ # PROJECT_JRUBY_OPTS=( --1.9 )
20
+ # The variable PROJECT_JRUBY_OPTS requires the following to be run in shell:
21
+ # chmod +x ${rvm_path}/hooks/after_use_jruby_opts
22
+
23
+ # First we attempt to load the desired environment directly from the environment
24
+ # file. This is very fast and efficient compared to running through the entire
25
+ # CLI and selector. If you want feedback on which environment was used then
26
+ # insert the word 'use' after --create as this triggers verbose mode.
27
+ if [[ -d "${rvm_path:-$HOME/.rvm}/environments"
28
+ && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
29
+ then
30
+ \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
31
+ [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] &&
32
+ \. "${rvm_path:-$HOME/.rvm}/hooks/after_use" || true
33
+ else
34
+ # If the environment file has not yet been created, use the RVM CLI to select.
35
+ rvm --create "$environment_id" || {
36
+ echo "Failed to create RVM environment '${environment_id}'."
37
+ return 1
38
+ }
39
+ fi
40
+
41
+ # If you use an RVM gemset file to install a list of gems (*.gems), you can have
42
+ # it be automatically loaded. Uncomment the following and adjust the filename if
43
+ # necessary.
44
+ #
45
+ # filename=".gems"
46
+ # if [[ -s "$filename" ]]
47
+ # then
48
+ # rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d'
49
+ # fi
50
+
51
+ # If you use bundler, this might be useful to you:
52
+ if [[ -s Gemfile ]] && ! command -v bundle >/dev/null
53
+ then
54
+ printf "%b" "The rubygem 'bundler' is not installed. Installing it now.\n"
55
+ gem install bundler
56
+ fi
57
+ # if [[ -s Gemfile ]] && command -v bundle
58
+ # then
59
+ # bundle install
60
+ # fi
61
+
62
+ if [[ $- == *i* ]] # check for interactive shells
63
+ then
64
+ echo "Using: $(tput setaf 2)$GEM_HOME$(tput sgr0)" # show the user the ruby and gemset they are using in green
65
+ else
66
+ echo "Using: $GEM_HOME" # don't use colors in interactive shells
67
+ fi
68
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Claudio Poli
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # Capistrano::Scale
2
+
3
+ This is a revised implementation of the ideas in Bill Kirtleys `capistrano-s3` and Richie McMahon `capistrano-s3-copy` gem.
4
+
5
+ Don't use it.
6
+
7
+ ### TODO
8
+
9
+ ## Contributing
10
+
11
+ 1. Fork it
12
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
13
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
14
+ 4. Push to the branch (`git push origin my-new-feature`)
15
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ require 'bundler/gem_tasks'
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/capistrano-scale/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = 'capistrano-scale'
6
+ gem.version = CapistranoScale::VERSION.dup
7
+ gem.author = 'Claudio Poli'
8
+ gem.email = 'masterkain@gmail.com'
9
+ gem.homepage = 'https://github.com/masterkain/capistrano-scale'
10
+ gem.summary = %q{Capistrano deployment strategy that transfers the release on S3}
11
+ gem.description = %q{Capistrano deployment strategy that creates and pushes a tarball into S3, for both pushed deployments and pulled auto-scaling.}
12
+
13
+ gem.files = `git ls-files`.split("\n")
14
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f)}
16
+ gem.require_paths = ['lib']
17
+
18
+ gem.add_runtime_dependency 'capistrano', '>= 2.13.3'
19
+ gem.add_runtime_dependency 'fog'
20
+ end
@@ -0,0 +1,97 @@
1
+ #!/bin/bash -ex
2
+
3
+ # Auto-scaling capistrano like deployment script.
4
+
5
+ # Begin S3 Credentials parsing.
6
+ IAM_ROLE=<%= configuration[:aws_ec2_iam_role] %>
7
+ # Begin application configuration
8
+ APPLICATION=<%= configuration[:application] %>
9
+
10
+ AWS_RELEASES_BUCKET=<%= configuration[:aws_releases_bucket] %>
11
+ RAILS_ENV=<%= configuration[:rails_env] %> # e.g. production
12
+ DEPLOY_TO=<%= configuration[:deploy_to] %> # e.g. /home/ubuntu/myapp
13
+ RELEASES_PATH=<%= configuration[:releases_path] %> # e.g. /home/ubuntu/myapp/releases
14
+ RELEASE_PATH=<%= configuration[:release_path] %> # e.g. /home/ubuntu/myapp/releases/20120428210958
15
+ SHARED_PATH=<%= configuration[:shared_path] %> # e.g. /home/ubuntu/myapp/shared
16
+ CURRENT_PATH=<%= configuration[:current_path] %> # e.g. /home/ubuntu/myapp/current
17
+
18
+ PACKAGE_NAME=<%= File.basename(filename) %> # e.g. 20120428210958.tar.gz
19
+ DOWNLOADED_PACKAGE_PATH=<%= remote_filename %> # e.g. /tmp/20120428210958.tar.gz
20
+ DECOMPRESS_CMD="<%= decompress(remote_filename).join(" ") %>" # e.g. tar xfz /tmp/20120428210958.tar.gz
21
+ S3_PACKAGE_PATH=${RAILS_ENV}/${APPLICATION}/${PACKAGE_NAME} # e.g. production/myapp/20120428210958.tar.gz
22
+
23
+ KEEP_RELEASES=<%= configuration[:keep_releases] %>
24
+
25
+ # EC2 IAM Role parsing.
26
+ AWS_CREDENTIALS="`curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${IAM_ROLE}`"
27
+ AWS_ACCESS_KEY_ID="$(ruby -r json -e 'puts JSON.parse(ARGV[0])["AccessKeyId"]' "$AWS_CREDENTIALS")"
28
+ AWS_SECRET_ACCESS_KEY="$(ruby -r json -e 'puts JSON.parse(ARGV[0])["SecretAccessKey"]' "$AWS_CREDENTIALS")"
29
+ AWS_SECRET_TOKEN="$(ruby -r json -e 'puts JSON.parse(ARGV[0])["Token"]' "$AWS_CREDENTIALS")"
30
+
31
+ if [ -z "$AWS_ACCESS_KEY_ID" ]; then
32
+ echo "Expecting the environment variable AWS_ACCESS_KEY_ID to be set"
33
+ exit 1
34
+ fi
35
+
36
+ if [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
37
+ echo "Expecting the environment variable AWS_SECRET_ACCESS_KEY to be set"
38
+ exit 2
39
+ fi
40
+
41
+ if [ -z "$AWS_SECRET_TOKEN" ]; then
42
+ echo "Expecting the environment variable AWS_SECRET_TOKEN to be set"
43
+ exit 2
44
+ fi
45
+
46
+ expires=${6:-$((`date +%s`+60))}
47
+ stringToSign="GET\n\n\n${expires}\nx-amz-security-token:${AWS_SECRET_TOKEN}\n/${AWS_RELEASES_BUCKET}/${S3_PACKAGE_PATH}"
48
+ base64Signature=`echo -en "${stringToSign}" | openssl dgst -sha1 -binary -hmac ${AWS_SECRET_ACCESS_KEY} | openssl base64`
49
+ escapedSignature="$(ruby -r cgi -e 'puts CGI.escape(ARGV[0])' "$base64Signature")"
50
+ escapedAwsKey="$(ruby -r cgi -e 'puts CGI.escape(ARGV[0])' "$AWS_ACCESS_KEY_ID")"
51
+ escapedToken="$(ruby -r cgi -e 'puts CGI.escape(ARGV[0])' "$AWS_SECRET_TOKEN")"
52
+
53
+ URL="http://s3.amazonaws.com/${AWS_RELEASES_BUCKET}/${S3_PACKAGE_PATH}?AWSAccessKeyId=${escapedAwsKey}&Signature=${escapedSignature}&Expires=${expires}&x-amz-security-token=${escapedToken}"
54
+
55
+ mkdir -p $DEPLOY_TO $RELEASES_PATH $SHARED_PATH ${SHARED_PATH}/system ${SHARED_PATH}/log ${SHARED_PATH}/pids
56
+ chmod g+w $DEPLOY_TO $RELEASES_PATH $SHARED_PATH ${SHARED_PATH}/system ${SHARED_PATH}/log ${SHARED_PATH}/pids
57
+
58
+ chmod -R g+w ${DEPLOY_TO}
59
+
60
+ curl -s -o $DOWNLOADED_PACKAGE_PATH --url "$URL"
61
+ cd ${RELEASES_PATH} && ${DECOMPRESS_CMD} && rm ${DOWNLOADED_PACKAGE_PATH}
62
+
63
+ cd ${RELEASE_PATH} && bundle install --gemfile ${RELEASE_PATH}/Gemfile --path ${SHARED_PATH}/bundle --deployment --quiet --without development test
64
+
65
+ chmod -R g+w ${RELEASE_PATH}
66
+ rm -rf ${RELEASE_PATH}/public/system && mkdir -p ${RELEASE_PATH}/public/
67
+ ln -s ${SHARED_PATH}/system ${RELEASE_PATH}/public/system
68
+ rm -rf ${RELEASE_PATH}/log
69
+ ln -s ${SHARED_PATH}/log ${RELEASE_PATH}/log
70
+ rm -rf ${RELEASE_PATH}/tmp/pids && mkdir -p ${RELEASE_PATH}/tmp/
71
+ ln -s ${SHARED_PATH}/pids ${RELEASE_PATH}/tmp/pids
72
+
73
+ rm -f ${CURRENT_PATH} && ln -s ${RELEASE_PATH} ${CURRENT_PATH}
74
+
75
+ cd ${RELEASE_PATH} && rvmsudo bundle exec foreman export upstart /etc/init -f ./Procfile.production -a ${APPLICATION} -u ubuntu -l ${SHARED_PATH}/log
76
+
77
+ sudo start ${APPLICATION} || sudo restart ${APPLICATION}
78
+
79
+ # Cleanup older releases.
80
+ versions=`ls -xt $RELEASES_PATH`
81
+ releases=(${versions// / })
82
+
83
+ releases_count=${#releases[@]}
84
+
85
+ if [ $releases_count -le $KEEP_RELEASES ]
86
+ then
87
+ echo 'no old releases to clean up'
88
+ else
89
+ echo keeping $KEEP_RELEASES of $releases_count deployed releases
90
+ releases=(${releases[@]:0:0} ${releases[@]:($KEEP_RELEASES)})
91
+
92
+ for release in "${releases[@]}"
93
+ do
94
+ path=$releases_path$release
95
+ `rm -rf $path`
96
+ done
97
+ fi
@@ -0,0 +1,121 @@
1
+ require 'capistrano/recipes/deploy/strategy/copy'
2
+ require 'erb'
3
+ require 'fog'
4
+
5
+ module Capistrano
6
+ module Deploy
7
+ module Strategy
8
+ class ScaleCopy < Copy
9
+
10
+ def initialize(config={})
11
+ super(config)
12
+
13
+ # Check configuration keys and raise error if something is missing.
14
+ %w(aws_access_key_id aws_secret_access_key aws_releases_bucket aws_install_script aws_ec2_iam_role).each do |var|
15
+ value = configuration[var.to_sym]
16
+ if value.nil?
17
+ raise(Capistrano::Error, "Missing configuration[:#{var}] setting")
18
+ end
19
+ end
20
+ # Build up variables needed in the later execution.
21
+ @aws_credentials = {
22
+ :aws_access_key_id => configuration[:aws_access_key_id],
23
+ :aws_secret_access_key => configuration[:aws_secret_access_key]
24
+ }
25
+ @bucket_name = configuration[:aws_releases_bucket]
26
+ @aws_shell_environment = @aws_credentials.collect{ |k,v| "#{k.upcase}=#{v}" }.join(' ')
27
+ @aws_connection = Fog::Storage::AWS.new(aws_credentials)
28
+ @aws_directory = @aws_connection.directories.create(
29
+ :key => bucket_name,
30
+ :public => false
31
+ )
32
+ end
33
+
34
+ # Check if curl is installed on the remote server.
35
+ def check!
36
+ super.check do |d|
37
+ d.remote.command("curl")
38
+ end
39
+ end
40
+
41
+ # Distributes the file to the remote servers.
42
+ def distribute!
43
+ package_path = filename
44
+ package_name = File.basename(package_path)
45
+
46
+ package_key = "#{rails_env}/#{application}/#{package_name}"
47
+
48
+ file = aws_directory.files.new(
49
+ :key => package_key,
50
+ :body => File.open(package_path),
51
+ :public => false,
52
+ :encryption => 'AES256'
53
+ )
54
+
55
+ logger.debug "Copying the package on S3: #{package_key}"
56
+ if configuration.dry_run
57
+ logger.debug file.inspect
58
+ else
59
+ begin
60
+ file.save
61
+ rescue => e
62
+ raise(Capistrano::Error, "S3 File upload failed: #{e.class.to_s}:#{e.message}")
63
+ end
64
+ end
65
+ logger.debug "Package copied."
66
+
67
+ expiring_url = file.url(Time.now + 600)
68
+
69
+ logger.debug "Fetching the release archive on the server"
70
+ run "curl -s -L -o #{remote_filename} --url '#{expiring_url}'"
71
+ logger.debug "Decompressing the release archive on the server"
72
+ run "cd #{configuration[:releases_path]} && #{decompress(remote_filename).join(" ")} && rm #{remote_filename}"
73
+ logger.debug "Release uncompressed, ready for hooks"
74
+
75
+ logger.debug "Creating instance initialization script locally"
76
+
77
+ template_text = File.read(configuration[:aws_install_script])
78
+ template_text = template_text.gsub("\r\n?", "\n")
79
+ template = ERB.new(template_text, nil, '<>-')
80
+ output = template.result(self.binding)
81
+
82
+ local_output_file = File.join(copy_dir, "#{rails_env}_aws_install.sh")
83
+
84
+ File.open(local_output_file, "w") do |f|
85
+ f.write(output)
86
+ end
87
+
88
+ logger.debug "Script created at: #{local_output_file}"
89
+
90
+ # Will be picked up by an internal Capistrano hook after a deploy has finished
91
+ # to put this manifest on S3.
92
+ configuration[:s3_install_cmd_path] = local_output_file
93
+ end
94
+
95
+ def binding
96
+ super
97
+ end
98
+
99
+ def aws_credentials
100
+ @aws_credentials
101
+ end
102
+
103
+ def aws_shell_environment
104
+ @aws_shell_environment
105
+ end
106
+
107
+ def bucket_name
108
+ @bucket_name
109
+ end
110
+
111
+ def aws_connection
112
+ @aws_connection
113
+ end
114
+
115
+ def aws_directory
116
+ @aws_directory
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,44 @@
1
+ require 'capistrano'
2
+ require 'capistrano/version'
3
+
4
+ module CapistranoScale
5
+ class CapistranoIntegration
6
+ def self.load_into(capistrano_config)
7
+ capistrano_config.load do
8
+ namespace :scale_copy do
9
+
10
+ desc "Internal hook that updates the aws_install.sh script to latest if the deploy completed"
11
+ task :store_aws_install_script_on_success do
12
+ install_cmd_path = fetch(:s3_install_cmd_path)
13
+
14
+ if install_cmd_path
15
+ aws_credentials = {
16
+ :aws_access_key_id => capistrano_config[:aws_access_key_id],
17
+ :aws_secret_access_key => capistrano_config[:aws_secret_access_key]
18
+ }
19
+ aws_connection = Fog::Storage::AWS.new(aws_credentials)
20
+ aws_directory = aws_connection.directories.create(
21
+ :key => capistrano_config[:aws_releases_bucket],
22
+ :public => false
23
+ )
24
+ logger.debug "Uploading initialization script to S3"
25
+ file = aws_directory.files.create(
26
+ :key => "#{rails_env}/#{application}/aws_install.sh",
27
+ :body => File.open(install_cmd_path),
28
+ :acl => 'public-read',
29
+ :encryption => 'AES256'
30
+ )
31
+ logger.debug "AWS Install script uploaded."
32
+ end
33
+ end
34
+ end
35
+
36
+ after 'deploy', 'scale_copy:store_aws_install_script_on_success'
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ if Capistrano::Configuration.instance
43
+ CapistranoScale::CapistranoIntegration.load_into(Capistrano::Configuration.instance)
44
+ end
@@ -0,0 +1,5 @@
1
+ module CapistranoScale
2
+ unless defined?(::CapistranoScale::VERSION)
3
+ VERSION = "0.0.2".freeze
4
+ end
5
+ end
@@ -0,0 +1,2 @@
1
+ require 'capistrano-scale/version'
2
+ require 'capistrano-scale/capistrano_integration'
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano-scale
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Claudio Poli
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: capistrano
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 2.13.3
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 2.13.3
30
+ - !ruby/object:Gem::Dependency
31
+ name: fog
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Capistrano deployment strategy that creates and pushes a tarball into
47
+ S3, for both pushed deployments and pulled auto-scaling.
48
+ email: masterkain@gmail.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - .rvmrc
55
+ - Gemfile
56
+ - LICENSE
57
+ - README.md
58
+ - Rakefile
59
+ - capistrano-scale.gemspec
60
+ - examples/aws_install.sh.erb
61
+ - lib/capistrano-scale.rb
62
+ - lib/capistrano-scale/capistrano_integration.rb
63
+ - lib/capistrano-scale/version.rb
64
+ - lib/capistrano/recipes/deploy/strategy/scale_copy.rb
65
+ homepage: https://github.com/masterkain/capistrano-scale
66
+ licenses: []
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ requirements: []
84
+ rubyforge_project:
85
+ rubygems_version: 1.8.24
86
+ signing_key:
87
+ specification_version: 3
88
+ summary: Capistrano deployment strategy that transfers the release on S3
89
+ test_files: []