├── .ruby-version ├── .ruby-gemset ├── .gitignore ├── lib ├── middleman-aws.rb └── middleman-aws │ └── tasks │ └── middleman-aws.rake ├── features └── support │ └── env.rb ├── Rakefile ├── Gemfile ├── LICENSE ├── samples ├── Gemfile └── config.rb ├── middleman-aws.gemspec └── README.md /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.2.2 2 | -------------------------------------------------------------------------------- /.ruby-gemset: -------------------------------------------------------------------------------- 1 | middleman-aws -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore bundler lock file 2 | /Gemfile.lock 3 | 4 | # Ignore pkg folder 5 | /pkg 6 | 7 | .idea -------------------------------------------------------------------------------- /lib/middleman-aws.rb: -------------------------------------------------------------------------------- 1 | 2 | 3 | if defined?(Rake) 4 | Rake.add_rakelib(File.expand_path('../middleman-aws/tasks', __FILE__)) 5 | end -------------------------------------------------------------------------------- /features/support/env.rb: -------------------------------------------------------------------------------- 1 | PROJECT_ROOT_PATH = File.dirname(File.dirname(File.dirname(__FILE__))) 2 | require 'middleman-core' 3 | require 'middleman-core/step_definitions' 4 | require File.join(PROJECT_ROOT_PATH, 'lib', 'middleman-aws') 5 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | # require 'bundler' 3 | # Bundler::GemHelper.install_tasks 4 | 5 | # require 'cucumber/rake/task' 6 | # 7 | # Cucumber::Rake::Task.new(:cucumber, 'Run features that should pass') do |t| 8 | # t.cucumber_opts = "--color --tags ~@wip --strict --format #{ENV['CUCUMBER_FORMAT'] || 'Fivemat'}" 9 | # end 10 | # 11 | # require 'rake/clean' 12 | # 13 | # task test: ['cucumber'] 14 | # 15 | # task default: :test 16 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # If you have OpenSSL installed, we recommend updating 2 | # the following line to use "https" 3 | source 'http://rubygems.org' 4 | 5 | # Specify your gem's dependencies in middleman-aws.gemspec 6 | gemspec 7 | 8 | # FIXME: temporary branch - move back to spec when PR is accepted 9 | gem 'middleman-cloudfront', 10 | #'>=4.0.0' waiting for release of PR https://github.com/andrusha/middleman-cloudfront/pull/23 11 | github: 'rosskevin/middleman-cloudfront', branch: 'middleman-4' 12 | #:path => '~/projects/middleman-cloudfront' 13 | 14 | group :development do 15 | gem 'rake' 16 | gem 'rdoc' 17 | gem 'yard' 18 | end 19 | 20 | group :test do 21 | gem 'cucumber' 22 | gem 'fivemat' 23 | gem 'aruba' 24 | gem 'rspec' 25 | end 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 AlienFast, LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /samples/Gemfile: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------ 2 | # Gemfile 3 | #------------------------------------------------------------------------ 4 | source 'http://rubygems.org' 5 | 6 | gem 'rake' 7 | gem 'middleman', '>= 4.0.0' 8 | gem 'middleman-livereload' 9 | gem 'middleman-search_engine_sitemap' 10 | 11 | 12 | #------------------------------------------------------------------------ 13 | # Deployment - requires additional configuration. See links below 14 | 15 | gem 'middleman-aws' # https://github.com/alienfast/middleman-aws 16 | 17 | 18 | # Even though already required by the middleman-aws gem, it appears middleman does not 19 | # pick up transitive dependency extensions early enough to avoid the 20 | # "== Unknown Extension:" error. Add these to your main project 21 | # (I wish this was unnecessary but don't know how to work around it) 22 | 23 | # https://github.com/fredjean/middleman-s3_sync 24 | gem 'middleman-s3_sync', '>=4.0.0' 25 | 26 | # https://github.com/andrusha/middleman-cloudfront 27 | gem 'middleman-cloudfront', 28 | #'>=4.0.0' waiting for release of PR https://github.com/andrusha/middleman-cloudfront/pull/23 29 | github: 'rosskevin/middleman-cloudfront', branch: 'middleman-4' 30 | 31 | #------------------------------------------------------------------------ 32 | # Other dependencies below here. 33 | -------------------------------------------------------------------------------- /middleman-aws.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path('../lib', __FILE__) 3 | 4 | Gem::Specification.new do |s| 5 | s.name = 'middleman-aws' 6 | s.version = '4.0.0' 7 | s.platform = Gem::Platform::RUBY 8 | 9 | s.authors = ['Kevin Ross'] 10 | s.email = ['kevin.ross@alienfast.com'] 11 | s.description = <<-TEXT 12 | Simple set of middleman rake tasks to build and deploy to AWS using s3_sync and cloudfront invalidation 13 | TEXT 14 | s.summary = <<-TEXT 15 | Simple set of middleman rake tasks to build and deploy to AWS using s3_sync and cloudfront invalidation 16 | TEXT 17 | s.homepage = 'https://github.com/alienfast/middleman-aws' 18 | s.license = 'MIT' 19 | 20 | s.files = `git ls-files`.split($/).reject { |f| f =~ /^samples\// } 21 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 22 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 23 | s.require_paths = ['lib'] 24 | 25 | # The version of middleman-core your extension depends on 26 | s.add_runtime_dependency 'middleman-core', ['>= 4.0.0'] 27 | 28 | s.add_dependency 'middleman-s3_sync', '>=4.0.0' # https://github.com/fredjean/middleman-s3_sync 29 | # s.add_dependency 'middleman-cloudfront', '>=4.0.0' # https://github.com/andrusha/middleman-cloudfront 30 | 31 | s.add_dependency 'rake' 32 | end 33 | -------------------------------------------------------------------------------- /lib/middleman-aws/tasks/middleman-aws.rake: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------ 2 | # Rakefile 3 | #------------------------------------------------------------------------ 4 | require 'yaml' 5 | require 'uri' 6 | 7 | namespace :mm do 8 | 9 | desc 'Remove all files in the build directory' 10 | task :clobber do |t, args| 11 | # kill the old package dir 12 | rm_r 'build' rescue nil 13 | end 14 | 15 | desc 'Compile all files into the build directory' 16 | task :build do 17 | puts '## Compiling static pages' 18 | status = system 'bundle exec middleman build' 19 | puts status ? 'Build successful.' : 'Build failed.' 20 | end 21 | 22 | desc 'Deploy to S3 and invalidate Cloudfront after a Git commit/push' 23 | task :deploy do 24 | 25 | puts '## Deploy starting...' 26 | cd 'build' do 27 | system 'git add -u' 28 | message = "Site updated at #{Time.now}" 29 | puts "## Commiting: #{message}" 30 | system "git commit -m \"#{message}\"" 31 | end 32 | 33 | aws_env = "AWS_ACCESS_KEY=#{credentials[:access_key_id]} AWS_SECRET=#{credentials[:secret_access_key]}" 34 | puts '## Syncing to S3...' 35 | system "#{aws_env} bundle exec middleman s3_sync" 36 | puts '## Invalidating cloudfront...' 37 | system "#{aws_env} bundle exec middleman invalidate" 38 | puts '## Deploy complete.' 39 | end 40 | 41 | desc 'One step clobber, build, deploy' 42 | task :publish => [:clobber, :build, :deploy] do 43 | end 44 | 45 | desc 'Serve the site' 46 | task :serve do 47 | system 'bundle exec middleman serve' 48 | end 49 | 50 | desc 'Show config' 51 | task :show_config do |t, args| 52 | 53 | puts "\n----------------------------------------------------------------------------------" 54 | puts 'Configuration:' 55 | puts "\t:working directory: #{Rake.original_dir}" 56 | puts "\t:project: #{project}" 57 | puts "\t:aws_secrets_file: #{aws_secrets_file}" 58 | puts "\t:access_key_id: #{credentials[:access_key_id]}" 59 | puts "----------------------------------------------------------------------------------\n" 60 | end 61 | 62 | def credentials 63 | unless File.exists?(aws_secrets_file) 64 | puts "\nWarning: Config file is missing: #{aws_secrets_file}.\nFile contents should look like:\naccess_key_id: XXXX\nsecret_access_key: XXXX\n\n." 65 | end 66 | 67 | # load from a user directory i.e. ~/.aws/acme.yml 68 | credentials = File.exists?(aws_secrets_file) ? YAML::load_file(aws_secrets_file) : {} 69 | 70 | access_key_id = credentials.fetch('access_key_id') { ENV['AWS_ACCESS_KEY_ID'] } 71 | secret_access_key = credentials.fetch('secret_access_key') { ENV['AWS_SECRET_ACCESS_KEY'] } 72 | 73 | { 74 | access_key_id: access_key_id, 75 | secret_access_key: secret_access_key 76 | } 77 | end 78 | 79 | def aws_secrets_file 80 | File.expand_path("~/.aws/#{project}.yml") 81 | end 82 | 83 | def project 84 | File.basename(Rake.original_dir) 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | middleman-aws 2 | ============= 3 | 4 | Simple set of [middleman](http://middlemanapp.com/) rake tasks to build and deploy to AWS using s3_sync and cloudfront invalidation. 5 | 6 | # Installation and Configuration 7 | 8 | ### Step 1: Add gems to the Gemfile 9 | 10 | See the [sample Gemfile](samples/Gemfile) for full configuration. 11 | 12 | ```ruby 13 | gem 'middleman-aws', '>=4.0.0' 14 | gem 'middleman-s3_sync', '>=4.0.0' 15 | gem 'middleman-cloudfront', 16 | #'>=4.0.0' waiting for release of PR https://github.com/andrusha/middleman-cloudfront/pull/23 17 | github: 'rosskevin/middleman-cloudfront', branch: 'middleman-4' 18 | ``` 19 | 20 | ### Step 2: Require this gem in the Rakefile 21 | 22 | require 'middleman-aws' 23 | 24 | ### Step 3: AWS credentials 25 | 26 | #### Option 1 - secrets file 27 | e.g. `~/.aws/acme.yml` 28 | 29 | This should contain the access and secret keys generated from the selected IAM user. This is the only file that will need to reside outside the repository. `acme` is equivalent to the directory name for your project. 30 | Don't worry, validation will make sure you have the path right. 31 | 32 | ```ruby 33 | access_key_id: XXXXXX 34 | secret_access_key: XXXXXX 35 | ``` 36 | 37 | #### Option 2 - ENV variables 38 | If you don't create secrets file, then environment variables `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` will be used. 39 | 40 | #### Option 3 - IAM 41 | If a secrets file is not present (option 1), there are no ENV variables (option 2), then request to AWS will fail (unless middleman-aws is used on EC2 instance with correct IAM role, then AWS will take care of authorising requests). 42 | 43 | ### Step 4: Add the necessary s3_sync and Cloudfront sections to your config 44 | See the [sample config.rb](samples/config.rb) for full configuration. Be sure to set the following variables: 45 | 46 | ```ruby 47 | #------------------------------------------------------------------------ 48 | # Configuration variables specific to each project 49 | #------------------------------------------------------------------------ 50 | SITE_NAME = 'AlienFast Acme' 51 | URL_ROOT = 'http://acme.alienfast.com' 52 | AWS_BUCKET = 'acme.alienfast.com' 53 | AWS_CLOUDFRONT_DISTRIBUTION_ID = 'xxxxxxxxxxxx' 54 | ``` 55 | 56 | # Usage 57 | Run the desired rake task. It's as simple as `rake mm:publish` in one step, or you can choose to do things one step at a time. 58 | See the available rake tasks below or run `rake -T` 59 | 60 | # Available Rake Tasks 61 | 62 | rake mm:build # Compile all files in the build directory 63 | rake mm:clobber # Remove all files in the build direcory 64 | rake mm:deploy # Deploy to S3 and invalidate Cloudfront after a Git commit/push 65 | rake mm:serve # Run the preview server at http://localhost:4567 66 | rake mm:publish # One step clobber, build, deploy 67 | rake mm:show_config # Show config 68 | 69 | # Real World Sample 70 | If you are just getting started with middleman and want to get a quick jumpstart on your `Gemfile` and `congfig.rb`, 71 | check out the source in the `samples` directory. 72 | 73 | ## Contributing 74 | 1. Fork it 75 | 2. Create your feature branch (`git checkout -b my-new-feature`) 76 | 3. Commit your changes (`git commit -am 'Add some feature'`) 77 | 4. Push to the branch (`git push origin my-new-feature`) 78 | 5. Create new Pull Request 79 | 80 | ## Copyright 81 | 82 | Copyright (c) 2014-2016 AlienFast, LLC. See MIT LICENSE.txt for further details. 83 | -------------------------------------------------------------------------------- /samples/config.rb: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------ 2 | # Typical custom configuration each project 3 | #------------------------------------------------------------------------ 4 | 5 | # Build config 6 | configure :build do 7 | # activate :minify_css 8 | # activate :minify_javascript 9 | # activate :asset_hash 10 | end 11 | 12 | # activate :external_pipeline, 13 | # name: :gulp, 14 | # command: build? ? './node_modules/gulp/bin/gulp.js' : './node_modules/gulp/bin/gulp.js default:watch', 15 | # source: 'dist' 16 | 17 | # Custom helpers 18 | # helpers do 19 | # def body_classes 20 | # "#{page_classes} #{data.page.bodyClasses}" 21 | # end 22 | # end 23 | 24 | #------------------------------------------------------------------------ 25 | # Configuration variables specific to each project 26 | #------------------------------------------------------------------------ 27 | SITE_NAME = 'AlienFast Acme' 28 | URL_ROOT = 'http://acme.alienfast.com' 29 | AWS_BUCKET = 'acme.alienfast.com' 30 | AWS_CLOUDFRONT_DISTRIBUTION_ID = 'xxxxxxxxxxxx' 31 | 32 | 33 | #------------------------------------------------------------------------ 34 | # Common configuration below here, should not need to be changed. 35 | #------------------------------------------------------------------------ 36 | 37 | 38 | # Sent in on CLI by rake task 39 | #------------------------------------------------------------------------ 40 | AWS_ACCESS_KEY = ENV['AWS_ACCESS_KEY'] 41 | AWS_SECRET = ENV['AWS_SECRET'] 42 | 43 | # Default layout 44 | page '/*', layout: 'application' 45 | 46 | # With no layout 47 | page '/*.xml', layout: false 48 | page '/*.json', layout: false 49 | page '/*.txt', layout: false 50 | 51 | # Reload the browser automatically whenever files change 52 | configure :development do 53 | activate :livereload, ignore: [ /.idea\// ] 54 | end 55 | 56 | activate :directory_indexes 57 | 58 | # # Use relative paths 59 | # activate :relative_assets 60 | # set :relative_links, true 61 | 62 | # Haml config 63 | set :haml, { :attr_wrapper => '"' } 64 | 65 | # https://github.com/Aupajo/middleman-search_engine_sitemap 66 | set :url_root, URL_ROOT 67 | activate :search_engine_sitemap 68 | 69 | # https://github.com/fredjean/middleman-s3_sync 70 | activate :s3_sync do |s3_sync| 71 | s3_sync.bucket = AWS_BUCKET # The name of the S3 bucket you are targeting. This is globally unique. 72 | # s3_sync.region = 'us-east-1' # The AWS region for your bucket. (S3 no longer requires this, dummy input?) 73 | s3_sync.aws_access_key_id = AWS_ACCESS_KEY 74 | s3_sync.aws_secret_access_key = AWS_SECRET 75 | s3_sync.delete = false # We delete stray files by default. 76 | # s3_sync.after_build = false # We do not chain after the build step by default. 77 | # s3_sync.prefer_gzip = true 78 | # s3_sync.path_style = true 79 | # s3_sync.reduced_redundancy_storage = false 80 | # s3_sync.acl = 'public-read' 81 | # s3_sync.encryption = false 82 | # s3_sync.prefix = '' 83 | # s3_sync.version_bucket = false 84 | end 85 | 86 | # https://github.com/andrusha/middleman-cloudfront 87 | activate :cloudfront do |cf| 88 | cf.access_key_id = AWS_ACCESS_KEY 89 | cf.secret_access_key = AWS_SECRET 90 | cf.distribution_id = AWS_CLOUDFRONT_DISTRIBUTION_ID 91 | # cf.filter = /\.html$/i 92 | end --------------------------------------------------------------------------------