capistrano-s3 1.2.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.gitignore +2 -1
- data/.travis.yml +4 -0
- data/CHANGELOG.md +6 -0
- data/README.md +24 -3
- data/capistrano-s3.gemspec +1 -1
- data/lib/capistrano/s3/defaults.rb +2 -2
- data/lib/capistrano/s3/publisher.rb +41 -23
- data/lib/capistrano/s3/version.rb +1 -1
- data/lib/capistrano/tasks/capistrano_2.rb +7 -2
- data/lib/capistrano/tasks/capistrano_3.rb +7 -2
- data/spec/publisher_spec.rb +16 -25
- data/spec/spec_helper.rb +2 -2
- metadata +4 -4
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e58eac78f1006adb9c1dc9ee60f4f34443a5a71e
|
4
|
+
data.tar.gz: 7214a8ede096b2186a2f8f526172390f81a3790c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 146e8d2dfa08cd96f99c6ef87bbb07dbe4f2ff05b38804d1a93c373cbf8ef01721c4630a53f9348e23acd2f7d8c04a9d1423a392760fdc3a9bda3f4ff4a8432e
|
7
|
+
data.tar.gz: 420bcb2f854a5e6c7d507a105228082e54848830c089691d19694fbbdd6b614c0e08011e0147c50d43f86abbfbd1e56d9897fe86635f1dbecaa68e63a56fe1a7
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## v2.0.0
|
4
|
+
|
5
|
+
Major change : AWS SDK dependency was upgragred to 2.6, see migration guide at bottom of README to upgrade from v1.
|
6
|
+
Feature : Add wait_for_invalidation task (#32) @exoszajzbuk
|
7
|
+
Improvement : Simpler way to set deployment_path (#33) @j15e
|
8
|
+
|
3
9
|
## v1.2.0
|
4
10
|
|
5
11
|
Feature : Add exclusions (#30) @exoszajzbuk
|
data/README.md
CHANGED
@@ -77,14 +77,14 @@ Add content to your public folder and run deploy command:
|
|
77
77
|
|
78
78
|
## Advanced options
|
79
79
|
|
80
|
-
### Custom
|
80
|
+
### Custom region
|
81
81
|
|
82
82
|
If your bucket is not in the default US Standard region,
|
83
|
-
set [
|
83
|
+
set [region](http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region)
|
84
84
|
with:
|
85
85
|
|
86
86
|
```ruby
|
87
|
-
set :
|
87
|
+
set :region, 'eu-west-1'
|
88
88
|
```
|
89
89
|
|
90
90
|
### Write options
|
@@ -139,6 +139,8 @@ set :distribution_id, "CHANGETHIS"
|
|
139
139
|
set :invalidations, [ "/index.html", "/assets/*" ]
|
140
140
|
```
|
141
141
|
|
142
|
+
If you want to wait until the invalidation batch is completed (e.g. on a CI server), you can run `cap <stage> deploy:s3:wait_for_invalidation`. The command will wait indefinitely until the invalidation is completed.
|
143
|
+
|
142
144
|
### Exclude files and directories
|
143
145
|
|
144
146
|
You can set a list of files or directories to exclude from upload. The path must relative to `deployment_path` and use the `dir/**/*` pattern to exclude directories.
|
@@ -169,6 +171,25 @@ See our boilerplate
|
|
169
171
|
[sinatra-static-bp](https://github.com/hooktstudios/sinatra-static-bp)
|
170
172
|
for an example of the complete setup.
|
171
173
|
|
174
|
+
## Migration guide
|
175
|
+
|
176
|
+
### From `< 2.0.0`
|
177
|
+
|
178
|
+
If you have customized `deployment_path` from 2.0 use a simplified format
|
179
|
+
|
180
|
+
```diff
|
181
|
+
# config/deploy.rb
|
182
|
+
-set :deployment_path, proc { Dir.pwd.gsub('\n', '') + '/build' }
|
183
|
+
+set :deployment_path, 'build'
|
184
|
+
```
|
185
|
+
|
186
|
+
If you have configured `s3_endpoint` to something other than the default switch to new syntax using [region](http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region) identifiers
|
187
|
+
|
188
|
+
```diff
|
189
|
+
-set :s3_endpoint, 's3-eu-west-1.amazonaws.com'
|
190
|
+
+set :region, 'eu-west-1'
|
191
|
+
```
|
192
|
+
|
172
193
|
## Contributing
|
173
194
|
|
174
195
|
See [CONTRIBUTING.md](https://github.com/hooktstudios/capistrano-s3/blob/master/CONTRIBUTING.md) for more details on contributing and running test.
|
data/capistrano-s3.gemspec
CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.required_ruby_version = ">= 2.1"
|
23
23
|
|
24
24
|
# Gem dependencies
|
25
|
-
s.add_runtime_dependency 'aws-sdk', '~>
|
25
|
+
s.add_runtime_dependency 'aws-sdk', '~> 2.6'
|
26
26
|
s.add_runtime_dependency 'capistrano', '>= 2'
|
27
27
|
s.add_runtime_dependency 'mime-types', '~> 1.23'
|
28
28
|
s.add_runtime_dependency 'net-ssh', '~> 2.9'
|
@@ -2,9 +2,9 @@ module Capistrano
|
|
2
2
|
module S3
|
3
3
|
module Defaults
|
4
4
|
DEFAULTS = {
|
5
|
-
:deployment_path =>
|
5
|
+
:deployment_path => "public",
|
6
6
|
:bucket_write_options => { :acl => :public_read },
|
7
|
-
:
|
7
|
+
:region => 'us-east-1',
|
8
8
|
:redirect_options => {},
|
9
9
|
:only_gzip => false,
|
10
10
|
:invalidations => [],
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'aws
|
1
|
+
require 'aws-sdk'
|
2
2
|
require 'mime/types'
|
3
3
|
require 'fileutils'
|
4
4
|
|
@@ -6,17 +6,19 @@ module Capistrano
|
|
6
6
|
module S3
|
7
7
|
module Publisher
|
8
8
|
LAST_PUBLISHED_FILE = '.last_published'
|
9
|
+
LAST_INVALIDATION_FILE = '.last_invalidation'
|
9
10
|
|
10
|
-
def self.publish!(
|
11
|
-
|
11
|
+
def self.publish!(region, key, secret, bucket, deployment_path, distribution_id, invalidations, exclusions, only_gzip, extra_options)
|
12
|
+
deployment_path_absolute = File.expand_path(deployment_path, Dir.pwd)
|
13
|
+
s3 = self.establish_s3_client_connection!(region, key, secret)
|
12
14
|
updated = false
|
13
15
|
|
14
|
-
self.files(
|
16
|
+
self.files(deployment_path_absolute, exclusions).each do |file|
|
15
17
|
if !File.directory?(file)
|
16
18
|
next if self.published?(file)
|
17
19
|
next if only_gzip && self.has_gzipped_version?(file)
|
18
20
|
|
19
|
-
path = self.base_file_path(
|
21
|
+
path = self.base_file_path(deployment_path_absolute, file)
|
20
22
|
path.gsub!(/^\//, "") # Remove preceding slash for S3
|
21
23
|
|
22
24
|
self.put_object(s3, bucket, path, file, only_gzip, extra_options)
|
@@ -25,9 +27,9 @@ module Capistrano
|
|
25
27
|
|
26
28
|
# invalidate CloudFront distribution if needed
|
27
29
|
if distribution_id && !invalidations.empty?
|
28
|
-
cf = self.establish_cf_client_connection!(key, secret)
|
30
|
+
cf = self.establish_cf_client_connection!(region, key, secret)
|
29
31
|
|
30
|
-
cf.create_invalidation({
|
32
|
+
response = cf.create_invalidation({
|
31
33
|
:distribution_id => distribution_id,
|
32
34
|
:invalidation_batch => {
|
33
35
|
:paths => {
|
@@ -37,41 +39,57 @@ module Capistrano
|
|
37
39
|
:caller_reference => SecureRandom.hex
|
38
40
|
}
|
39
41
|
})
|
42
|
+
|
43
|
+
if response && response.successful?
|
44
|
+
File.open(LAST_INVALIDATION_FILE, 'w') { |file| file.write(response[:invalidation][:id]) }
|
45
|
+
end
|
40
46
|
end
|
41
47
|
|
42
48
|
FileUtils.touch(LAST_PUBLISHED_FILE)
|
43
49
|
end
|
44
50
|
|
45
|
-
def self.clear!(
|
46
|
-
s3 = self.establish_s3_connection!(
|
51
|
+
def self.clear!(region, key, secret, bucket)
|
52
|
+
s3 = self.establish_s3_connection!(region, key, secret)
|
47
53
|
s3.buckets[bucket].clear!
|
48
54
|
|
49
55
|
FileUtils.rm(LAST_PUBLISHED_FILE)
|
56
|
+
FileUtils.rm(LAST_INVALIDATION_FILE)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.check_invalidation(region, key, secret, distribution_id)
|
60
|
+
last_invalidation_id = File.read(LAST_INVALIDATION_FILE).strip
|
61
|
+
|
62
|
+
cf = self.establish_cf_client_connection!(region, key, secret)
|
63
|
+
cf.wait_until(:invalidation_completed, distribution_id: distribution_id, id: last_invalidation_id) do |w|
|
64
|
+
w.max_attempts = nil
|
65
|
+
w.delay = 30
|
66
|
+
end
|
50
67
|
end
|
51
68
|
|
52
69
|
private
|
53
70
|
|
54
71
|
# Establishes the connection to Amazon S3
|
55
|
-
def self.establish_connection!(klass,
|
72
|
+
def self.establish_connection!(klass, region, key, secret)
|
56
73
|
# Send logging to STDOUT
|
57
|
-
|
74
|
+
Aws.config[:logger] = ::Logger.new(STDOUT)
|
75
|
+
Aws.config[:log_formatter] = Aws::Log::Formatter.colored
|
58
76
|
klass.new(
|
59
|
-
:
|
77
|
+
:region => region,
|
60
78
|
:access_key_id => key,
|
61
79
|
:secret_access_key => secret
|
62
80
|
)
|
63
81
|
end
|
64
82
|
|
65
|
-
def self.establish_cf_client_connection!(key, secret)
|
66
|
-
self.establish_connection!(
|
83
|
+
def self.establish_cf_client_connection!(region, key, secret)
|
84
|
+
self.establish_connection!(Aws::CloudFront::Client, region, key, secret)
|
67
85
|
end
|
68
86
|
|
69
|
-
def self.establish_s3_client_connection!(
|
70
|
-
self.establish_connection!(
|
87
|
+
def self.establish_s3_client_connection!(region, key, secret)
|
88
|
+
self.establish_connection!(Aws::S3::Client, region, key, secret)
|
71
89
|
end
|
72
90
|
|
73
|
-
def self.establish_s3_connection!(
|
74
|
-
self.establish_connection!(
|
91
|
+
def self.establish_s3_connection!(region, key, secret)
|
92
|
+
self.establish_connection!(Aws::S3, region, key, secret)
|
75
93
|
end
|
76
94
|
|
77
95
|
def self.base_file_path(root, file)
|
@@ -79,7 +97,7 @@ module Capistrano
|
|
79
97
|
end
|
80
98
|
|
81
99
|
def self.files(deployment_path, exclusions)
|
82
|
-
Dir.glob("#{deployment_path}/**/*") - Dir.glob(exclusions.map{ |e| "#{deployment_path}/#{e}" })
|
100
|
+
Dir.glob("#{deployment_path}/**/*") - Dir.glob(exclusions.map { |e| "#{deployment_path}/#{e}" })
|
83
101
|
end
|
84
102
|
|
85
103
|
def self.published?(file)
|
@@ -91,10 +109,10 @@ module Capistrano
|
|
91
109
|
base_name = File.basename(file)
|
92
110
|
mime_type = mime_type_for_file(base_name)
|
93
111
|
options = {
|
94
|
-
:
|
95
|
-
:key
|
96
|
-
:
|
97
|
-
:acl
|
112
|
+
:bucket => bucket,
|
113
|
+
:key => path,
|
114
|
+
:body => open(file),
|
115
|
+
:acl => :public_read,
|
98
116
|
}
|
99
117
|
|
100
118
|
options.merge!(build_redirect_hash(path, extra_options[:redirect]))
|
@@ -11,13 +11,18 @@ module Capistrano
|
|
11
11
|
namespace :s3 do
|
12
12
|
desc "Empties bucket of all files. Caution when using this command, as it cannot be undone!"
|
13
13
|
task :empty do
|
14
|
-
S3::Publisher.clear!(
|
14
|
+
S3::Publisher.clear!(region, access_key_id, secret_access_key, bucket)
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Waits until the last CloudFront invalidation batch is completed"
|
18
|
+
task :wait_for_invalidation do
|
19
|
+
S3::Publisher.check_invalidation(region, access_key_id, secret_access_key, distribution_id)
|
15
20
|
end
|
16
21
|
|
17
22
|
desc "Upload files to the bucket in the current state"
|
18
23
|
task :upload_files do
|
19
24
|
extra_options = { :write => bucket_write_options, :redirect => redirect_options }
|
20
|
-
S3::Publisher.publish!(
|
25
|
+
S3::Publisher.publish!(region, access_key_id, secret_access_key,
|
21
26
|
bucket, deployment_path, distribution_id, invalidations, exclusions, only_gzip, extra_options)
|
22
27
|
end
|
23
28
|
end
|
@@ -8,13 +8,18 @@ namespace :deploy do
|
|
8
8
|
namespace :s3 do
|
9
9
|
desc "Empties bucket of all files. Caution when using this command, as it cannot be undone!"
|
10
10
|
task :empty do
|
11
|
-
Capistrano::S3::Publisher.clear!(fetch(:
|
11
|
+
Capistrano::S3::Publisher.clear!(fetch(:region), fetch(:access_key_id), fetch(:secret_access_key), fetch(:bucket))
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Waits until the last CloudFront invalidation batch is completed"
|
15
|
+
task :wait_for_invalidation do
|
16
|
+
Capistrano::S3::Publisher.check_invalidation(fetch(:region), fetch(:access_key_id), fetch(:secret_access_key), fetch(:distribution_id))
|
12
17
|
end
|
13
18
|
|
14
19
|
desc "Upload files to the bucket in the current state"
|
15
20
|
task :upload_files do
|
16
21
|
extra_options = { :write => fetch(:bucket_write_options), :redirect => fetch(:redirect_options) }
|
17
|
-
Capistrano::S3::Publisher.publish!(fetch(:
|
22
|
+
Capistrano::S3::Publisher.publish!(fetch(:region), fetch(:access_key_id), fetch(:secret_access_key),
|
18
23
|
fetch(:bucket), fetch(:deployment_path), fetch(:distribution_id), fetch(:invalidations), fetch(:exclusions), fetch(:only_gzip), extra_options)
|
19
24
|
end
|
20
25
|
end
|
data/spec/publisher_spec.rb
CHANGED
@@ -9,60 +9,51 @@ describe Capistrano::S3::Publisher do
|
|
9
9
|
|
10
10
|
context "on publish!" do
|
11
11
|
it "publish all files" do
|
12
|
-
|
13
|
-
|
14
|
-
path = File.join(@root, 'sample')
|
15
|
-
Capistrano::S3::Publisher.publish!('s3.amazonaws.com', 'abc', '123', 'mybucket.amazonaws.com', path, 'cf123', [], [], false, {})
|
12
|
+
Aws::S3::Client.any_instance.expects(:put_object).times(8)
|
13
|
+
Capistrano::S3::Publisher.publish!('s3.amazonaws.com', 'abc', '123', 'mybucket.amazonaws.com', './spec/sample', 'cf123', [], [], false, {})
|
16
14
|
end
|
17
15
|
|
18
16
|
it "publish only gzip files when option is enabled" do
|
19
|
-
|
20
|
-
|
21
|
-
path = File.join(@root, 'sample')
|
22
|
-
Capistrano::S3::Publisher.publish!('s3.amazonaws.com', 'abc', '123', 'mybucket.amazonaws.com', path, 'cf123', [], [], true, {})
|
17
|
+
Aws::S3::Client.any_instance.expects(:put_object).times(4)
|
18
|
+
Capistrano::S3::Publisher.publish!('s3.amazonaws.com', 'abc', '123', 'mybucket.amazonaws.com', 'spec/sample', 'cf123', [], [], true, {})
|
23
19
|
end
|
24
20
|
|
25
21
|
context "invalidations" do
|
26
22
|
it "publish all files with invalidations" do
|
27
|
-
|
28
|
-
|
23
|
+
Aws::S3::Client.any_instance.expects(:put_object).times(8)
|
24
|
+
Aws::CloudFront::Client.any_instance.expects(:create_invalidation).once
|
29
25
|
|
30
|
-
|
31
|
-
Capistrano::S3::Publisher.publish!('s3.amazonaws.com', 'abc', '123', 'mybucket.amazonaws.com', path, 'cf123', ['*'], [], false, {})
|
26
|
+
Capistrano::S3::Publisher.publish!('s3.amazonaws.com', 'abc', '123', 'mybucket.amazonaws.com', 'spec/sample/', 'cf123', ['*'], [], false, {})
|
32
27
|
end
|
33
28
|
|
34
29
|
it "publish all files without invalidations" do
|
35
|
-
|
36
|
-
|
30
|
+
Aws::S3::Client.any_instance.expects(:put_object).times(8)
|
31
|
+
Aws::CloudFront::Client.any_instance.expects(:create_invalidation).never
|
37
32
|
|
38
|
-
|
39
|
-
Capistrano::S3::Publisher.publish!('s3.amazonaws.com', 'abc', '123', 'mybucket.amazonaws.com', path, 'cf123', [], [], false, {})
|
33
|
+
Capistrano::S3::Publisher.publish!('s3.amazonaws.com', 'abc', '123', 'mybucket.amazonaws.com', './spec/sample/', 'cf123', [], [], false, {})
|
40
34
|
end
|
41
35
|
end
|
42
36
|
|
43
37
|
context "exclusions" do
|
44
38
|
it "exclude one files" do
|
45
|
-
|
39
|
+
Aws::S3::Client.any_instance.expects(:put_object).times(7)
|
46
40
|
|
47
|
-
path = File.join(@root, 'sample')
|
48
41
|
exclude_paths = ['fonts/cantarell-regular-webfont.svg']
|
49
|
-
Capistrano::S3::Publisher.publish!('s3.amazonaws.com', 'abc', '123', 'mybucket.amazonaws.com',
|
42
|
+
Capistrano::S3::Publisher.publish!('s3.amazonaws.com', 'abc', '123', 'mybucket.amazonaws.com', 'spec/sample', 'cf123', [], exclude_paths, false, {})
|
50
43
|
end
|
51
44
|
|
52
45
|
it "exclude multiple files" do
|
53
|
-
|
46
|
+
Aws::S3::Client.any_instance.expects(:put_object).times(6)
|
54
47
|
|
55
|
-
path = File.join(@root, 'sample')
|
56
48
|
exclude_paths = ['fonts/cantarell-regular-webfont.svg', 'fonts/cantarell-regular-webfont.svg.gz']
|
57
|
-
Capistrano::S3::Publisher.publish!('s3.amazonaws.com', 'abc', '123', 'mybucket.amazonaws.com',
|
49
|
+
Capistrano::S3::Publisher.publish!('s3.amazonaws.com', 'abc', '123', 'mybucket.amazonaws.com', 'spec/sample', 'cf123', [], exclude_paths, false, {})
|
58
50
|
end
|
59
51
|
|
60
52
|
it "exclude directory" do
|
61
|
-
|
53
|
+
Aws::S3::Client.any_instance.expects(:put_object).times(0)
|
62
54
|
|
63
|
-
path = File.join(@root, 'sample')
|
64
55
|
exclude_paths = ['fonts/**/*']
|
65
|
-
Capistrano::S3::Publisher.publish!('s3.amazonaws.com', 'abc', '123', 'mybucket.amazonaws.com',
|
56
|
+
Capistrano::S3::Publisher.publish!('s3.amazonaws.com', 'abc', '123', 'mybucket.amazonaws.com', 'spec/sample', 'cf123', [], exclude_paths, false, {})
|
66
57
|
end
|
67
58
|
end
|
68
59
|
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: capistrano-s3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean-Philippe Doyle
|
@@ -36,7 +36,7 @@ cert_chain:
|
|
36
36
|
t/JsZnAlWYkJIees2SFV5X/t34oeMu04yY2u9y2YBqKovR97m5YF7zqgx0JODV0x
|
37
37
|
ytwUJvEjznBnJV4OoDE=
|
38
38
|
-----END CERTIFICATE-----
|
39
|
-
date: 2017-01-
|
39
|
+
date: 2017-01-26 00:00:00.000000000 Z
|
40
40
|
dependencies:
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: aws-sdk
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '2.6'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '2.6'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: capistrano
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
metadata.gz.sig
CHANGED
Binary file
|