capistrano-s3 2.4.0 → 3.0.0.pre2

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.
@@ -1,107 +1,111 @@
1
- require 'aws-sdk'
2
- require 'mime/types'
3
- require 'fileutils'
4
- require 'capistrano/s3/mime_types'
1
+ # frozen_string_literal: true
2
+
3
+ require "aws-sdk"
4
+ require "mime/types"
5
+ require "fileutils"
6
+ require "capistrano/s3/mime_types"
7
+ require "yaml"
5
8
 
6
9
  module Capistrano
7
10
  module S3
8
11
  module Publisher
9
- LAST_PUBLISHED_FILE = '.last_published'
10
- LAST_INVALIDATION_FILE = '.last_invalidation'
12
+ LAST_PUBLISHED_FILE = ".last_published"
13
+ LAST_INVALIDATION_FILE = ".last_invalidation"
11
14
 
12
- def self.publish!(region, key, secret, bucket, deployment_path, target_path, distribution_id, invalidations, exclusions, only_gzip, extra_options, stage = 'default')
13
- deployment_path_absolute = File.expand_path(deployment_path, Dir.pwd)
14
- s3 = self.establish_s3_client_connection!(region, key, secret)
15
- updated = false
15
+ class << self
16
+ def publish!(region, key, secret, bucket, deployment_path, target_path, distribution_id,
17
+ invalidations, exclusions, only_gzip, extra_options, stage = "default")
18
+ deployment_path_absolute = File.expand_path(deployment_path, Dir.pwd)
19
+ s3_client = establish_s3_client_connection!(region, key, secret)
16
20
 
17
- self.files(deployment_path_absolute, exclusions).each do |file|
18
- if !File.directory?(file)
19
- next if self.published?(file, bucket, stage)
20
- next if only_gzip && self.has_gzipped_version?(file)
21
+ files(deployment_path_absolute, exclusions).each do |file|
22
+ next if File.directory?(file)
23
+ next if published?(file, bucket, stage)
24
+ next if only_gzip && gzipped_version?(file)
21
25
 
