middleman-s3_sync 4.6.2 → 4.6.4
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 +4 -4
- data/.mise.toml +17 -0
- data/Changelog.md +8 -0
- data/lib/middleman/s3_sync/caching_policy.rb +3 -3
- data/lib/middleman/s3_sync/indifferent_hash.rb +62 -0
- data/lib/middleman/s3_sync/options.rb +26 -3
- data/lib/middleman/s3_sync/resource.rb +56 -34
- data/lib/middleman/s3_sync/version.rb +1 -1
- data/lib/middleman-s3_sync/extension.rb +22 -2
- data/middleman-s3_sync.gemspec +1 -4
- data/spec/aws_sdk_parameters_spec.rb +110 -0
- data/spec/extension_spec.rb +114 -0
- data/spec/options_spec.rb +272 -0
- metadata +11 -47
- /data/{.envrc → .envrc.backup} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e6b576cfe91e75975edadd71f0cfd319e84772edecd882aabe2e3c8c06c90082
|
|
4
|
+
data.tar.gz: 86bc102e074f9b47980e4cbf93060babd7f7b8a5117cbf35b60ea78ba7476ff0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 20b465799e297cff4e8085ba9c9e25637a25a3a77242d862f1d2b93291dd6112c32835fc91eb8fd92d0e4cd11df6676c034330d804e4556b5fc0ba4c2312215e
|
|
7
|
+
data.tar.gz: 36a4b96fa0c6831047a90ef4140c598bfab3eb5279fffa09adeee5e23673cb30a811806019ea63de16d1c52383b9a644a2ed6cf0bf400ccd1e9eaade616ae00a
|
data/.mise.toml
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[tools]
|
|
2
|
+
ruby = "3.4"
|
|
3
|
+
|
|
4
|
+
[env]
|
|
5
|
+
_.file = ".env"
|
|
6
|
+
_.path = ["./bin"]
|
|
7
|
+
|
|
8
|
+
[tasks.binstubs]
|
|
9
|
+
description = "Generate binstubs for all gems"
|
|
10
|
+
run = "bundle binstubs --all"
|
|
11
|
+
|
|
12
|
+
[tasks.setup]
|
|
13
|
+
description = "Setup project dependencies and binstubs"
|
|
14
|
+
run = [
|
|
15
|
+
"bundle install",
|
|
16
|
+
"mise run binstubs"
|
|
17
|
+
]
|
data/Changelog.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
The gem that tries really hard not to push files to S3.
|
|
4
4
|
|
|
5
|
+
## v4.6.4
|
|
6
|
+
* Remove map gem dependency and replace with native Ruby implementation
|
|
7
|
+
* Add IndifferentHash class to provide string/symbol indifferent access without external dependencies
|
|
8
|
+
* Improve gem stability by eliminating dependency on unmaintained library
|
|
9
|
+
|
|
10
|
+
## v4.6.3
|
|
11
|
+
* Restrict incompatible map 8.x installation
|
|
12
|
+
|
|
5
13
|
## v4.6.2
|
|
6
14
|
|
|
7
15
|
* Fix AWS SDK parameter format issues from Fog migration
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'middleman/s3_sync/indifferent_hash'
|
|
2
2
|
|
|
3
3
|
module Middleman
|
|
4
4
|
module S3Sync
|
|
@@ -17,7 +17,7 @@ module Middleman
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def caching_policies
|
|
20
|
-
@caching_policies ||=
|
|
20
|
+
@caching_policies ||= IndifferentHash.new
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
|
@@ -25,7 +25,7 @@ module Middleman
|
|
|
25
25
|
attr_accessor :policies
|
|
26
26
|
|
|
27
27
|
def initialize(options = {})
|
|
28
|
-
@policies =
|
|
28
|
+
@policies = IndifferentHash.from_hash(options)
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def cache_control
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module Middleman
|
|
2
|
+
module S3Sync
|
|
3
|
+
# A simple hash wrapper that provides string/symbol indifferent access
|
|
4
|
+
# This replaces the Map gem dependency with native Ruby functionality
|
|
5
|
+
class IndifferentHash < Hash
|
|
6
|
+
# Convert keys to strings for consistent access
|
|
7
|
+
def normalize_key(key)
|
|
8
|
+
key.to_s
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Override [] to provide indifferent access
|
|
12
|
+
def [](key)
|
|
13
|
+
super(normalize_key(key))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Override []= to store with normalized keys
|
|
17
|
+
def []=(key, value)
|
|
18
|
+
super(normalize_key(key), value)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Override fetch to provide indifferent access
|
|
22
|
+
def fetch(key, *args, &block)
|
|
23
|
+
super(normalize_key(key), *args, &block)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Override has_key? to work with normalized keys
|
|
27
|
+
def has_key?(key)
|
|
28
|
+
super(normalize_key(key))
|
|
29
|
+
end
|
|
30
|
+
alias_method :key?, :has_key?
|
|
31
|
+
alias_method :include?, :has_key?
|
|
32
|
+
|
|
33
|
+
# Create an IndifferentHash from a regular hash
|
|
34
|
+
def self.from_hash(hash)
|
|
35
|
+
new_hash = new
|
|
36
|
+
hash.each do |key, value|
|
|
37
|
+
new_hash[key] = value
|
|
38
|
+
end
|
|
39
|
+
new_hash
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Provide dot notation access to hash values
|
|
43
|
+
def method_missing(method, *args, &block)
|
|
44
|
+
key = method.to_s
|
|
45
|
+
if key.end_with?('=')
|
|
46
|
+
# Handle setter: hash.key = value
|
|
47
|
+
self[key.chop] = args.first
|
|
48
|
+
elsif has_key?(key)
|
|
49
|
+
# Handle getter: hash.key
|
|
50
|
+
self[key]
|
|
51
|
+
else
|
|
52
|
+
super
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def respond_to_missing?(method, include_private = false)
|
|
57
|
+
key = method.to_s.sub(/=$/, '')
|
|
58
|
+
has_key?(key) || super
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -10,10 +10,10 @@ module Middleman
|
|
|
10
10
|
:region,
|
|
11
11
|
:aws_access_key_id,
|
|
12
12
|
:aws_secret_access_key,
|
|
13
|
+
:aws_session_token,
|
|
13
14
|
:after_build,
|
|
14
15
|
:delete,
|
|
15
16
|
:encryption,
|
|
16
|
-
:existing_remote_file,
|
|
17
17
|
:build_dir,
|
|
18
18
|
:force,
|
|
19
19
|
:prefer_gzip,
|
|
@@ -25,12 +25,35 @@ module Middleman
|
|
|
25
25
|
:content_types,
|
|
26
26
|
:ignore_paths,
|
|
27
27
|
:index_document,
|
|
28
|
-
:error_document
|
|
28
|
+
:error_document,
|
|
29
|
+
:cloudfront_distribution_id,
|
|
30
|
+
:cloudfront_invalidate,
|
|
31
|
+
:cloudfront_invalidate_all,
|
|
32
|
+
:cloudfront_invalidation_batch_size,
|
|
33
|
+
:cloudfront_invalidation_max_retries,
|
|
34
|
+
:cloudfront_invalidation_batch_delay,
|
|
35
|
+
:cloudfront_wait
|
|
29
36
|
]
|
|
30
37
|
attr_accessor *OPTIONS
|
|
31
38
|
|
|
32
39
|
def acl
|
|
33
|
-
@acl
|
|
40
|
+
# If @acl is explicitly set to empty string or false, return nil (for buckets with ACLs disabled)
|
|
41
|
+
# If @acl is nil and was never set, return default 'public-read'
|
|
42
|
+
# Otherwise return the set value
|
|
43
|
+
return nil if @acl == '' || @acl == false
|
|
44
|
+
@acl_explicitly_set ? @acl : (@acl || 'public-read')
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def acl=(value)
|
|
48
|
+
@acl_explicitly_set = true
|
|
49
|
+
@acl = value
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def acl_enabled?
|
|
53
|
+
# ACLs are disabled if explicitly set to nil, empty string, or false
|
|
54
|
+
return false if @acl_explicitly_set && (@acl.nil? || @acl == '' || @acl == false)
|
|
55
|
+
# Otherwise ACLs are enabled (using default or explicit value)
|
|
56
|
+
true
|
|
34
57
|
end
|
|
35
58
|
|
|
36
59
|
def aws_access_key_id=(aws_access_key_id)
|
|
@@ -55,10 +55,11 @@ module Middleman
|
|
|
55
55
|
def to_h
|
|
56
56
|
attributes = {
|
|
57
57
|
:key => key,
|
|
58
|
-
:acl => options.acl,
|
|
59
58
|
:content_type => content_type,
|
|
60
59
|
'content-md5' => local_content_md5
|
|
61
60
|
}
|
|
61
|
+
# Only add ACL if enabled (not for buckets with ACLs disabled)
|
|
62
|
+
attributes[:acl] = options.acl if options.acl_enabled?
|
|
62
63
|
|
|
63
64
|
if caching_policy
|
|
64
65
|
attributes[:cache_control] = caching_policy.cache_control
|
|
@@ -115,40 +116,22 @@ module Middleman
|
|
|
115
116
|
|
|
116
117
|
def upload!
|
|
117
118
|
object = bucket.object(remote_path.sub(/^\//, ''))
|
|
118
|
-
upload_options =
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
upload_options[:content_encoding] = "gzip" if options.prefer_gzip && gzipped
|
|
134
|
-
|
|
135
|
-
# Add cache control and expires if present
|
|
136
|
-
if caching_policy
|
|
137
|
-
upload_options[:cache_control] = caching_policy.cache_control
|
|
138
|
-
upload_options[:expires] = caching_policy.expires
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
# Add storage class if needed
|
|
142
|
-
if options.reduced_redundancy_storage
|
|
143
|
-
upload_options[:storage_class] = 'REDUCED_REDUNDANCY'
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
# Add encryption if needed
|
|
147
|
-
if options.encryption
|
|
148
|
-
upload_options[:server_side_encryption] = 'AES256'
|
|
119
|
+
upload_options = build_upload_options
|
|
120
|
+
|
|
121
|
+
begin
|
|
122
|
+
object.put(upload_options)
|
|
123
|
+
rescue Aws::S3::Errors::AccessControlListNotSupported => e
|
|
124
|
+
# Bucket has ACLs disabled - retry without ACL
|
|
125
|
+
if upload_options.key?(:acl)
|
|
126
|
+
say_status "#{ANSI.yellow{"Note"}} Bucket does not support ACLs, retrying without ACL parameter"
|
|
127
|
+
# Automatically disable ACLs for this bucket going forward
|
|
128
|
+
options.acl = ''
|
|
129
|
+
upload_options.delete(:acl)
|
|
130
|
+
retry
|
|
131
|
+
else
|
|
132
|
+
raise e
|
|
133
|
+
end
|
|
149
134
|
end
|
|
150
|
-
|
|
151
|
-
object.put(upload_options)
|
|
152
135
|
end
|
|
153
136
|
|
|
154
137
|
def ignore!
|
|
@@ -330,6 +313,45 @@ module Middleman
|
|
|
330
313
|
end
|
|
331
314
|
|
|
332
315
|
protected
|
|
316
|
+
|
|
317
|
+
def build_upload_options
|
|
318
|
+
upload_options = {
|
|
319
|
+
body: local_content,
|
|
320
|
+
content_type: content_type
|
|
321
|
+
}
|
|
322
|
+
# Only add ACL if enabled (not for buckets with ACLs disabled)
|
|
323
|
+
upload_options[:acl] = options.acl if options.acl_enabled?
|
|
324
|
+
|
|
325
|
+
# Add metadata if present
|
|
326
|
+
if local_content_md5
|
|
327
|
+
upload_options[:metadata] = { 'content-md5' => local_content_md5 }
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# Add redirect if present
|
|
331
|
+
upload_options[:website_redirect_location] = redirect_url if redirect?
|
|
332
|
+
|
|
333
|
+
# Add content encoding if present
|
|
334
|
+
upload_options[:content_encoding] = "gzip" if options.prefer_gzip && gzipped
|
|
335
|
+
|
|
336
|
+
# Add cache control and expires if present
|
|
337
|
+
if caching_policy
|
|
338
|
+
upload_options[:cache_control] = caching_policy.cache_control
|
|
339
|
+
upload_options[:expires] = caching_policy.expires
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
# Add storage class if needed
|
|
343
|
+
if options.reduced_redundancy_storage
|
|
344
|
+
upload_options[:storage_class] = 'REDUCED_REDUNDANCY'
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
# Add encryption if needed
|
|
348
|
+
if options.encryption
|
|
349
|
+
upload_options[:server_side_encryption] = 'AES256'
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
upload_options
|
|
353
|
+
end
|
|
354
|
+
|
|
333
355
|
def bucket
|
|
334
356
|
Middleman::S3Sync.bucket
|
|
335
357
|
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
require 'middleman-core'
|
|
2
2
|
require 'middleman/s3_sync'
|
|
3
|
-
require 'map'
|
|
4
3
|
|
|
5
4
|
module Middleman
|
|
6
5
|
class S3SyncExtension < ::Middleman::Extension
|
|
@@ -77,7 +76,28 @@ module Middleman
|
|
|
77
76
|
end
|
|
78
77
|
|
|
79
78
|
def s3_sync_options
|
|
80
|
-
|
|
79
|
+
self
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def acl_enabled?
|
|
83
|
+
# ACLs are disabled if acl is explicitly set to nil, empty string, or false
|
|
84
|
+
acl_value = options.acl
|
|
85
|
+
return false if acl_value.nil? || acl_value == '' || acl_value == false
|
|
86
|
+
# Otherwise ACLs are enabled (using default or explicit value)
|
|
87
|
+
true
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Delegate option readers to the options object
|
|
91
|
+
def method_missing(method, *args, &block)
|
|
92
|
+
if options.respond_to?(method)
|
|
93
|
+
options.send(method, *args, &block)
|
|
94
|
+
else
|
|
95
|
+
super
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def respond_to_missing?(method, include_private = false)
|
|
100
|
+
options.respond_to?(method) || super
|
|
81
101
|
end
|
|
82
102
|
|
|
83
103
|
# Read config options from an IO stream and set them on `self`. Defaults
|
data/middleman-s3_sync.gemspec
CHANGED
|
@@ -20,15 +20,12 @@ Gem::Specification.new do |gem|
|
|
|
20
20
|
|
|
21
21
|
gem.add_runtime_dependency 'middleman-core'
|
|
22
22
|
gem.add_runtime_dependency 'middleman-cli'
|
|
23
|
-
gem.add_runtime_dependency '
|
|
24
|
-
gem.add_runtime_dependency 'aws-sdk-s3'
|
|
23
|
+
gem.add_runtime_dependency 'aws-sdk-s3', '>= 1.187.0'
|
|
25
24
|
gem.add_runtime_dependency 'aws-sdk-cloudfront'
|
|
26
|
-
gem.add_runtime_dependency 'map'
|
|
27
25
|
gem.add_runtime_dependency 'parallel'
|
|
28
26
|
gem.add_runtime_dependency 'ruby-progressbar'
|
|
29
27
|
gem.add_runtime_dependency 'ansi', '~> 1.5.0'
|
|
30
28
|
gem.add_runtime_dependency 'mime-types', '~> 3.1'
|
|
31
|
-
gem.add_runtime_dependency 'base64'
|
|
32
29
|
gem.add_runtime_dependency 'nokogiri', '>= 1.18.4'
|
|
33
30
|
|
|
34
31
|
gem.add_development_dependency 'rake'
|
|
@@ -152,6 +152,88 @@ describe 'AWS SDK Parameter Validation' do
|
|
|
152
152
|
resource.upload!
|
|
153
153
|
end
|
|
154
154
|
|
|
155
|
+
context 'when ACL is set to empty string (for buckets with ACLs disabled)' do
|
|
156
|
+
before do
|
|
157
|
+
options.acl = ''
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
it 'does not include acl parameter in upload' do
|
|
161
|
+
expect(s3_object).to receive(:put) do |upload_options|
|
|
162
|
+
expect(upload_options).not_to have_key(:acl)
|
|
163
|
+
expect(upload_options[:body]).to eq('test content')
|
|
164
|
+
expect(upload_options[:content_type]).to eq('text/html')
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
resource.upload!
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
context 'when ACL is set to nil (for buckets with ACLs disabled)' do
|
|
172
|
+
before do
|
|
173
|
+
options.acl = nil
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
it 'does not include acl parameter in upload' do
|
|
177
|
+
expect(s3_object).to receive(:put) do |upload_options|
|
|
178
|
+
expect(upload_options).not_to have_key(:acl)
|
|
179
|
+
expect(upload_options[:body]).to eq('test content')
|
|
180
|
+
expect(upload_options[:content_type]).to eq('text/html')
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
resource.upload!
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
context 'when bucket does not support ACLs (auto-detection)' do
|
|
188
|
+
before do
|
|
189
|
+
# ACL is enabled by default
|
|
190
|
+
expect(options.acl).to eq('public-read')
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
it 'automatically retries without ACL when AccessControlListNotSupported error occurs' do
|
|
194
|
+
call_count = 0
|
|
195
|
+
expect(s3_object).to receive(:put).twice do |upload_options|
|
|
196
|
+
call_count += 1
|
|
197
|
+
if call_count == 1
|
|
198
|
+
# First call should include ACL
|
|
199
|
+
expect(upload_options[:acl]).to eq('public-read')
|
|
200
|
+
raise Aws::S3::Errors::AccessControlListNotSupported.new(nil, 'The bucket does not allow ACLs')
|
|
201
|
+
else
|
|
202
|
+
# Second call should not include ACL
|
|
203
|
+
expect(upload_options).not_to have_key(:acl)
|
|
204
|
+
expect(upload_options[:body]).to eq('test content')
|
|
205
|
+
expect(upload_options[:content_type]).to eq('text/html')
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Should automatically disable ACLs after the error
|
|
210
|
+
resource.upload!
|
|
211
|
+
expect(options.acl_enabled?).to be false
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
it 'permanently disables ACLs after detecting bucket does not support them' do
|
|
215
|
+
call_count = 0
|
|
216
|
+
allow(s3_object).to receive(:put) do |upload_options|
|
|
217
|
+
call_count += 1
|
|
218
|
+
if call_count == 1
|
|
219
|
+
expect(upload_options[:acl]).to eq('public-read')
|
|
220
|
+
raise Aws::S3::Errors::AccessControlListNotSupported.new(nil, 'The bucket does not allow ACLs')
|
|
221
|
+
else
|
|
222
|
+
# Second call should succeed without ACL
|
|
223
|
+
expect(upload_options).not_to have_key(:acl)
|
|
224
|
+
true
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
resource.upload!
|
|
229
|
+
expect(options.acl_enabled?).to be false
|
|
230
|
+
|
|
231
|
+
# Verify ACLs stay disabled for future uploads
|
|
232
|
+
resource.upload!
|
|
233
|
+
expect(call_count).to eq(3) # First attempt, retry, and third upload
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
155
237
|
context 'when gzip is enabled' do
|
|
156
238
|
before do
|
|
157
239
|
options.prefer_gzip = true
|
|
@@ -306,6 +388,34 @@ describe 'AWS SDK Parameter Validation' do
|
|
|
306
388
|
expect(attributes).not_to have_key('x-amz-meta-content-md5')
|
|
307
389
|
end
|
|
308
390
|
|
|
391
|
+
context 'when ACL is set to empty string' do
|
|
392
|
+
before do
|
|
393
|
+
options.acl = ''
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
it 'does not include acl in attributes' do
|
|
397
|
+
attributes = resource.to_h
|
|
398
|
+
|
|
399
|
+
expect(attributes).not_to have_key(:acl)
|
|
400
|
+
expect(attributes[:key]).to eq('test/file.html')
|
|
401
|
+
expect(attributes[:content_type]).to eq('text/html')
|
|
402
|
+
end
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
context 'when ACL is set to nil' do
|
|
406
|
+
before do
|
|
407
|
+
options.acl = nil
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
it 'does not include acl in attributes' do
|
|
411
|
+
attributes = resource.to_h
|
|
412
|
+
|
|
413
|
+
expect(attributes).not_to have_key(:acl)
|
|
414
|
+
expect(attributes[:key]).to eq('test/file.html')
|
|
415
|
+
expect(attributes[:content_type]).to eq('text/html')
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|
|
309
419
|
context 'when resource has a redirect' do
|
|
310
420
|
let(:mm_resource) do
|
|
311
421
|
double(
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Middleman::S3SyncExtension do
|
|
4
|
+
let(:app) { double('app').as_null_object }
|
|
5
|
+
|
|
6
|
+
let(:extension) { described_class.new(app, {}) }
|
|
7
|
+
|
|
8
|
+
describe '#acl_enabled?' do
|
|
9
|
+
context 'when acl has default value' do
|
|
10
|
+
it 'returns true' do
|
|
11
|
+
expect(extension.acl_enabled?).to be true
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
context 'when acl is explicitly set to a value' do
|
|
16
|
+
let(:extension) { described_class.new(app, acl: 'private') }
|
|
17
|
+
|
|
18
|
+
it 'returns true' do
|
|
19
|
+
expect(extension.acl_enabled?).to be true
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
context 'when acl is set to nil' do
|
|
24
|
+
let(:extension) { described_class.new(app, acl: nil) }
|
|
25
|
+
|
|
26
|
+
it 'returns false' do
|
|
27
|
+
expect(extension.acl_enabled?).to be false
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
context 'when acl is set to empty string' do
|
|
32
|
+
let(:extension) { described_class.new(app, acl: '') }
|
|
33
|
+
|
|
34
|
+
it 'returns false' do
|
|
35
|
+
expect(extension.acl_enabled?).to be false
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
context 'when acl is set to false' do
|
|
40
|
+
let(:extension) { described_class.new(app, acl: false) }
|
|
41
|
+
|
|
42
|
+
it 'returns false' do
|
|
43
|
+
expect(extension.acl_enabled?).to be false
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe '#s3_sync_options' do
|
|
49
|
+
it 'returns the extension instance itself' do
|
|
50
|
+
expect(extension.s3_sync_options).to eq(extension)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'allows access to acl_enabled? through s3_sync_options' do
|
|
54
|
+
expect(extension.s3_sync_options.acl_enabled?).to be true
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe 'option delegation' do
|
|
59
|
+
let(:extension) do
|
|
60
|
+
described_class.new(app,
|
|
61
|
+
bucket: 'test-bucket',
|
|
62
|
+
region: 'us-west-2',
|
|
63
|
+
acl: 'public-read',
|
|
64
|
+
verbose: true
|
|
65
|
+
)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it 'delegates option readers to the options object' do
|
|
69
|
+
expect(extension.bucket).to eq('test-bucket')
|
|
70
|
+
expect(extension.region).to eq('us-west-2')
|
|
71
|
+
expect(extension.acl).to eq('public-read')
|
|
72
|
+
expect(extension.verbose).to be true
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'responds to option methods' do
|
|
76
|
+
expect(extension.respond_to?(:bucket)).to be true
|
|
77
|
+
expect(extension.respond_to?(:region)).to be true
|
|
78
|
+
expect(extension.respond_to?(:acl)).to be true
|
|
79
|
+
expect(extension.respond_to?(:verbose)).to be true
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'does not respond to non-existent methods' do
|
|
83
|
+
expect(extension.respond_to?(:nonexistent_method)).to be false
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'raises NoMethodError for non-existent methods' do
|
|
87
|
+
expect { extension.nonexistent_method }.to raise_error(NoMethodError)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
describe 'integration with S3Sync module' do
|
|
92
|
+
before do
|
|
93
|
+
allow(Middleman::Application).to receive(:root).and_return('/tmp')
|
|
94
|
+
allow(File).to receive(:exist?).with('/tmp/.s3_sync').and_return(false)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
let(:extension) do
|
|
98
|
+
described_class.new(app,
|
|
99
|
+
bucket: 'test-bucket',
|
|
100
|
+
acl: 'private'
|
|
101
|
+
)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it 'sets s3_sync_options to the extension instance' do
|
|
105
|
+
extension.after_configuration
|
|
106
|
+
expect(Middleman::S3Sync.s3_sync_options).to eq(extension)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it 'allows S3Sync to access acl_enabled? through s3_sync_options' do
|
|
110
|
+
extension.after_configuration
|
|
111
|
+
expect(Middleman::S3Sync.s3_sync_options.acl_enabled?).to be true
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Middleman::S3Sync::Options do
|
|
4
|
+
let(:options) { described_class.new }
|
|
5
|
+
|
|
6
|
+
describe 'option accessors' do
|
|
7
|
+
it 'provides accessors for all defined options' do
|
|
8
|
+
described_class::OPTIONS.each do |option_name|
|
|
9
|
+
expect(options).to respond_to(option_name)
|
|
10
|
+
expect(options).to respond_to("#{option_name}=")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe 'AWS credentials options' do
|
|
16
|
+
it 'supports aws_access_key_id' do
|
|
17
|
+
options.aws_access_key_id = 'test_key'
|
|
18
|
+
expect(options.aws_access_key_id).to eq('test_key')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'supports aws_secret_access_key' do
|
|
22
|
+
options.aws_secret_access_key = 'test_secret'
|
|
23
|
+
expect(options.aws_secret_access_key).to eq('test_secret')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'supports aws_session_token' do
|
|
27
|
+
options.aws_session_token = 'test_token'
|
|
28
|
+
expect(options.aws_session_token).to eq('test_token')
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'falls back to ENV for aws_access_key_id' do
|
|
32
|
+
ENV['AWS_ACCESS_KEY_ID'] = 'env_key'
|
|
33
|
+
expect(options.aws_access_key_id).to eq('env_key')
|
|
34
|
+
ensure
|
|
35
|
+
ENV.delete('AWS_ACCESS_KEY_ID')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'falls back to ENV for aws_secret_access_key' do
|
|
39
|
+
ENV['AWS_SECRET_ACCESS_KEY'] = 'env_secret'
|
|
40
|
+
expect(options.aws_secret_access_key).to eq('env_secret')
|
|
41
|
+
ensure
|
|
42
|
+
ENV.delete('AWS_SECRET_ACCESS_KEY')
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe 'CloudFront options' do
|
|
47
|
+
it 'supports cloudfront_distribution_id' do
|
|
48
|
+
options.cloudfront_distribution_id = 'E1234567890123'
|
|
49
|
+
expect(options.cloudfront_distribution_id).to eq('E1234567890123')
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'supports cloudfront_invalidate' do
|
|
53
|
+
options.cloudfront_invalidate = true
|
|
54
|
+
expect(options.cloudfront_invalidate).to be true
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'supports cloudfront_invalidate_all' do
|
|
58
|
+
options.cloudfront_invalidate_all = true
|
|
59
|
+
expect(options.cloudfront_invalidate_all).to be true
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it 'supports cloudfront_invalidation_batch_size' do
|
|
63
|
+
options.cloudfront_invalidation_batch_size = 500
|
|
64
|
+
expect(options.cloudfront_invalidation_batch_size).to eq(500)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'supports cloudfront_invalidation_max_retries' do
|
|
68
|
+
options.cloudfront_invalidation_max_retries = 10
|
|
69
|
+
expect(options.cloudfront_invalidation_max_retries).to eq(10)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'supports cloudfront_invalidation_batch_delay' do
|
|
73
|
+
options.cloudfront_invalidation_batch_delay = 5
|
|
74
|
+
expect(options.cloudfront_invalidation_batch_delay).to eq(5)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'supports cloudfront_wait' do
|
|
78
|
+
options.cloudfront_wait = true
|
|
79
|
+
expect(options.cloudfront_wait).to be true
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
describe 'S3 options' do
|
|
84
|
+
it 'supports bucket' do
|
|
85
|
+
options.bucket = 'my-bucket'
|
|
86
|
+
expect(options.bucket).to eq('my-bucket')
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'supports region' do
|
|
90
|
+
options.region = 'us-west-2'
|
|
91
|
+
expect(options.region).to eq('us-west-2')
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'supports endpoint' do
|
|
95
|
+
options.endpoint = 'https://s3-compatible.example.com'
|
|
96
|
+
expect(options.endpoint).to eq('https://s3-compatible.example.com')
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it 'supports prefix' do
|
|
100
|
+
options.prefix = 'my-prefix'
|
|
101
|
+
expect(options.prefix).to eq('my-prefix/')
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it 'supports path_style' do
|
|
105
|
+
options.path_style = false
|
|
106
|
+
expect(options.path_style).to be false
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it 'defaults path_style to true' do
|
|
110
|
+
expect(options.path_style).to be true
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it 'supports encryption' do
|
|
114
|
+
options.encryption = true
|
|
115
|
+
expect(options.encryption).to be true
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it 'defaults encryption to false' do
|
|
119
|
+
expect(options.encryption).to be false
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it 'supports reduced_redundancy_storage' do
|
|
123
|
+
options.reduced_redundancy_storage = true
|
|
124
|
+
expect(options.reduced_redundancy_storage).to be true
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
describe 'ACL options' do
|
|
129
|
+
it 'supports acl' do
|
|
130
|
+
options.acl = 'private'
|
|
131
|
+
expect(options.acl).to eq('private')
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it 'defaults acl to public-read' do
|
|
135
|
+
expect(options.acl).to eq('public-read')
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it 'supports acl_enabled?' do
|
|
139
|
+
expect(options.acl_enabled?).to be true
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
context 'when acl is disabled' do
|
|
143
|
+
it 'returns false for acl_enabled? when set to empty string' do
|
|
144
|
+
options.acl = ''
|
|
145
|
+
expect(options.acl_enabled?).to be false
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it 'returns false for acl_enabled? when set to nil' do
|
|
149
|
+
options.acl = nil
|
|
150
|
+
expect(options.acl_enabled?).to be false
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
it 'returns false for acl_enabled? when set to false' do
|
|
154
|
+
options.acl = false
|
|
155
|
+
expect(options.acl_enabled?).to be false
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
describe 'sync behavior options' do
|
|
161
|
+
it 'supports delete' do
|
|
162
|
+
options.delete = false
|
|
163
|
+
expect(options.delete).to be false
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it 'defaults delete to true' do
|
|
167
|
+
expect(options.delete).to be true
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
it 'supports force' do
|
|
171
|
+
options.force = true
|
|
172
|
+
expect(options.force).to be true
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it 'supports prefer_gzip' do
|
|
176
|
+
options.prefer_gzip = false
|
|
177
|
+
expect(options.prefer_gzip).to be false
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
it 'defaults prefer_gzip to true' do
|
|
181
|
+
expect(options.prefer_gzip).to be true
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it 'supports verbose' do
|
|
185
|
+
options.verbose = true
|
|
186
|
+
expect(options.verbose).to be true
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
it 'supports dry_run' do
|
|
190
|
+
options.dry_run = true
|
|
191
|
+
expect(options.dry_run).to be true
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
it 'supports version_bucket' do
|
|
195
|
+
options.version_bucket = true
|
|
196
|
+
expect(options.version_bucket).to be true
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
it 'defaults version_bucket to false' do
|
|
200
|
+
expect(options.version_bucket).to be false
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
describe 'build options' do
|
|
205
|
+
it 'supports build_dir' do
|
|
206
|
+
options.build_dir = 'dist'
|
|
207
|
+
expect(options.build_dir).to eq('dist')
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
it 'supports after_build' do
|
|
211
|
+
options.after_build = true
|
|
212
|
+
expect(options.after_build).to be true
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
it 'defaults after_build to false' do
|
|
216
|
+
expect(options.after_build).to be false
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
describe 'content options' do
|
|
221
|
+
it 'supports content_types' do
|
|
222
|
+
content_types = { '.webp' => 'image/webp' }
|
|
223
|
+
options.content_types = content_types
|
|
224
|
+
expect(options.content_types).to eq(content_types)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
it 'supports ignore_paths' do
|
|
228
|
+
ignore_paths = [/\.bak$/, 'temp/']
|
|
229
|
+
options.ignore_paths = ignore_paths
|
|
230
|
+
expect(options.ignore_paths).to eq(ignore_paths)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
it 'defaults ignore_paths to empty array' do
|
|
234
|
+
expect(options.ignore_paths).to eq([])
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
describe 'website options' do
|
|
239
|
+
it 'supports index_document' do
|
|
240
|
+
options.index_document = 'index.html'
|
|
241
|
+
expect(options.index_document).to eq('index.html')
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
it 'supports error_document' do
|
|
245
|
+
options.error_document = '404.html'
|
|
246
|
+
expect(options.error_document).to eq('404.html')
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
describe 'option consistency' do
|
|
251
|
+
it 'includes all options from extension in OPTIONS constant' do
|
|
252
|
+
# These are the options defined in the extension
|
|
253
|
+
extension_options = [
|
|
254
|
+
:prefix, :http_prefix, :acl, :bucket, :endpoint, :region,
|
|
255
|
+
:aws_access_key_id, :aws_secret_access_key, :aws_session_token,
|
|
256
|
+
:after_build, :build_dir, :delete, :encryption, :force,
|
|
257
|
+
:prefer_gzip, :reduced_redundancy_storage, :path_style,
|
|
258
|
+
:version_bucket, :verbose, :dry_run, :index_document,
|
|
259
|
+
:error_document, :content_types, :ignore_paths,
|
|
260
|
+
:cloudfront_distribution_id, :cloudfront_invalidate,
|
|
261
|
+
:cloudfront_invalidate_all, :cloudfront_invalidation_batch_size,
|
|
262
|
+
:cloudfront_invalidation_max_retries, :cloudfront_invalidation_batch_delay,
|
|
263
|
+
:cloudfront_wait
|
|
264
|
+
]
|
|
265
|
+
|
|
266
|
+
extension_options.each do |option_name|
|
|
267
|
+
expect(described_class::OPTIONS).to include(option_name),
|
|
268
|
+
"Expected OPTIONS to include :#{option_name}"
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: middleman-s3_sync
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.6.
|
|
4
|
+
version: 4.6.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Frederic Jean
|
|
8
8
|
- Will Koehler
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-01-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: middleman-core
|
|
@@ -38,34 +38,20 @@ dependencies:
|
|
|
38
38
|
- - ">="
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '0'
|
|
41
|
-
- !ruby/object:Gem::Dependency
|
|
42
|
-
name: unf
|
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
|
44
|
-
requirements:
|
|
45
|
-
- - ">="
|
|
46
|
-
- !ruby/object:Gem::Version
|
|
47
|
-
version: '0'
|
|
48
|
-
type: :runtime
|
|
49
|
-
prerelease: false
|
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
-
requirements:
|
|
52
|
-
- - ">="
|
|
53
|
-
- !ruby/object:Gem::Version
|
|
54
|
-
version: '0'
|
|
55
41
|
- !ruby/object:Gem::Dependency
|
|
56
42
|
name: aws-sdk-s3
|
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
|
58
44
|
requirements:
|
|
59
45
|
- - ">="
|
|
60
46
|
- !ruby/object:Gem::Version
|
|
61
|
-
version:
|
|
47
|
+
version: 1.187.0
|
|
62
48
|
type: :runtime
|
|
63
49
|
prerelease: false
|
|
64
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
51
|
requirements:
|
|
66
52
|
- - ">="
|
|
67
53
|
- !ruby/object:Gem::Version
|
|
68
|
-
version:
|
|
54
|
+
version: 1.187.0
|
|
69
55
|
- !ruby/object:Gem::Dependency
|
|
70
56
|
name: aws-sdk-cloudfront
|
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -80,20 +66,6 @@ dependencies:
|
|
|
80
66
|
- - ">="
|
|
81
67
|
- !ruby/object:Gem::Version
|
|
82
68
|
version: '0'
|
|
83
|
-
- !ruby/object:Gem::Dependency
|
|
84
|
-
name: map
|
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
|
86
|
-
requirements:
|
|
87
|
-
- - ">="
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: '0'
|
|
90
|
-
type: :runtime
|
|
91
|
-
prerelease: false
|
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
-
requirements:
|
|
94
|
-
- - ">="
|
|
95
|
-
- !ruby/object:Gem::Version
|
|
96
|
-
version: '0'
|
|
97
69
|
- !ruby/object:Gem::Dependency
|
|
98
70
|
name: parallel
|
|
99
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -150,20 +122,6 @@ dependencies:
|
|
|
150
122
|
- - "~>"
|
|
151
123
|
- !ruby/object:Gem::Version
|
|
152
124
|
version: '3.1'
|
|
153
|
-
- !ruby/object:Gem::Dependency
|
|
154
|
-
name: base64
|
|
155
|
-
requirement: !ruby/object:Gem::Requirement
|
|
156
|
-
requirements:
|
|
157
|
-
- - ">="
|
|
158
|
-
- !ruby/object:Gem::Version
|
|
159
|
-
version: '0'
|
|
160
|
-
type: :runtime
|
|
161
|
-
prerelease: false
|
|
162
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
163
|
-
requirements:
|
|
164
|
-
- - ">="
|
|
165
|
-
- !ruby/object:Gem::Version
|
|
166
|
-
version: '0'
|
|
167
125
|
- !ruby/object:Gem::Dependency
|
|
168
126
|
name: nokogiri
|
|
169
127
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -311,8 +269,9 @@ executables: []
|
|
|
311
269
|
extensions: []
|
|
312
270
|
extra_rdoc_files: []
|
|
313
271
|
files:
|
|
314
|
-
- ".envrc"
|
|
272
|
+
- ".envrc.backup"
|
|
315
273
|
- ".gitignore"
|
|
274
|
+
- ".mise.toml"
|
|
316
275
|
- ".rspec"
|
|
317
276
|
- ".s3_sync.sample"
|
|
318
277
|
- ".travis.yml"
|
|
@@ -329,6 +288,7 @@ files:
|
|
|
329
288
|
- lib/middleman/s3_sync.rb
|
|
330
289
|
- lib/middleman/s3_sync/caching_policy.rb
|
|
331
290
|
- lib/middleman/s3_sync/cloudfront.rb
|
|
291
|
+
- lib/middleman/s3_sync/indifferent_hash.rb
|
|
332
292
|
- lib/middleman/s3_sync/options.rb
|
|
333
293
|
- lib/middleman/s3_sync/resource.rb
|
|
334
294
|
- lib/middleman/s3_sync/status.rb
|
|
@@ -338,6 +298,8 @@ files:
|
|
|
338
298
|
- spec/aws_sdk_parameters_spec.rb
|
|
339
299
|
- spec/caching_policy_spec.rb
|
|
340
300
|
- spec/cloudfront_spec.rb
|
|
301
|
+
- spec/extension_spec.rb
|
|
302
|
+
- spec/options_spec.rb
|
|
341
303
|
- spec/resource_spec.rb
|
|
342
304
|
- spec/s3_sync_integration_spec.rb
|
|
343
305
|
- spec/spec_helper.rb
|
|
@@ -366,6 +328,8 @@ test_files:
|
|
|
366
328
|
- spec/aws_sdk_parameters_spec.rb
|
|
367
329
|
- spec/caching_policy_spec.rb
|
|
368
330
|
- spec/cloudfront_spec.rb
|
|
331
|
+
- spec/extension_spec.rb
|
|
332
|
+
- spec/options_spec.rb
|
|
369
333
|
- spec/resource_spec.rb
|
|
370
334
|
- spec/s3_sync_integration_spec.rb
|
|
371
335
|
- spec/spec_helper.rb
|
/data/{.envrc → .envrc.backup}
RENAMED
|
File without changes
|