middleman-s3_sync 4.7.0 → 4.8.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 +4 -4
- data/Changelog.md +54 -0
- data/README.md +20 -2
- data/lib/middleman/s3_sync/caching_policy.rb +6 -0
- data/lib/middleman/s3_sync/resource.rb +4 -4
- data/lib/middleman/s3_sync/version.rb +1 -1
- data/middleman-s3_sync.gemspec +0 -1
- data/spec/aws_sdk_parameters_spec.rb +42 -0
- data/spec/caching_policy_spec.rb +27 -2
- data/spec/spec_helper.rb +0 -1
- metadata +1 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1ca1bccd213b5e15c13b3c24763c20164493043d5ed3772b90ac38dc8391293d
|
|
4
|
+
data.tar.gz: 5f2b316721b80826dfe8b33f96ba3b5389b455260a256ff8cf7562cd563a1d28
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3ce61465bdc1d5986030e772d632fc425bc7d97b3d2d948ae5afee9bda9f5b92edb44cfd7bef8ad9d3f435a5c111945091f1e62428d3fd20d803a06a5e4f8e7d
|
|
7
|
+
data.tar.gz: a97276e8b0246ca38c8e5f95a0628b18d980185b366b558979dddeeb414ef2538201f3ce8697d9294390154d096676a71d2545b3fb1f84836d86d72feb53483f
|
data/Changelog.md
CHANGED
|
@@ -2,6 +2,60 @@
|
|
|
2
2
|
|
|
3
3
|
The gem that tries really hard not to push files to S3.
|
|
4
4
|
|
|
5
|
+
## v4.8.0
|
|
6
|
+
- Add `immutable` directive to caching policies. Pair with a long `max_age` on
|
|
7
|
+
fingerprinted assets (e.g. those produced by Middleman's `asset_hash`
|
|
8
|
+
extension) to tell browsers they never need to revalidate:
|
|
9
|
+
`caching_policy 'text/css', max_age: 1.year, public: true, immutable: true`.
|
|
10
|
+
- Prefer `Cache-Control: max-age` over the `Expires` header. When a policy sets
|
|
11
|
+
`max_age:`, the `Expires` header is now suppressed even if `expires:` is also
|
|
12
|
+
set. Per RFC 7234 §5.3, `max-age` overrides `Expires` for HTTP/1.1 caches, so
|
|
13
|
+
emitting both adds no information and forces a metadata update on every build
|
|
14
|
+
as the `expires:` timestamp drifts forward. Existing configs that rely solely
|
|
15
|
+
on `expires:` (without `max_age:`) continue to work unchanged.
|
|
16
|
+
- Resource uploads no longer include empty `cache_control` or `expires` keys
|
|
17
|
+
when the caching policy yields `nil` for them.
|
|
18
|
+
- Drop `timerizer` development dependency. Its monkey-patch of `Time.new` was
|
|
19
|
+
incompatible with Ruby 3.1.7's keyword-argument changes and crashed RSpec at
|
|
20
|
+
startup on the 3.1 CI matrix. The three test usages were replaced with plain
|
|
21
|
+
`Time` literals.
|
|
22
|
+
|
|
23
|
+
## v4.7.0
|
|
24
|
+
- Add `after_s3_sync` callback hook that runs after sync completes (#138).
|
|
25
|
+
Accepts a lambda/proc — optionally receiving a results hash with `created`,
|
|
26
|
+
`updated`, `deleted` counts and invalidation paths — or a symbol referencing
|
|
27
|
+
a method on the Middleman app. Zero-arg callbacks work without modification
|
|
28
|
+
via arity detection. Callback failures are logged but do not abort the sync.
|
|
29
|
+
- Add `scan_build_dir` option (default: `false`) to sync files in the build
|
|
30
|
+
directory that aren't in the Middleman sitemap (#108, #137). Useful for
|
|
31
|
+
output from `after_build` callbacks, image optimizers, or anything placed
|
|
32
|
+
in `build/` outside the sitemap.
|
|
33
|
+
- Add `routing_rules` option to configure S3 website routing rules at sync
|
|
34
|
+
time, so deployments don't overwrite manually-configured rules (#142).
|
|
35
|
+
Supports `condition.key_prefix_equals`,
|
|
36
|
+
`condition.http_error_code_returned_equals`, and the
|
|
37
|
+
`redirect.{host_name, http_redirect_code, protocol, replace_key_prefix_with,
|
|
38
|
+
replace_key_with}` keys. Requires `index_document` to also be set.
|
|
39
|
+
- Improve content type detection with a `mime-types` fallback for files
|
|
40
|
+
Middleman doesn't classify (e.g. orphan files, WebP, woff2). The
|
|
41
|
+
`content_types` option is now checked first, and unknown extensions default
|
|
42
|
+
to `application/octet-stream`. Bumped `mime-types` constraint to `~> 3.4`.
|
|
43
|
+
(#161)
|
|
44
|
+
- Fix sitemap population for build-mode extensions (#116, #128). The sync
|
|
45
|
+
now calls `ensure_resource_list_updated!` so extensions like blog and
|
|
46
|
+
asset_hash populate the sitemap, and always runs in `:build` mode so
|
|
47
|
+
`configure :build` blocks are active. Files emitted by `after_build`
|
|
48
|
+
callbacks still aren't visible to the sitemap — use `scan_build_dir` for
|
|
49
|
+
those.
|
|
50
|
+
- Fix `Resource#redirect?` to return `true`/`false` instead of a truthy URL
|
|
51
|
+
string (#143). The status logic was already correct; this just normalizes
|
|
52
|
+
the boolean contract.
|
|
53
|
+
- Tighten gemspec dependency bounds and require Ruby `>= 3.0` (#167).
|
|
54
|
+
Pessimistic constraints on all runtime and development deps to resolve the
|
|
55
|
+
open-ended-dependency warnings on `gem build`.
|
|
56
|
+
- Add GitHub Actions CI matrix (Ruby 3.1, 3.2, 3.3, 3.4) and an automated
|
|
57
|
+
RubyGems release workflow that publishes on `v*` tags (#169).
|
|
58
|
+
|
|
5
59
|
## v4.6.5
|
|
6
60
|
- Performance and stability improvements
|
|
7
61
|
- Thread-safe invalidation path tracking (use Set + mutex) when running in parallel
|
data/README.md
CHANGED
|
@@ -546,6 +546,21 @@ The following keys can be set:
|
|
|
546
546
|
| `no_store` | boolean | `no-store` | Instructs caches not to keep a copy of the representation under any conditions. |
|
|
547
547
|
| `must_revalidate` | boolean | `must-revalidate` | Tells the caches that they must obey any freshness information you give them about a representation. |
|
|
548
548
|
| `proxy_revalidate` | boolean | `proxy-revalidate` | Similar as `must-revalidate`, but only for proxies. |
|
|
549
|
+
| `immutable` | boolean | `immutable` | Tells browsers the response body will never change for this URL, so they should not revalidate even on a user-initiated reload. Pair with a long `max_age` for content-addressed (fingerprinted) assets. |
|
|
550
|
+
|
|
551
|
+
#### Hashed Assets
|
|
552
|
+
|
|
553
|
+
If you use Middleman's `asset_hash` extension, fingerprinted asset URLs
|
|
554
|
+
are content-addressed and never need to be revalidated. Combining a
|
|
555
|
+
long `max_age` with `immutable` is the strongest browser cache hint
|
|
556
|
+
you can give:
|
|
557
|
+
|
|
558
|
+
```ruby
|
|
559
|
+
caching_policy 'text/css', max_age: 1.year, public: true, immutable: true
|
|
560
|
+
caching_policy 'application/javascript', max_age: 1.year, public: true, immutable: true
|
|
561
|
+
caching_policy 'image/png', max_age: 1.year, public: true, immutable: true
|
|
562
|
+
caching_policy 'image/jpeg', max_age: 1.year, public: true, immutable: true
|
|
563
|
+
```
|
|
549
564
|
|
|
550
565
|
#### Setting `Expires` Header
|
|
551
566
|
|
|
@@ -554,8 +569,11 @@ You can pass the `expires` key to the `caching_policy` and
|
|
|
554
569
|
header on a results. You will need to pass it a Time object indicating
|
|
555
570
|
when the resource is set to expire.
|
|
556
571
|
|
|
557
|
-
> Note that the `Cache-Control` header
|
|
558
|
-
>
|
|
572
|
+
> Note that the `Cache-Control` header takes precedence over `Expires`
|
|
573
|
+
> for HTTP/1.1 caches (RFC 7234 §5.3). For that reason, when a policy
|
|
574
|
+
> sets `max_age:`, the `Expires` header is suppressed entirely — even
|
|
575
|
+
> if `expires:` is also set. This avoids redundant metadata churn from
|
|
576
|
+
> the `expires:` timestamp drifting forward on every build.
|
|
559
577
|
|
|
560
578
|
#### A Note About Browser Caching
|
|
561
579
|
|
|
@@ -38,6 +38,7 @@ module Middleman
|
|
|
38
38
|
policy << "no-store" if policies.fetch(:no_store, false)
|
|
39
39
|
policy << "must-revalidate" if policies.fetch(:must_revalidate, false)
|
|
40
40
|
policy << "proxy-revalidate" if policies.fetch(:proxy_revalidate, false)
|
|
41
|
+
policy << "immutable" if policies.fetch(:immutable, false)
|
|
41
42
|
if policy.empty?
|
|
42
43
|
nil
|
|
43
44
|
else
|
|
@@ -49,7 +50,12 @@ module Middleman
|
|
|
49
50
|
cache_control
|
|
50
51
|
end
|
|
51
52
|
|
|
53
|
+
# Returns an RFC 1123 date for the Expires header.
|
|
54
|
+
# When :max_age is set we suppress Expires entirely: per RFC 7234 §5.3
|
|
55
|
+
# max-age takes precedence over Expires for HTTP/1.1 caches, so emitting
|
|
56
|
+
# both adds no information and forces a metadata update on every build.
|
|
52
57
|
def expires
|
|
58
|
+
return nil if policies.has_key?(:max_age)
|
|
53
59
|
if expiration = policies.fetch(:expires, nil)
|
|
54
60
|
CGI.rfc1123_date(expiration)
|
|
55
61
|
end
|
|
@@ -64,8 +64,8 @@ module Middleman
|
|
|
64
64
|
attributes[:acl] = options.acl if options.acl_enabled?
|
|
65
65
|
|
|
66
66
|
if caching_policy
|
|
67
|
-
attributes[:cache_control] = caching_policy.cache_control
|
|
68
|
-
attributes[:expires] = caching_policy.expires
|
|
67
|
+
attributes[:cache_control] = caching_policy.cache_control if caching_policy.cache_control
|
|
68
|
+
attributes[:expires] = caching_policy.expires if caching_policy.expires
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
if options.prefer_gzip && gzipped
|
|
@@ -382,8 +382,8 @@ module Middleman
|
|
|
382
382
|
|
|
383
383
|
# Add cache control and expires if present
|
|
384
384
|
if caching_policy
|
|
385
|
-
upload_options[:cache_control] = caching_policy.cache_control
|
|
386
|
-
upload_options[:expires] = caching_policy.expires
|
|
385
|
+
upload_options[:cache_control] = caching_policy.cache_control if caching_policy.cache_control
|
|
386
|
+
upload_options[:expires] = caching_policy.expires if caching_policy.expires
|
|
387
387
|
end
|
|
388
388
|
|
|
389
389
|
# Add storage class if needed
|
data/middleman-s3_sync.gemspec
CHANGED
|
@@ -39,6 +39,5 @@ Gem::Specification.new do |gem|
|
|
|
39
39
|
gem.add_development_dependency 'rspec-support', '~> 3.12'
|
|
40
40
|
gem.add_development_dependency 'rspec-its', '~> 2.0'
|
|
41
41
|
gem.add_development_dependency 'rspec-mocks', '~> 3.12'
|
|
42
|
-
gem.add_development_dependency 'timerizer', '~> 0.3'
|
|
43
42
|
gem.add_development_dependency 'webrick', '~> 1.8'
|
|
44
43
|
end
|
|
@@ -479,6 +479,48 @@ describe 'AWS SDK Parameter Validation' do
|
|
|
479
479
|
end
|
|
480
480
|
end
|
|
481
481
|
|
|
482
|
+
context 'when a caching policy with only max_age is in effect' do
|
|
483
|
+
before do
|
|
484
|
+
policy = Middleman::S3Sync::BrowserCachePolicy.new(max_age: 31536000, public: true, immutable: true)
|
|
485
|
+
allow(Middleman::S3Sync).to receive(:caching_policy_for).and_return(policy)
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
it 'sets cache_control but omits expires' do
|
|
489
|
+
attributes = resource.to_h
|
|
490
|
+
|
|
491
|
+
expect(attributes[:cache_control]).to eq('max-age=31536000, public, immutable')
|
|
492
|
+
expect(attributes).not_to have_key(:expires)
|
|
493
|
+
end
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
context 'when a caching policy with only expires is in effect' do
|
|
497
|
+
before do
|
|
498
|
+
policy = Middleman::S3Sync::BrowserCachePolicy.new(expires: Time.utc(2030, 1, 1))
|
|
499
|
+
allow(Middleman::S3Sync).to receive(:caching_policy_for).and_return(policy)
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
it 'sets expires but omits cache_control' do
|
|
503
|
+
attributes = resource.to_h
|
|
504
|
+
|
|
505
|
+
expect(attributes[:expires]).to eq(CGI.rfc1123_date(Time.utc(2030, 1, 1)))
|
|
506
|
+
expect(attributes).not_to have_key(:cache_control)
|
|
507
|
+
end
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
context 'when a caching policy sets both max_age and expires' do
|
|
511
|
+
before do
|
|
512
|
+
policy = Middleman::S3Sync::BrowserCachePolicy.new(max_age: 300, expires: Time.utc(2030, 1, 1))
|
|
513
|
+
allow(Middleman::S3Sync).to receive(:caching_policy_for).and_return(policy)
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
it 'emits cache_control and suppresses the redundant expires' do
|
|
517
|
+
attributes = resource.to_h
|
|
518
|
+
|
|
519
|
+
expect(attributes[:cache_control]).to eq('max-age=300')
|
|
520
|
+
expect(attributes).not_to have_key(:expires)
|
|
521
|
+
end
|
|
522
|
+
end
|
|
523
|
+
|
|
482
524
|
context 'when resource has a redirect' do
|
|
483
525
|
let(:mm_resource) do
|
|
484
526
|
double(
|
data/spec/caching_policy_spec.rb
CHANGED
|
@@ -17,6 +17,7 @@ describe Middleman::S3Sync::BrowserCachePolicy do
|
|
|
17
17
|
expect(policy.to_s).to_not match /no-store/
|
|
18
18
|
expect(policy.to_s).to_not match /must-revalidate/
|
|
19
19
|
expect(policy.to_s).to_not match /proxy-revalidate/
|
|
20
|
+
expect(policy.to_s).to_not match /immutable/
|
|
20
21
|
expect(policy.expires).to eq nil
|
|
21
22
|
end
|
|
22
23
|
|
|
@@ -62,6 +63,19 @@ describe Middleman::S3Sync::BrowserCachePolicy do
|
|
|
62
63
|
its(:to_s) { is_expected.to match /proxy-revalidate/ }
|
|
63
64
|
end
|
|
64
65
|
|
|
66
|
+
context "setting the immutable flag" do
|
|
67
|
+
let(:options) { { immutable: true } }
|
|
68
|
+
its(:to_s) { is_expected.to match /immutable/ }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
context "combining max_age, public, and immutable for hashed assets" do
|
|
72
|
+
let(:options) { { max_age: 31536000, public: true, immutable: true } }
|
|
73
|
+
|
|
74
|
+
it "emits the directives in policy order" do
|
|
75
|
+
expect(policy.to_s).to eq "max-age=31536000, public, immutable"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
65
79
|
context "divide caching policiies with a comma and a space" do
|
|
66
80
|
let(:options) { { :max_age => 300, :public => true } }
|
|
67
81
|
|
|
@@ -74,9 +88,20 @@ describe Middleman::S3Sync::BrowserCachePolicy do
|
|
|
74
88
|
end
|
|
75
89
|
|
|
76
90
|
context "set the expiration date" do
|
|
77
|
-
let(:
|
|
91
|
+
let(:expires_at) { Time.utc(2030, 1, 1) }
|
|
92
|
+
let(:options) { { expires: expires_at } }
|
|
93
|
+
|
|
94
|
+
its(:expires) { is_expected.to eq CGI.rfc1123_date(expires_at) }
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
context "max_age suppresses the Expires header" do
|
|
98
|
+
let(:options) { { max_age: 300, expires: Time.utc(2030, 1, 1) } }
|
|
99
|
+
|
|
100
|
+
it "still emits max-age in cache_control" do
|
|
101
|
+
expect(policy.to_s).to match /max-age=300/
|
|
102
|
+
end
|
|
78
103
|
|
|
79
|
-
its(:expires) { is_expected.to
|
|
104
|
+
its(:expires) { is_expected.to be_nil }
|
|
80
105
|
end
|
|
81
106
|
end
|
|
82
107
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: middleman-s3_sync
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.
|
|
4
|
+
version: 4.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Frederic Jean
|
|
@@ -246,20 +246,6 @@ dependencies:
|
|
|
246
246
|
- - "~>"
|
|
247
247
|
- !ruby/object:Gem::Version
|
|
248
248
|
version: '3.12'
|
|
249
|
-
- !ruby/object:Gem::Dependency
|
|
250
|
-
name: timerizer
|
|
251
|
-
requirement: !ruby/object:Gem::Requirement
|
|
252
|
-
requirements:
|
|
253
|
-
- - "~>"
|
|
254
|
-
- !ruby/object:Gem::Version
|
|
255
|
-
version: '0.3'
|
|
256
|
-
type: :development
|
|
257
|
-
prerelease: false
|
|
258
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
259
|
-
requirements:
|
|
260
|
-
- - "~>"
|
|
261
|
-
- !ruby/object:Gem::Version
|
|
262
|
-
version: '0.3'
|
|
263
249
|
- !ruby/object:Gem::Dependency
|
|
264
250
|
name: webrick
|
|
265
251
|
requirement: !ruby/object:Gem::Requirement
|