22
- path = self.base_file_path(deployment_path_absolute, file)
23
- path.gsub!(/^\//, "") # Remove preceding slash for S3
26
+ path = base_file_path(deployment_path_absolute, file)
27
+ path.gsub!(%r{^/}, "") # Remove preceding slash for S3
24
28
 
25
- self.put_object(s3, bucket, target_path, path, file, only_gzip, extra_options)
29
+ put_object(s3_client, bucket, target_path, path, file, only_gzip, extra_options)
26
30
  end
27
- end
28
31
 
29
- # invalidate CloudFront distribution if needed
30
- if distribution_id && !invalidations.empty?
31
- cf = self.establish_cf_client_connection!(region, key, secret)
32
-
33
- response = cf.create_invalidation({
34
- :distribution_id => distribution_id,
35
- :invalidation_batch => {
36
- :paths => {
37
- :quantity => invalidations.count,
38
- :items => invalidations.map do |path|
39
- File.join('/', self.add_prefix(path, prefix: target_path))
40
- end
41
- },
42
- :caller_reference => SecureRandom.hex
43
- }
44
- })
45
-
46
- if response && response.successful?
47
- File.open(LAST_INVALIDATION_FILE, 'w') { |file| file.write(response[:invalidation][:id]) }
32
+ # invalidate CloudFront distribution if needed
33
+ if distribution_id && !invalidations.empty?
34
+ cf = establish_cf_client_connection!(region, key, secret)
35
+
36
+ response = cf.create_invalidation(
37
+ distribution_id: distribution_id,
38
+ invalidation_batch: {
39
+ paths: {
40
+ quantity: invalidations.count,
41
+ items: invalidations.map do |path|
42
+ File.join("/", add_prefix(path, prefix: target_path))
43
+ end
44
+ },
45
+ caller_reference: SecureRandom.hex
46
+ }
47
+ )
48
+
49
+ if response&.successful?
50
+ File.write(LAST_INVALIDATION_FILE, response[:invalidation][:id])
51
+ end
48
52
  end
49
- end
50
53
 
51
- self.published_to!(bucket, stage)
52
- end
54
+ published_to!(bucket, stage)
55
+ end
53
56
 
54
- def self.clear!(region, key, secret, bucket, stage = 'default')
55
- s3 = self.establish_s3_connection!(region, key, secret)
56
- s3.buckets[bucket].clear!
57
+ def clear!(region, key, secret, bucket, stage = "default")
58
+ s3 = establish_s3_connection!(region, key, secret)
59
+ s3.buckets[bucket].clear!
57
60
 
58
- self.clear_published!(bucket, stage)
59
- FileUtils.rm(LAST_INVALIDATION_FILE)
60
- end
61
+ clear_published!(bucket, stage)
62
+ FileUtils.rm(LAST_INVALIDATION_FILE)
63
+ end
61
64
 
62
- def self.check_invalidation(region, key, secret, distribution_id, stage = 'default')
63
- last_invalidation_id = File.read(LAST_INVALIDATION_FILE).strip
65
+ def check_invalidation(region, key, secret, distribution_id, _stage = "default")
66
+ last_invalidation_id = File.read(LAST_INVALIDATION_FILE).strip
64
67
 
65
- cf = self.establish_cf_client_connection!(region, key, secret)
66
- cf.wait_until(:invalidation_completed, distribution_id: distribution_id, id: last_invalidation_id) do |w|
67
- w.max_attempts = nil
68
- w.delay = 30
68
+ cf = establish_cf_client_connection!(region, key, secret)
69
+ cf.wait_until(:invalidation_completed, distribution_id: distribution_id,
70
+ id: last_invalidation_id) do |w|
71
+ w.max_attempts = nil
72
+ w.delay = 30
73
+ end
69
74
  end
70
- end
71
75
 
72
- private
76
+ private
73
77
 
74
78
  # Establishes the connection to Amazon S3
75
- def self.establish_connection!(klass, region, key, secret)
79
+ def establish_connection!(klass, region, key, secret)
76
80
  # Send logging to STDOUT
77
81
  Aws.config[:logger] = ::Logger.new(STDOUT)
78
82
  Aws.config[:log_formatter] = Aws::Log::Formatter.colored
79
83
  klass.new(
80
- :region => region,
81
- :access_key_id => key,
82
- :secret_access_key => secret
84
+ region: region,
85
+ access_key_id: key,
86
+ secret_access_key: secret
83
87
  )
84
88
  end
85
89
 
86
- def self.establish_cf_client_connection!(region, key, secret)
87
- self.establish_connection!(Aws::CloudFront::Client, region, key, secret)
90
+ def establish_cf_client_connection!(region, key, secret)
91
+ establish_connection!(Aws::CloudFront::Client, region, key, secret)
88
92
  end
89
93
 
90
- def self.establish_s3_client_connection!(region, key, secret)
91
- self.establish_connection!(Aws::S3::Client, region, key, secret)
94
+ def establish_s3_client_connection!(region, key, secret)
95
+ establish_connection!(Aws::S3::Client, region, key, secret)
92
96
  end
93
97
 
94
- def self.establish_s3_connection!(region, key, secret)
95
- self.establish_connection!(Aws::S3, region, key, secret)
98
+ def establish_s3_connection!(region, key, secret)
99
+ establish_connection!(Aws::S3, region, key, secret)
96
100
  end
97
101
 
98
- def self.base_file_path(root, file)
102
+ def base_file_path(root, file)
99
103
  file.gsub(root, "")
100
104
  end
101
105
 
102
- def self.files(deployment_path, exclusions)
106
+ def files(deployment_path, exclusions)
103
107
  globbed_paths = Dir.glob(
104
- File.join(deployment_path, '**', '*'),
108
+ File.join(deployment_path, "**", "*"),
105
109
  File::FNM_DOTMATCH # Else Unix-like hidden files will be ignored
106
110
  )
107
111
 
@@ -112,41 +116,42 @@ module Capistrano
112
116
  globbed_paths - excluded_paths
113
117
  end
114
118
 
115
- def self.last_published
116
- if File.exists? LAST_PUBLISHED_FILE
119
+ def last_published
120
+ if File.exist? LAST_PUBLISHED_FILE
117
121
  YAML.load_file(LAST_PUBLISHED_FILE) || {}
118
122
  else
119
123
  {}
120
124
  end
121
125
  end
122
126
 
123
- def self.published_to!(bucket, stage)
124
- current_publish = self.last_published
127
+ def published_to!(bucket, stage)
128
+ current_publish = last_published
125
129
  current_publish["#{bucket}::#{stage}"] = Time.now.iso8601
126
130
  File.write(LAST_PUBLISHED_FILE, current_publish.to_yaml)
127
131
  end
128
132
 
129
- def self.clear_published!(bucket, stage)
130
- current_publish = self.last_published
133
+ def clear_published!(bucket, stage)
134
+ current_publish = last_published
131
135
  current_publish["#{bucket}::#{stage}"] = nil
132
136
  File.write(LAST_PUBLISHED_FILE, current_publish.to_yaml)
133
137
  end
134
138
 
135
- def self.published?(file, bucket, stage)
136
- return false unless last_publish_time = self.last_published["#{bucket}::#{stage}"]
139
+ def published?(file, bucket, stage)
140
+ return false unless (last_publish_time = last_published["#{bucket}::#{stage}"])
141
+
137
142
  File.mtime(file) < Time.parse(last_publish_time)
138
143
  end
139
144
 
140
- def self.put_object(s3, bucket, target_path, path, file, only_gzip, extra_options)
145
+ def put_object(s3_client, bucket, target_path, path, file, only_gzip, extra_options)
141
146
  prefer_cf_mime_types = extra_options[:prefer_cf_mime_types] || false
142
147
 
143
148
  base_name = File.basename(file)
144
149
  mime_type = mime_type_for_file(base_name, prefer_cf_mime_types)
145
150
  options = {
146
- :bucket => bucket,
147
- :key => self.add_prefix(path, prefix: target_path),
148
- :body => open(file),
149
- :acl => 'public-read',
151
+ bucket: bucket,
152
+ key: add_prefix(path, prefix: target_path),
153
+ body: File.read(file),
154
+ acl: "public-read"
150
155
  }
151
156
 
152
157
  options.merge!(build_redirect_hash(path, extra_options[:redirect]))
@@ -154,9 +159,7 @@ module Capistrano
154
159
 
155
160
  object_write_options = extra_options[:object_write] || {}
156
161
  object_write_options.each do |pattern, object_options|
157
- if File.fnmatch(pattern, options[:key])
158
- options.merge!(object_options)
159
- end
162
+ options.merge!(object_options) if File.fnmatch(pattern, options[:key])
160
163
  end
161
164
 
162
165
  if mime_type
@@ -167,69 +170,68 @@ module Capistrano
167
170
  options.merge!(build_gzip_content_type_hash(file, mime_type, prefer_cf_mime_types))
168
171
 
169
172
  # upload as original file name
170
- options.merge!(key: self.add_prefix(self.orig_name(path), prefix: target_path)) if only_gzip
173
+ options[:key] = add_prefix(orig_name(path), prefix: target_path) if only_gzip
171
174
  end
172
175
  end
173
176
 
174
- s3.put_object(options)
177
+ s3_client.put_object(options)
175
178
  end
176
179
 
177
- def self.build_redirect_hash(path, redirect_options)
180
+ def build_redirect_hash(path, redirect_options)
178
181
  return {} unless redirect_options && redirect_options[path]
179
182
 
180
- { :website_redirect_location => redirect_options[path] }
183
+ { website_redirect_location: redirect_options[path] }
181
184
  end
182
185
 
183
- def self.build_content_type_hash(mime_type)
184
- { :content_type => mime_type.content_type }
186
+ def build_content_type_hash(mime_type)
187
+ { content_type: mime_type.content_type }
185
188
  end
186
189
 
187
- def self.build_gzip_content_encoding_hash
188
- { :content_encoding => "gzip" }
190
+ def build_gzip_content_encoding_hash
191
+ { content_encoding: "gzip" }
189
192
  end
190
193
 
191
- def self.has_gzipped_version?(file)
192
- File.exist?(self.gzip_name(file))
194
+ def gzipped_version?(file)
195
+ File.exist?(gzip_name(file))
193
196
  end
194
197
 
195
- def self.build_gzip_content_type_hash(file, mime_type, prefer_cf_mime_types)
196
- orig_name = self.orig_name(file)
198
+ def build_gzip_content_type_hash(file, _mime_type, prefer_cf_mime_types)
199
+ orig_name = orig_name(file)
197
200
  orig_mime = mime_type_for_file(orig_name, prefer_cf_mime_types)
198
201
 
199
202
  return {} unless orig_mime && File.exist?(orig_name)
200
203
 
201
- { :content_type => orig_mime.content_type }
204
+ { content_type: orig_mime.content_type }
202
205
  end
203
206
 
204
- def self.mime_type_for_file(file, prefer_cf_mime_types)
207
+ def mime_type_for_file(file, prefer_cf_mime_types)
205
208
  types = MIME::Types.type_for(file)
206
209
 
207
210
  if prefer_cf_mime_types
208
211
  intersection = types & Capistrano::S3::MIMETypes::CF_MIME_TYPES
209
212
 
210
- unless intersection.empty?
211
- types = intersection
212
- end
213
+ types = intersection unless intersection.empty?
213
214
  end
214
215
 
215
216
  types.first
216
217
  end
217
218
 
218
- def self.gzip_name(file)
219
+ def gzip_name(file)
219
220
  "#{file}.gz"
220
221
  end
221
222
 
222
- def self.orig_name(file)
223
+ def orig_name(file)
223
224
  file.sub(/\.gz$/, "")
224
225
  end
225
226
 
226
- def self.add_prefix(path, prefix:)
227
+ def add_prefix(path, prefix:)
227
228
  if prefix.empty?
228
229
  path
229
230
  else
230
231
  File.join(prefix, path)
231
232
  end
232
233
  end
234
+ end
233
235
  end
234
236
  end
235
237
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Capistrano
2
4
  module S3
3
- VERSION = "2.4.0"
5
+ VERSION = "3.0.0.pre2"
4
6
  end
5
7
  end
data/lib/capistrano/s3.rb CHANGED
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "capistrano"
2
4
  require "capistrano/s3/publisher"
3
5
  require "capistrano/s3/version"
4
6
  require "capistrano/s3/defaults"
5
7
  require "capistrano/s3/mime_types"
6
8
 
7
- if Gem::Specification.find_by_name('capistrano').version >= Gem::Version.new('3.0.0')
8
- load File.expand_path('../tasks/capistrano_3.rb', __FILE__)
9
+ if Gem::Specification.find_by_name("capistrano").version >= Gem::Version.new("3.0.0")
10
+ load File.expand_path("tasks/capistrano_3.rb", __dir__)
9
11
  else
10
- require_relative 'tasks/capistrano_2'
12
+ require_relative "tasks/capistrano_2"
11
13
  end
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Capistrano
4
+ # rubocop:disable Metrics/BlockLength
2
5
  Configuration.instance(true).load do
3
6
  def _cset(name, *args, &block)
4
- set(name, *args, &block) if !exists?(name)
7
+ set(name, *args, &block) unless exists?(name)
5
8
  end
6
9
 
7
10
  Capistrano::S3::Defaults.populate(self, :_cset)
@@ -16,14 +19,21 @@ module Capistrano
16
19
 
17
20
  desc "Waits until the last CloudFront invalidation batch is completed"
18
21
  task :wait_for_invalidation do
19
- S3::Publisher.check_invalidation(region, access_key_id, secret_access_key, distribution_id)
22
+ S3::Publisher.check_invalidation(region, access_key_id, secret_access_key,
23
+ distribution_id)
20
24
  end
21
25
 
22
26
  desc "Upload files to the bucket in the current state"
23
27
  task :upload_files do
24
- extra_options = { :write => bucket_write_options, :redirect => redirect_options, :object_write => object_write_options, :prefer_cf_mime_types => prefer_cf_mime_types }
28
+ extra_options = {
29
+ write: bucket_write_options,
30
+ redirect: redirect_options,
31
+ object_write: object_write_options,
32
+ prefer_cf_mime_types: prefer_cf_mime_types
33
+ }
25
34
  S3::Publisher.publish!(region, access_key_id, secret_access_key,
26
- bucket, deployment_path, target_path, distribution_id, invalidations, exclusions, only_gzip, extra_options)
35
+ bucket, deployment_path, target_path, distribution_id,
36
+ invalidations, exclusions, only_gzip, extra_options)
27
37
  end
