middleman-cloudfront 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 007e6bd92ef3aa1bda2443a2bcb204ff9c629359
4
- data.tar.gz: bbdd3a6b015710a5da1cc00b8f4124645fa53449
2
+ SHA256:
3
+ metadata.gz: 45630e9002202a7bb7480ca73b84675937a5068864f7c238dd2c477899cf9184
4
+ data.tar.gz: 33c8b3c56d298a6f5ea6ff9c3382867b6e684d74617e1de255b90cb5b1744aa9
5
5
  SHA512:
6
- metadata.gz: c86faeaea4789c2962892e8d6ab4b227fc32b4696b3187b9b78dc26694de484b921cda7547a7bdafb1f93ba97d6f2aebef85fa5900409a875cc4b19855caaec1
7
- data.tar.gz: 368a02b61331f1b8f74264825674a3d6cd6f2a998c4521992f91d6d8dd8ba0f3f30df65f627506ee757bfd28efd48df33045e63934e327a13074473941c4a338
6
+ metadata.gz: a09550094d9d1bc154e36fc2ba60beede436c967c93e698f6bd2d99038dd1ea001825689d31e38b4b72cb61bc5869e97d2c8dfe0e644d48a7723753802a7e1d7
7
+ data.tar.gz: dac269c7465ae90b45767a485550906f72eaef4417bfe3fbb4c6f9658578e9cbe245700911ef2164af039c2ffd66fdfaf367451522e9d427702acdc89367f650
@@ -1,7 +1,9 @@
1
1
  language: ruby
2
+ sudo: false
3
+ cache: bundler
4
+ before_script:
5
+ - gem update --system
6
+ - gem update bundler
2
7
  rvm:
