capistrano-s3 1.2.0 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cb5552bb93390a37dfef42b1c2f04ab86f8c24b2
4
- data.tar.gz: 7e90088960110cc77b870709ab8e1b7cc1d00af0
3
+ metadata.gz: e58eac78f1006adb9c1dc9ee60f4f34443a5a71e
4
+ data.tar.gz: 7214a8ede096b2186a2f8f526172390f81a3790c
5
5
  SHA512:
6
- metadata.gz: 96b33af80859e1be1a7df56b268d6f8f6bf6a9061c16fd006ff4d2d702571bbfaa36803a7bc228db9385d088ac6cacc3b6a3e5dcbd35400467f00da5ac88ec05
7
- data.tar.gz: aaeec8a903a3e4e1c1d44246108217e33b6a80046df824ed12a86b71e90c4ddb84941166b9c1465f37eed448e5c0ad85d6c87e7b9a7e85e18ef95db26884388f
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
@@ -1,3 +1,4 @@
1
1
  *.gem
2
2
  .last_published
3
- Gemfile.lock
3
+ .last_invalidation
4
+ Gemfile.lock
data/.travis.yml CHANGED
@@ -1,3 +1,7 @@
1
+ notifications:
2
+ email:
3
+ on_success: never
4
+ on_failure: change
1
5
  language: ruby
2
6
  dist: trusty
3
7
  bundler_args: --without debug release
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 endpoint
80
+ ### Custom region
81
81
 
82
82
  If your bucket is not in the default US Standard region,
83
- set [endpoint](http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region)
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 :s3_endpoint, 's3-eu-west-1.amazonaws.com'
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.
@@ -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', '~> 1.11'
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 => proc { Dir.pwd.gsub("\n", "") + "/public" },
5
+ :deployment_path => "public",
6
6
  :bucket_write_options => { :acl => :public_read },
7
- :s3_endpoint => "s3.amazonaws.com",
7
+ :region => 'us-east-1',
8
8
  :redirect_options => {},
9
9
  :only_gzip => false,
10
10
  :invalidations => [],
@@ -1,4 +1,4 @@
1
- require 'aws/s3'
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!(s3_endpoint, key, secret, bucket, source, distribution_id, invalidations, exclusions, only_gzip, extra_options)
11
- s3 = self.establish_s3_client_connection!(s3_endpoint, key, secret)
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(source, exclusions).each do |file|
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(source, file)
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!(s3_endpoint, key, secret, bucket)
46
- s3 = self.establish_s3_connection!(s3_endpoint, key, secret)
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, s3_endpoint, key, secret)
72
+ def self.establish_connection!(klass, region, key, secret)
56
73
  # Send logging to STDOUT
57
- AWS.config(:logger => ::Logger.new(STDOUT))
74
+ Aws.config[:logger] = ::Logger.new(STDOUT)
75
+ Aws.config[:log_formatter] = Aws::Log::Formatter.colored
58
76
  klass.new(
59
- :s3_endpoint => s3_endpoint,
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!(AWS::CloudFront::Client, nil, key, secret)
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!(s3_endpoint, key, secret)
70
- self.establish_connection!(AWS::S3::Client, s3_endpoint, key, secret)
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!(s3_endpoint, key, secret)
74
- self.establish_connection!(AWS::S3, s3_endpoint, key, secret)
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
- :bucket_name => bucket,
95
- :key => path,
96
- :data => open(file),
97
- :acl => :public_read,
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]))
@@ -1,5 +1,5 @@
1
1
  module Capistrano
2
2
  module S3
3
- VERSION = "1.2.0"
3
+ VERSION = "2.0.0"
4
4
  end
5
5
  end
@@ -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!(s3_endpoint, access_key_id, secret_access_key, bucket)
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!(s3_endpoint, access_key_id, secret_access_key,
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(:s3_endpoint), fetch(:access_key_id), fetch(:secret_access_key), fetch(:bucket))
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(:s3_endpoint), fetch(:access_key_id), fetch(:secret_access_key),
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
@@ -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
- AWS::S3::Client::V20060301.any_instance.expects(:put_object).times(8)
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
- AWS::S3::Client::V20060301.any_instance.expects(:put_object).times(4)
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
- AWS::S3::Client::V20060301.any_instance.expects(:put_object).times(8)
28
- AWS::CloudFront::Client::V20141106.any_instance.expects(:create_invalidation).once
23
+ Aws::S3::Client.any_instance.expects(:put_object).times(8)
24
+ Aws::CloudFront::Client.any_instance.expects(:create_invalidation).once
29
25
 
30
- path = File.join(@root, 'sample')
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
- AWS::S3::Client::V20060301.any_instance.expects(:put_object).times(8)
36
- AWS::CloudFront::Client::V20141106.any_instance.expects(:create_invalidation).never
30
+ Aws::S3::Client.any_instance.expects(:put_object).times(8)
31
+ Aws::CloudFront::Client.any_instance.expects(:create_invalidation).never
37
32
 
38
- path = File.join(@root, 'sample')
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
- AWS::S3::Client::V20060301.any_instance.expects(:put_object).times(7)
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', path, 'cf123', [], exclude_paths, false, {})
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
- AWS::S3::Client::V20060301.any_instance.expects(:put_object).times(6)
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', path, 'cf123', [], exclude_paths, false, {})
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
- AWS::S3::Client::V20060301.any_instance.expects(:put_object).times(0)
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', path, 'cf123', [], exclude_paths, false, {})
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
@@ -1,8 +1,8 @@
1
1
  require 'capistrano/s3/publisher'
2
2
  require 'mocha/api'
3
3
 
4
- AWS.stub!
4
+ Aws.config[:stub_responses] = true
5
5
 
6
6
  RSpec.configure do |config|
7
7
  config.mock_framework = :mocha
8
- end
8
+ end
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: 1.2.0
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-25 00:00:00.000000000 Z
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: '1.11'
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: '1.11'
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