28
38
  end
29
39
 
@@ -31,7 +41,10 @@ module Capistrano
31
41
  s3.upload_files
32
42
  end
33
43
 
34
- task :restart do; end
44
+ task :restart do
45
+ # @todo remove?
46
+ end
35
47
  end
36
48
  end
49
+ # rubocop:enable Metrics/BlockLength
37
50
  end
@@ -1,26 +1,42 @@
1
+ # frozen_string_literal: true
2
+
1
3
  namespace :load do
2
4
  task :defaults do
3
5
  Capistrano::S3::Defaults.populate(self, :set)
4
6
  end
5
7
  end
6
8
 
9
+ # rubocop:disable Metrics/BlockLength
7
10
  namespace :deploy do
8
11
  namespace :s3 do
9
12
  desc "Empties bucket of all files. Caution when using this command, as it cannot be undone!"
10
13
  task :empty do
11
- Capistrano::S3::Publisher.clear!(fetch(:region), fetch(:access_key_id), fetch(:secret_access_key), fetch(:bucket), fetch(:stage))
14
+ Capistrano::S3::Publisher.clear!(fetch(:region), fetch(:access_key_id),
15
+ fetch(:secret_access_key), fetch(:bucket), fetch(:stage))
12
16
  end
13
17
 
14
18
  desc "Waits until the last CloudFront invalidation batch is completed"