3
- - 1.9
4
- - 2.0
5
- - 2.1
6
- - 2.2
7
- - jruby
8
+ - 2.2.5
9
+ - 2.3.1
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Middleman CloudFront [![Build Status](https://travis-ci.org/andrusha/middleman-cloudfront.png)](https://travis-ci.org/andrusha/middleman-cloudfront) [![Dependency Status](https://gemnasium.com/andrusha/middleman-cloudfront.png)](https://gemnasium.com/andrusha/middleman-cloudfront) [![Code Climate](https://codeclimate.com/github/andrusha/middleman-cloudfront.png)](https://codeclimate.com/github/andrusha/middleman-cloudfront)
1
+ # Middleman CloudFront [![Build Status](https://travis-ci.org/andrusha/middleman-cloudfront.svg?branch=master)](https://travis-ci.org/andrusha/middleman-cloudfront) [![Dependency Status](https://gemnasium.com/andrusha/middleman-cloudfront.png)](https://gemnasium.com/andrusha/middleman-cloudfront) [![Code Climate](https://codeclimate.com/github/andrusha/middleman-cloudfront.png)](https://codeclimate.com/github/andrusha/middleman-cloudfront)
2
2
  A deploying tool for middleman which allows you to interact with Amazon CloudFront.
3
3
  Some of its features are:
4
4
 
@@ -115,3 +115,5 @@ after_s3_sync do |files_by_status|
115
115
  invalidate files_by_status[:updated]
116
116
  end
117
117
  ```
118
+
119
+ NOTE: The `after_s3_sync` hook only works with middleman-s3_sync v3.x and below. It has been [removed in v4.0](https://github.com/fredjean/middleman-s3_sync/blob/master/Changelog.md#v400).
data/Rakefile CHANGED
@@ -3,12 +3,6 @@ require 'rspec/core/rake_task'
3
3
  require 'bundler'
4
4
  Bundler::GemHelper.install_tasks
5
5
 
6
- require 'cucumber/rake/task'
7
-
8
- Cucumber::Rake::Task.new(:cucumber, 'Run features that should pass') do |t|
9
- t.cucumber_opts = "--color --tags ~@wip --strict --format #{ENV['CUCUMBER_FORMAT'] || 'Fivemat'}"
10
- end
11
-
12
6
  RSpec::Core::RakeTask.new(:spec)
13
7
 
14
8
  task :default => :spec
@@ -1,7 +1,4 @@
1
- require 'middleman-core'
2
- require 'middleman-cloudfront/commands'
1
+ require 'pathname' # for some reason, had to require this because middleman-core 4.1.7 did not.
2
+ require 'middleman-cloudfront/extension'
3
3
 
4
- ::Middleman::Extensions.register(:cloudfront, ">= 3.0.0") do
5
- require "middleman-cloudfront/extension"
6
- ::Middleman::CloudFront
7
- end
4
+ Middleman::Extensions.register :cloudfront, Middleman::CloudFront::Extension
@@ -0,0 +1,146 @@
1
+ require 'middleman-cli'
2
+ require 'middleman-cloudfront/extension'
3
+ require 'fog/aws'
4
+
5
+ module Middleman
6
+ module Cli
7
+ module CloudFront
8
+ # This class provides an "invalidate" command for the middleman CLI.
9
+ class Invalidate < ::Thor::Group
10
+ include Thor::Actions
11
+
12
+ INVALIDATION_LIMIT = 1000
13
+ INDEX_REGEX = /
14
+ \A
15
+ (.*\/)?
16
+ index\.html
17
+ \z
18
+ /ix
19
+
20
+ check_unknown_options!
21
+
22
+ def self.exit_on_failure?
23
+ true
24
+ end
25
+
26
+ def invalidate(options = nil, files = nil)
27
+
28
+ # If called via commandline, discover config (from bin/middleman)
29
+ if options.nil?
30
+ app = Middleman::Application.new do
31
+ config[:mode] = :config
32
+ config[:exit_before_ready] = true
33
+ config[:watcher_disable] = true
34
+ config[:disable_sitemap] = true
35
+ end
36
+
37
+ # Get the options from the cloudfront extension
38
+ extension = app.extensions[:cloudfront]
39
+ unless extension.nil?
40
+ options = extension.options
41
+ end
42
+ end
43
+
44
+ if options.nil?
45
+ configuration_usage
46
+ end
47
+
48
+ [:distribution_id, :filter].each do |key|
49
+ raise StandardError, "Configuration key #{key} is missing." if options.public_send(key).nil?
50
+ end
51
+
52
+ puts '## Invalidating files on CloudFront'
53
+
54
+ fog_options = {
55
+ :provider => 'AWS'
56
+ }
57
+
58
+ fog_options.merge!(
59
+ if options.access_key_id && options.secret_access_key
60
+ {
61
+ :aws_access_key_id => options.access_key_id,
62
+ :aws_secret_access_key => options.secret_access_key
63
+ }
64
+ else
65
+ { :use_iam_profile => true }
66
+ end
67
+ )
68
+
69
+ cdn = Fog::CDN.new(fog_options)
70
+
71
+ distribution = cdn.distributions.get(options.distribution_id)
72
+
73
+ raise StandardError, "Cannot access Distribution with id #{options.distribution_id}." if distribution.nil?
74
+
75
+
76
+ # CloudFront limits the amount of files which can be invalidated by one request to 1000.
77
+ # If there are more than 1000 files to invalidate, do so sequentially and wait until each validation is ready.
78
+ # If there are max 1000 files, create the invalidation and return immediately.
79
+ files = normalize_files(files || list_files(options.filter))
80
+ return if files.empty?
81
+
82
+ if files.count <= INVALIDATION_LIMIT
83
+ puts "Invalidating #{files.count} files. It might take 10 to 15 minutes until all files are invalidated."
84
+ puts 'Please check the AWS Management Console to see the status of the invalidation.'
85
+ invalidation = distribution.invalidations.create(:paths => files)
86
+ raise StandardError, %(Invalidation status is #{invalidation.status}. Expected "InProgress") unless invalidation.status == 'InProgress'
87
+ else
88
+ slices = files.each_slice(INVALIDATION_LIMIT)
89
+ puts "Invalidating #{files.count} files in #{slices.count} batch(es). It might take 10 to 15 minutes per batch until all files are invalidated."
90
+ slices.each_with_index do |slice, i|
91
+ puts "Invalidating batch #{i + 1}..."
92
+ invalidation = distribution.invalidations.create(:paths => slice)
93
+ invalidation.wait_for { ready? } unless i == slices.count - 1
94
+ end
95
+ end
96
+ end
97
+
98
+ protected
99
+
100
+ def configuration_usage
101
+ raise Error, <<-TEXT
102
+ ERROR: You need to activate the cloudfront extension in config.rb.
103
+
104
+ The example configuration is:
105
+ activate :cloudfront do |cf|
106
+ cf.access_key_id = 'I'
107
+ cf.secret_access_key = 'love'
108
+ cf.distribution_id = 'cats'
109
+ # cf.filter = /\.html/i # default /.*/
110
+ # cf.after_build = true # default is false
111
+ end
112
+ TEXT
113
+ end
114
+
115
+ def list_files(filter)
116
+ Dir.chdir('build/') do
117
+ Dir.glob('**/*', File::FNM_DOTMATCH).tap do |files|
118
+ # Remove directories
119
+ files.reject! { |f| File.directory?(f) }
120
+
121
+ # Remove files that do not match filter
122
+ files.reject! { |f| f !~ filter }
123
+ end
124
+ end
125
+ end
126
+
127
+ def normalize_files(files)
128
+ # Add directories since they have to be invalidated
129
+ # as well if :directory_indexes is active
130
+ files += files.grep(INDEX_REGEX).map do |file|
131
+ file == 'index.html' ? '/' : File.dirname(file) << '/'
132
+ end.uniq
133
+
134
+ # URI encode and add leading slash
135
+ files.map { |f| URI::encode(f.start_with?('/') ? f : "/#{f}") }
136
+ end
137
+
138
+ # Add to CLI
139
+ Base.register(self, 'invalidate', 'invalidate', 'Invalidate a cloudfront distribution.')
140
+
141
+ # Map "inv" to "invalidate"
142
+ Base.map('inv' => 'invalidate')
143
+ end
144
+ end
145
+ end
146
+ end
@@ -1,36 +1,31 @@
1
1
  require 'middleman-core'
2
+ require 'middleman-cloudfront/commands/invalidate'
2
3
 
3
4
  module Middleman
4
5
  module CloudFront
5
- class Options < Struct.new(:access_key_id, :secret_access_key, :distribution_id, :filter, :after_build); end
6
-
7
- class << self
8
- def options
9
- @@cloudfront_options
6
+ class Extension < Middleman::Extension
7
+ # @param [Symbol] key The name of the option
8
+ # @param [Object] default The default value for the option
9
+ # @param [String] description A human-readable description of what the option does
10
+ option :access_key_id, nil, 'Access key id'
11
+ option :secret_access_key, nil, 'Secret access key'
12
+ option :distribution_id, nil, 'Distribution id'
13
+ option :filter, /.*/, 'Filter files to be invalidated'
14
+ option :after_build, false, 'Invalidate after build'
15
+
16
+ def initialize(app, options_hash={}, &block)
17
+ super
10
18
  end
11
19
 
12
- def registered(app, options_hash = {}, &block)
13
- @@cloudfront_options = Options.new(options_hash)
14
- yield @@cloudfront_options if block_given?
15
-
16
- app.after_build do
17
- ::Middleman::Cli::CloudFront.new.invalidate(@@cloudfront_options) if @@cloudfront_options.after_build
18
- end
19
-
20
- app.send :include, Helpers
20
+ def after_build
21
+ Middleman::Cli::CloudFront::Invalidate.new.invalidate(options) if options.after_build
21
22
  end
22
- alias :included :registered
23
- end
24
23
 
25
- module Helpers
26
- def cloudfront_options
27
- ::Middleman::CloudFront.options
28
- end
29
-
30
- def invalidate(files = nil)
31
- ::Middleman::Cli::CloudFront.new.invalidate(cloudfront_options, files)
24
+ helpers do
25
+ def invalidate(files = nil)
26
+ Middleman::Cli::CloudFront::Invalidate.new.invalidate(options, files)
27
+ end
32
28
  end
33
29
  end
34
-
35
30
  end
36
31
  end
@@ -1,5 +1,5 @@
1
1
  module Middleman
2
2
  module CloudFront
3
- VERSION = '0.2.1'
3
+ VERSION = '0.3.0'
4
4
  end
5
5
  end
@@ -15,25 +15,16 @@ Gem::Specification.new do |s|
15
15
  s.summary = %q{Invalidate CloudFront cache after deployment to S3}
16
16
  s.description = %q{Adds ability to invalidate a specific set of files in your CloudFront cache}
17
17
 
18
- s.rubyforge_project = "middleman-cloudfront"
19
-
20
18
  s.files = `git ls-files -z`.split("\0")
21
19
  s.test_files = `git ls-files -z -- {fixtures,features}/*`.split("\0")
22
20
  s.require_paths = ["lib"]
23
21
 
24
- s.add_dependency 'fog', '~> 1.9'
22
+ s.required_ruby_version = '>= 2.0.0'
25
23
 
26
- s.add_development_dependency 'cucumber', '~> 1.3'
27
- s.add_development_dependency 'aruba', '~> 0.5'
28
- s.add_development_dependency 'fivemat', '~> 1.3'
29
- s.add_development_dependency 'simplecov', '~> 0.8'
30
24
  s.add_development_dependency 'rake', '>= 0.9.0'
31
25
  s.add_development_dependency 'rspec', '~> 3.0'
32
26
 
33
- if RUBY_VERSION <= '1.9.2'
34
- s.add_dependency 'middleman-core', '~> 3.0', '<= 3.2.0'
35
- s.add_development_dependency 'activesupport', '< 4.0.0'
36
- else
37
- s.add_dependency 'middleman-core', '~> 3.0'
38
- end
27
+ s.add_dependency 'fog-aws', '>= 0.1.1'
28
+ s.add_dependency 'middleman-core', '>= 3.0'
29
+ s.add_dependency 'middleman-cli', '>= 3.0'
39
30
  end
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+
3
+ require 'fog/aws/models/cdn/distributions'
4
+
5
+ describe Middleman::Cli::CloudFront::Invalidate do
6
+ INVALIDATION_LIMIT = Middleman::Cli::CloudFront::Invalidate::INVALIDATION_LIMIT
7
+ let(:cloudfront) { described_class.new }
8
+ let(:options) do
9
+ config = Middleman::Configuration::ConfigurationManager.new
10
+ config.access_key_id ='access_key_id_123'
11
+ config.secret_access_key = 'secret_access_key_123'
12
+ config.distribution_id = 'distribution_id_123'
13
+ config.filter = 'filter_123'
14
+ config.after_build = 'after_build_123'
15
+ config
16
+ end
17
+ let(:distribution) { double('distribution', invalidations: double('invalidations')) }
18
+
19
+ before do
20
+ allow_any_instance_of(Fog::CDN::AWS::Distributions).to receive(:get).and_return(distribution)
21
+ allow(distribution.invalidations).to receive(:create) do
22
+ double('invalidation', status: 'InProgress', wait_for: -> {})
23
+ end
24
+ end
25
+
26
+ it 'gets the correct distribution' do
27
+ allow(cloudfront).to receive(:list_files).and_return([])
28
+ expect_any_instance_of(Fog::CDN::AWS::Distributions).to receive(:get).with('distribution_id_123')
29
+ cloudfront.invalidate(options)
30
+ end
31
+
32
+ it 'normalizes paths' do
33
+ files = %w(file directory/index.html)
34
+ normalized_files = %w(/file /directory/index.html /directory/)
35
+ allow(cloudfront).to receive(:list_files).and_return(files)
36
+ expect(distribution.invalidations).to receive(:create).once.with(paths: normalized_files)
37
+ cloudfront.invalidate(options)
38
+ end
39
+
40
+ context 'when the amount of files to invalidate is under the limit' do
41
+ it 'divides them up in packages and creates one invalidation per package' do
42
+ files = (1..INVALIDATION_LIMIT).map { |i| "/file_#{i}" }
43
+ allow(cloudfront).to receive(:list_files).and_return(files)
44
+ expect(distribution.invalidations).to receive(:create).once.with(paths: files)
45
+ cloudfront.invalidate(options)
46
+ end
47
+ end
48
+
49
+ context 'when the amount of files to invalidate is over the limit' do
50
+ it 'creates only one invalidation with all of them' do
51
+ files = (1..(INVALIDATION_LIMIT * 3)).map { |i| "/file_#{i}" }
52
+ allow(cloudfront).to receive(:list_files).and_return(files)
53
+ expect(distribution.invalidations).to receive(:create).once.with(paths: files[0, INVALIDATION_LIMIT])
54
+ expect(distribution.invalidations).to receive(:create).once.with(paths: files[INVALIDATION_LIMIT, INVALIDATION_LIMIT])
55
+ expect(distribution.invalidations).to receive(:create).once.with(paths: files[INVALIDATION_LIMIT * 2, INVALIDATION_LIMIT])
56
+ cloudfront.invalidate(options)
57
+ end
58
+ end
59
+
60
+ context 'when files to invalidate are explicitly specified' do
61
+ it 'uses them instead of the files in the build directory' do
62
+ files = (1..3).map { |i| "/file_#{i}" }
63
+ expect(distribution.invalidations).to receive(:create).once.with(paths: files)
64
+ cloudfront.invalidate(options, files)
65
+ end
66
+
67
+ it "doesn't filter them" do
68
+ files = (1..3).map { |i| "/file_#{i}" }
69
+ options.filter = /filter that matches no files/
70
+ expect(distribution.invalidations).to receive(:create).once.with(paths: files)
71
+ cloudfront.invalidate(options, files)
72
+ end
73
+
74
+ it 'normalizes them' do
75
+ files = %w(file directory/index.html)
76
+ normalized_files = %w(/file /directory/index.html /directory/)
77
+ expect(distribution.invalidations).to receive(:create).once.with(paths: normalized_files)
78
+ cloudfront.invalidate(options, files)
79
+ end
80
+ end
81
+
82
+ context 'when the distribution_id is invalid' do
83
+ it 'it raise_error' do
84
+ #fog will return nil if the distribution_id is invalid
85
+ allow_any_instance_of(Fog::CDN::AWS::Distributions).to receive(:get).and_return(nil)
86
+ expect { cloudfront.invalidate(options) }.to raise_error(StandardError, "Cannot access Distribution with id distribution_id_123.")
87
+ end
88
+ end
89
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: middleman-cloudfront
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrey Korzhuev
@@ -9,118 +9,76 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-04-18 00:00:00.000000000 Z
12
+ date: 2017-12-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: fog
16
- requirement: !ruby/object:Gem::Requirement
17
- requirements:
18
- - - "~>"
19
- - !ruby/object:Gem::Version
20
- version: '1.9'
21
- type: :runtime
22
- prerelease: false
23
- version_requirements: !ruby/object:Gem::Requirement
24
- requirements:
25
- - - "~>"
26
- - !ruby/object:Gem::Version
27
- version: '1.9'
28
- - !ruby/object:Gem::Dependency
29
- name: cucumber
30
- requirement: !ruby/object:Gem::Requirement
31
- requirements:
32
- - - "~>"
33
- - !ruby/object:Gem::Version
34
- version: '1.3'
35
- type: :development
36
- prerelease: false
37
- version_requirements: !ruby/object:Gem::Requirement
38
- requirements:
39
- - - "~>"
40
- - !ruby/object:Gem::Version
41
- version: '1.3'
42
- - !ruby/object:Gem::Dependency
43
- name: aruba
44
- requirement: !ruby/object:Gem::Requirement
45
- requirements:
46
- - - "~>"
47
- - !ruby/object:Gem::Version
48
- version: '0.5'
49
- type: :development
50
- prerelease: false
51
- version_requirements: !ruby/object:Gem::Requirement
52
- requirements:
53
- - - "~>"
54
- - !ruby/object:Gem::Version
55
- version: '0.5'
56
- - !ruby/object:Gem::Dependency
57
- name: fivemat
15
+ name: rake
58
16
  requirement: !ruby/object:Gem::Requirement
59
17
  requirements:
60
- - - "~>"
18
+ - - ">="
61
19
  - !ruby/object:Gem::Version
62
- version: '1.3'
20
+ version: 0.9.0
63
21
  type: :development
64
22
  prerelease: false
65
23
  version_requirements: !ruby/object:Gem::Requirement
66
24
  requirements:
67
- - - "~>"
25
+ - - ">="
68
26
  - !ruby/object:Gem::Version
69
- version: '1.3'
27
+ version: 0.9.0
70
28
  - !ruby/object:Gem::Dependency
71
- name: simplecov
29
+ name: rspec
72
30
  requirement: !ruby/object:Gem::Requirement
73
31
  requirements:
74
32
  - - "~>"
75
33
  - !ruby/object:Gem::Version
76
- version: '0.8'
34
+ version: '3.0'
77
35
  type: :development
78
36
  prerelease: false
79
37
  version_requirements: !ruby/object:Gem::Requirement
80
38
  requirements:
81
39
  - - "~>"
82
40
  - !ruby/object:Gem::Version
83
- version: '0.8'
41
+ version: '3.0'
84
42
  - !ruby/object:Gem::Dependency
85
- name: rake
43
+ name: fog-aws
86
44
  requirement: !ruby/object:Gem::Requirement
87
45
  requirements:
88
46
  - - ">="
89
47
  - !ruby/object:Gem::Version
90
- version: 0.9.0
91
- type: :development
48
+ version: 0.1.1
49
+ type: :runtime
92
50
  prerelease: false
93
51
  version_requirements: !ruby/object:Gem::Requirement
94
52
  requirements:
95
53
  - - ">="
96
54
  - !ruby/object:Gem::Version
97
- version: 0.9.0
55
+ version: 0.1.1
98
56
  - !ruby/object:Gem::Dependency
99
- name: rspec
57
+ name: middleman-core
100
58
  requirement: !ruby/object:Gem::Requirement
101
59
  requirements:
102
- - - "~>"
60
+ - - ">="
103
61
  - !ruby/object:Gem::Version
104
62
  version: '3.0'
105
- type: :development
63
+ type: :runtime
106
64
  prerelease: false
107
65
  version_requirements: !ruby/object:Gem::Requirement
108
66
  requirements:
109
- - - "~>"
67
+ - - ">="
110
68
  - !ruby/object:Gem::Version
111
69
  version: '3.0'
112
70
  - !ruby/object:Gem::Dependency
113
- name: middleman-core
71
+ name: middleman-cli
114
72
  requirement: !ruby/object:Gem::Requirement
115
73
  requirements:
116
- - - "~>"
74
+ - - ">="
117
75
  - !ruby/object:Gem::Version
118
76
  version: '3.0'
119
77
  type: :runtime
120
78
  prerelease: false
121
79
  version_requirements: !ruby/object:Gem::Requirement
122
80
  requirements:
123
- - - "~>"
81
+ - - ">="
124
82
  - !ruby/object:Gem::Version
125
83
  version: '3.0'
126
84
  description: Adds ability to invalidate a specific set of files in your CloudFront
@@ -138,14 +96,13 @@ files:
138
96
  - LICENSE
139
97
  - README.md
140
98
  - Rakefile
141
- - features/support/env.rb
142
99
  - lib/middleman-cloudfront.rb
143
- - lib/middleman-cloudfront/commands.rb
100
+ - lib/middleman-cloudfront/commands/invalidate.rb
144
101
  - lib/middleman-cloudfront/extension.rb
145
102
  - lib/middleman-cloudfront/version.rb
146
103
  - lib/middleman_extension.rb
147
104
  - middleman-cloudfront.gemspec
148
- - spec/lib/middleman-cloudfront/commands_spec.rb
105
+ - spec/lib/middleman-cloudfront/invalidate_spec.rb
149
106
  - spec/spec_helper.rb
150
107
  homepage: https://github.com/andrusha/middleman-cloudfront
151
108
  licenses: []
@@ -158,18 +115,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
158
115
  requirements:
159
116
  - - ">="
160
117
  - !ruby/object:Gem::Version
161
- version: '0'
118
+ version: 2.0.0
162
119
  required_rubygems_version: !ruby/object:Gem::Requirement
163
120
  requirements:
164
121
  - - ">="
165
122
  - !ruby/object:Gem::Version
166
123
  version: '0'
167
124
  requirements: []
168
- rubyforge_project: middleman-cloudfront
169
- rubygems_version: 2.4.5
125
+ rubyforge_project:
126
+ rubygems_version: 2.7.4
170
127
  signing_key:
171
128
  specification_version: 4
172
129
  summary: Invalidate CloudFront cache after deployment to S3
173
- test_files:
174
- - features/support/env.rb
175
- has_rdoc:
130
+ test_files: []
@@ -1,6 +0,0 @@
1
- require "simplecov"
2
- SimpleCov.start
3
- PROJECT_ROOT_PATH = File.dirname(File.dirname(File.dirname(__FILE__)))
4
- require "middleman-core"
5
- require "middleman-core/step_definitions"
6
- require File.join(PROJECT_ROOT_PATH, 'lib', 'middleman-cloudfront')
@@ -1,122 +0,0 @@
1
- require "middleman-core/cli"
2
- require "middleman-cloudfront/extension"
3
- require "fog"
4
-
5
- module Middleman
6
- module Cli
7
-
8
- class CloudFront < Thor
9
- include Thor::Actions
10
-
11
- INVALIDATION_LIMIT = 1000
12
- INDEX_REGEX = /
13
- \A
14
- (.*\/)?
15
- index\.html
16
- \z
17
- /ix
18
-
19
- check_unknown_options!
20
-
21
- namespace :invalidate
22
-
23
- def self.exit_on_failure?
24
- true
25
- end
26
-
27
- desc "invalidate", "A way to deal with your CloudFront distributions"
28
- def invalidate(options = nil, files = nil)
29
- if options.nil?
30
- app_instance = ::Middleman::Application.server.inst
31
- unless app_instance.respond_to?(:cloudfront_options)
32
- raise Error, <<-TEXT
33
- ERROR: You need to activate the cloudfront extension in config.rb.
34
-
35
- The example configuration is:
36
- activate :cloudfront do |cf|
37
- cf.access_key_id = 'I'
38
- cf.secret_access_key = 'love'
39
- cf.distribution_id = 'cats'
40
- cf.filter = /\.html/i # default /.*/
41
- cf.after_build = true # default is false
42
- end
43
- TEXT
44
- end
45
- options = app_instance.cloudfront_options
46
- end
47
- options.filter ||= /.*/
48
- [:distribution_id, :filter].each do |key|
49
- raise StandardError, "Configuration key #{key} is missing." if options.public_send(key).nil?
50
- end
51
-
52
- puts "## Invalidating files on CloudFront"
53
-
54
- fog_options = {
55
- :provider => 'AWS'
56
- }
57
-
58
- if options.access_key_id && options.secret_access_key
59
- fog_options.merge!({
60
- :aws_access_key_id => options.access_key_id,
61
- :aws_secret_access_key => options.secret_access_key
62
- })
63
- else
64
- fog_options.merge!({:use_iam_profile => true})
65
- end
66
-
67
- cdn = Fog::CDN.new(fog_options)
68
-
69
- distribution = cdn.distributions.get(options.distribution_id)
70
-
71
- # CloudFront limits the amount of files which can be invalidated by one request to 1000.
72
- # If there are more than 1000 files to invalidate, do so sequentially and wait until each validation is ready.
73
- # If there are max 1000 files, create the invalidation and return immediately.
74
- files = normalize_files(files || list_files(options.filter))
75
- return if files.empty?
76
-
77
- if files.count <= INVALIDATION_LIMIT
78
- puts "Invalidating #{files.count} files. It might take 10 to 15 minutes until all files are invalidated."
79
- puts 'Please check the AWS Management Console to see the status of the invalidation.'
80
- invalidation = distribution.invalidations.create(:paths => files)
81
- raise StandardError, %(Invalidation status is #{invalidation.status}. Expected "InProgress") unless invalidation.status == 'InProgress'
82
- else
83
- slices = files.each_slice(INVALIDATION_LIMIT)
84
- puts "Invalidating #{files.count} files in #{slices.count} batch(es). It might take 10 to 15 minutes per batch until all files are invalidated."
85
- slices.each_with_index do |slice, i|
86
- puts "Invalidating batch #{i + 1}..."
87
- invalidation = distribution.invalidations.create(:paths => slice)
88
- invalidation.wait_for { ready? } unless i == slices.count - 1
89
- end
90
- end
91
- end
92
-
93
- protected
94
-
95
- def list_files(filter)
96
- Dir.chdir('build/') do
97
- Dir.glob('**/*', File::FNM_DOTMATCH).tap do |files|
98
- # Remove directories
99
- files.reject! { |f| File.directory?(f) }
100
-
101
- # Remove files that do not match filter
102
- files.reject! { |f| f !~ filter }
103
- end
104
- end
105
- end
106
-
107
- def normalize_files(files)
108
- # Add directories since they have to be invalidated
109
- # as well if :directory_indexes is active
110
- files += files.grep(INDEX_REGEX).map do |file|
111
- file == 'index.html' ? '/' : File.dirname(file) << '/'
112
- end.uniq
113
-
114
- # URI encode and add leading slash
115
- files.map { |f| URI::encode(f.start_with?('/') ? f : "/#{f}") }
116
- end
117
-
118
- end
119
-
120
- Base.map({"inv" => "invalidate"})
121
- end
122
- end
@@ -1,82 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'fog/aws/models/cdn/distributions'
4
-
5
- describe Middleman::Cli::CloudFront do
6
- let(:cloudfront) { described_class.new }
7
- let(:options) do
8
- Middleman::CloudFront::Options.new(
9
- 'access_key_id_123',
10
- 'secret_access_key_123',
11
- 'distribution_id_123',
12
- 'filter_123',
13
- 'after_build_123'
14
- )
15
- end
16
- let(:distribution) { double('distribution', invalidations: double('invalidations')) }
17
-
18
- describe '#invalidate' do
19
- before do
20
- allow_any_instance_of(Fog::CDN::AWS::Distributions).to receive(:get).and_return(distribution)
21
- allow(distribution.invalidations).to receive(:create) do
22
- double('invalidation', status: 'InProgress', wait_for: -> {})
23
- end
24
- end
25
-
26
- it 'gets the correct distribution' do
27
- allow(cloudfront).to receive(:list_files).and_return([])
28
- expect_any_instance_of(Fog::CDN::AWS::Distributions).to receive(:get).with('distribution_id_123')
29
- cloudfront.invalidate(options)
30
- end
31
-
32
- it 'normalizes paths' do
33
- files = %w(file directory/index.html)
34
- normalized_files = %w(/file /directory/index.html /directory/)
35
- allow(cloudfront).to receive(:list_files).and_return(files)
36
- expect(distribution.invalidations).to receive(:create).once.with(paths: normalized_files)
37
- cloudfront.invalidate(options)
38
- end
39
-
40
- context 'when the amount of files to invalidate is under the limit' do
41
- it 'divides them up in packages and creates one invalidation per package' do
42
- files = (1..Middleman::Cli::CloudFront::INVALIDATION_LIMIT).map { |i| "/file_#{i}" }
43
- allow(cloudfront).to receive(:list_files).and_return(files)
44
- expect(distribution.invalidations).to receive(:create).once.with(paths: files)
45
- cloudfront.invalidate(options)
46
- end
47
- end
48
-
49
- context 'when the amount of files to invalidate is over the limit' do
50
- it 'creates only one invalidation with all of them' do
51
- files = (1..(Middleman::Cli::CloudFront::INVALIDATION_LIMIT * 3)).map { |i| "/file_#{i}" }
52
- allow(cloudfront).to receive(:list_files).and_return(files)
53
- expect(distribution.invalidations).to receive(:create).once.with(paths: files[0, Middleman::Cli::CloudFront::INVALIDATION_LIMIT])
54
- expect(distribution.invalidations).to receive(:create).once.with(paths: files[Middleman::Cli::CloudFront::INVALIDATION_LIMIT, Middleman::Cli::CloudFront::INVALIDATION_LIMIT])
55
- expect(distribution.invalidations).to receive(:create).once.with(paths: files[Middleman::Cli::CloudFront::INVALIDATION_LIMIT * 2, Middleman::Cli::CloudFront::INVALIDATION_LIMIT])
56
- cloudfront.invalidate(options)
57
- end
58
- end
59
-
60
- context 'when files to invalidate are explicitly specified' do
61
- it 'uses them instead of the files in the build directory' do
62
- files = (1..3).map { |i| "/file_#{i}" }
63
- expect(distribution.invalidations).to receive(:create).once.with(paths: files)
64
- cloudfront.invalidate(options, files)
65
- end
66
-
67
- it "doesn't filter them" do
68
- files = (1..3).map { |i| "/file_#{i}" }
69
- options.filter = /filter that matches no files/
70
- expect(distribution.invalidations).to receive(:create).once.with(paths: files)
71
- cloudfront.invalidate(options, files)
72
- end
73
-
74
- it 'normalizes them' do
75
- files = %w(file directory/index.html)
76
- normalized_files = %w(/file /directory/index.html /directory/)
77
- expect(distribution.invalidations).to receive(:create).once.with(paths: normalized_files)
78
- cloudfront.invalidate(options, files)
79
- end
80
- end
81
- end
82
- end