15
19
  task :wait_for_invalidation do
16
- Capistrano::S3::Publisher.check_invalidation(fetch(:region), fetch(:access_key_id), fetch(:secret_access_key), fetch(:distribution_id), fetch(:stage))
20
+ Capistrano::S3::Publisher.check_invalidation(fetch(:region), fetch(:access_key_id),
21
+ fetch(:secret_access_key),
22
+ fetch(:distribution_id),
23
+ fetch(:stage))
17
24
  end
18
25
 
19
26
  desc "Upload files to the bucket in the current state"
20
27
  task :upload_files do
21
- extra_options = { :write => fetch(:bucket_write_options), :redirect => fetch(:redirect_options), :object_write => fetch(:object_write_options), :prefer_cf_mime_types => fetch(:prefer_cf_mime_types) }
22
- Capistrano::S3::Publisher.publish!(fetch(:region), fetch(:access_key_id), fetch(:secret_access_key),
23
- fetch(:bucket), fetch(:deployment_path), fetch(:target_path), fetch(:distribution_id), fetch(:invalidations), fetch(:exclusions), fetch(:only_gzip), extra_options, fetch(:stage))
28
+ extra_options = {
29
+ write: fetch(:bucket_write_options),
30
+ redirect: fetch(:redirect_options),
31
+ object_write: fetch(:object_write_options),
32
+ prefer_cf_mime_types: fetch(:prefer_cf_mime_types)
33
+ }
34
+ Capistrano::S3::Publisher.publish!(fetch(:region), fetch(:access_key_id),
35
+ fetch(:secret_access_key), fetch(:bucket),
36
+ fetch(:deployment_path), fetch(:target_path),
37
+ fetch(:distribution_id), fetch(:invalidations),
38
+ fetch(:exclusions), fetch(:only_gzip), extra_options,
39
+ fetch(:stage))
24
40
  end
25
41
  end
26
42
 
@@ -28,3 +44,4 @@ namespace :deploy do
28
44
  invoke("deploy:s3:upload_files")
29
45
  end
30
46
  end
47
+ # rubocop:enable Metrics/BlockLength