momentum 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e6d9f5cfb124f1061f031e1830abf34dc1c9dab3
4
+ data.tar.gz: 85c8676d3ca113bda88117ec61d6eda40260316a
5
+ SHA512:
6
+ metadata.gz: 3a4991c287f2fe675ec3293040a2adf55260420d1c3ae3ed859f53be884b400572c0475facd367ef764c67d4b036ac6a997f038a9c705dcf3fa37db793732527
7
+ data.tar.gz: 0f99656306f1ce62477c222088d6cad42e4a0de76655ccab35f5fcd62fba1b3ebc679a5e36f2d833f175fa94fb5ecd8481eae6ce95bbcba1ab38bd3d5b00ff3c
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in momentum.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Artsy
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # Momentum
2
+
3
+ Shared utilities for managing and deploying OpsWorks apps at Artsy.
4
+
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile, probably in the `:development` group:
9
+
10
+ gem 'momentum', github: 'artsy/momentum', require: false
11
+
12
+ In your application's Rakefile, add this line above the `load_tasks` command:
13
+
14
+ begin
15
+ require 'momentum' # necessary b/c tasks from gems in :development group aren't loaded automatically
16
+ Momentum.configure do |conf|
17
+ conf[:app_base_name] = 'your_app_name'
18
+ end
19
+ rescue LoadError
20
+ # momentum should only be installed in development
21
+ end
22
+
23
+ And then execute:
24
+
25
+ $ bundle
26
+ $ gem install librarian-chef # ideally this would be in the bundle, but has conflicts
27
+ $ bundle exec rake momentum:init
28
+
29
+
30
+ ## Rake Tasks
31
+
32
+ This gem adds a few useful rake tasks to your project. In general, the `aws_id` and `aws_secret` arguments are taken from `AWS_ID` and `AWS_SECRET` ENV variables. The `to` argument can refer to an environment or developer (e.g., _joey_ in the case of _reflection-joey_, or _staging_ in the case of _gravity-staging_). It's assumed that this value can be appended to the `app_base_name` to form the stack name.
33
+
34
+ ### momentum:init
35
+
36
+ Initialize a default librarian-chef config.
37
+
38
+ ### ow:config[to,aws_id,aws_secret]
39
+
40
+ Print the custom configuration values for the given stack. E.g.:
41
+
42
+ bundle exec rake ow:config[joey]
43
+
44
+ ### ow:config:from_env[to,aws_id,aws_secret]
45
+
46
+ Add the given stack's custom configuration values to the current task's ENV. Can be prepended to other rake tasks that depend on the ENV, e.g.:
47
+
48
+ bundle exec rake ow:config:from_env[production] some:migration
49
+
50
+ ### ow:console[to,env,aws_id,aws_secret]
51
+
52
+ Start a rails console on the given remote OpsWorks stack. Chooses an instance of the _rails-app_ layer by default, or the configured `rails_console_layer` if provided. E.g.:
53
+
54
+ bundle exec rake ow:console[production]
55
+
56
+ For stacks with labels not matching the Rails environment (e.g., _reflection-joey_), provide a 2nd argument with the desired environment:
57
+
58
+ bundle exec rake ow:console[joey,staging]
59
+
60
+ ### ow:cookbooks:update[to,aws_id,aws_secret]
61
+
62
+ Zip, upload, and propagate custom cookbooks to the given stack. Or, more concisely:
63
+
64
+ bundle exec rake ow:cookbooks:update[staging]
65
+ # or just:
66
+ bundle exec rake ow:cookbooks:update:staging
67
+
68
+ ### ow:deploy[to,aws_id,aws_secret]
69
+
70
+ Trigger an OpsWorks deploy to the given stack. By default, deploys app to all running instances of the _rails-app_ layer, or the list configured in `app_layers`. E.g.:
71
+
72
+ bundle exec rake ow:deploy[staging]
73
+ # or just:
74
+ bundle exec rake ow:deploy:staging
75
+
76
+ ## Configuration:
77
+
78
+ * **app_base_name** - Your app's name. Stacks are assumed to be named like _appbasename-env_ (e.g., _gravity-staging_ or _reflection-joey_).
79
+ * **app_layers** - Array of OpsWorks layer names to which this rails app should be deployed. Default: `['rails-app']`
80
+ * **cookbooks_install_path** - Local path where librarian-chef will install cookbooks. Default: _tmp/cookbooks_
81
+ * **custom_cookbooks_bucket** - Bucket to which custom cookbooks are uploaded. Default: _artsy-cookbooks_
82
+ * **rails_console_layer** - The OpsWorks layer used for SSH-ing and starting a rails console. Default: _rails-app_
83
+
84
+
85
+ ## To Do
86
+
87
+ * git/branch helpers
88
+ * Integrate librarian-chef as legit dependency once rails/chef conflicts resolved
89
+
90
+
91
+ © 2014 [Artsy](http://artsy.net). See [LICENSE](LICENSE.txt) for details.
92
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,89 @@
1
+ module Momentum::OpsWorks
2
+
3
+ def self.client(aws_id, aws_secret)
4
+ raise "You must specify aws_id and aws_secret!" unless aws_id.present? && aws_secret.present?
5
+ require 'aws-sdk'
6
+ AWS::OpsWorks::Client.new(access_key_id: aws_id, secret_access_key: aws_secret)
7
+ end
8
+
9
+ def self.get_stack(client, stack_name)
10
+ client.describe_stacks[:stacks].detect { |k, v| k[:name] == stack_name }.tap do |stack|
11
+ raise "No #{stack_name} stack found!" unless stack
12
+ end
13
+ end
14
+
15
+ def self.get_app(client, stack, app_name)
16
+ client.describe_apps(stack_id: stack[:stack_id])[:apps].detect { |a| a[:name] == app_name }
17
+ end
18
+
19
+ def self.get_layers(client, stack, layer_names)
20
+ client.describe_layers(stack_id: stack[:stack_id])[:layers].select { |l| layer_names.include?(l[:shortname]) }
21
+ end
22
+
23
+ def self.get_online_instance_ids(client, query = {})
24
+ get_online_instances(client, query).map { |i| i[:instance_id] }
25
+ end
26
+
27
+ def self.get_online_instances(client, query = {})
28
+ client.describe_instances(query)[:instances].select { |i| i[:status] == 'online' }
29
+ end
30
+
31
+ class Config
32
+
33
+ def self.from_stack(client, stack_name, app_name = Momentum.config[:app_base_name])
34
+ @@configs ||= {}
35
+ @@configs[[stack_name, app_name]] ||= load_from_stack(client, stack_name, app_name)
36
+ end
37
+
38
+ private
39
+
40
+ def self.load_from_stack(client, stack_name, app_name)
41
+ stack = Momentum::OpsWorks.get_stack(client, stack_name)
42
+ JSON.parse(stack[:custom_json])["custom_env"][app_name].tap do |config|
43
+ # Custom config from OpsWorks doesn't include RAILS_ENV, so add it.
44
+ config['RAILS_ENV'] = Momentum::OpsWorks.get_app(client, stack, app_name)[:attributes]['RailsEnv']
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+
51
+ class Deployer
52
+ TIMEOUT = 15 * 60 # wait up to 15 minutes
53
+
54
+ def initialize(aws_id, aws_secret)
55
+ @ow = Momentum::OpsWorks.client(aws_id, aws_secret)
56
+ end
57
+
58
+ def deploy!(stack_name, app_name = Momentum.config[:app_base_name])
59
+ stack = Momentum::OpsWorks.get_stack(@ow, stack_name)
60
+ app = Momentum::OpsWorks.get_app(@ow, stack, app_name)
61
+ layers = Momentum::OpsWorks.get_layers(@ow, stack, Momentum.config[:app_layers])
62
+ instance_ids = layers.inject([]) { |ids, l| ids + Momentum::OpsWorks.get_online_instance_ids(@ow, layer_id: l[:layer_id]) }
63
+ raise 'No online instances found!' if instance_ids.empty?
64
+ @ow.create_deployment(
65
+ stack_id: stack[:stack_id],
66
+ app_id: app[:app_id],
67
+ command: { name: 'deploy' },
68
+ instance_ids: instance_ids
69
+ )
70
+ end
71
+
72
+ def wait_for_success!(deployment, timeout = TIMEOUT)
73
+ Timeout.timeout(timeout) do
74
+ status = @ow.describe_deployments(deployment_ids: [deployment[:deployment_id]])[:deployments].first[:status]
75
+ $stderr.puts 'Polling deploy status...'
76
+ while status == 'running'
77
+ sleep 10
78
+ status = @ow.describe_deployments(deployment_ids: [deployment[:deployment_id]])[:deployments].first[:status]
79
+ $stderr.print '.'
80
+ end
81
+ raise "Deploy failed (status: #{status})!" unless status == 'successful'
82
+ end
83
+ $stderr.puts 'Success!'
84
+ rescue Timeout::Error
85
+ raise "Timed out waiting for deploy to succeed after #{timeout} seconds."
86
+ end
87
+ end
88
+
89
+ end
@@ -0,0 +1,14 @@
1
+ class Momentum::Railtie < ::Rails::Railtie
2
+
3
+ railtie_name :momentum
4
+
5
+ rake_tasks do
6
+ load 'tasks/init.rake'
7
+ load 'tasks/librarian.rake'
8
+ load 'tasks/ow-config.rake'
9
+ load 'tasks/ow-console.rake'
10
+ load 'tasks/ow-cookbooks.rake'
11
+ load 'tasks/ow-deploy.rake'
12
+ end
13
+
14
+ end
@@ -0,0 +1,19 @@
1
+ # Helpers for rake tasks
2
+
3
+ def require_credentials!(args)
4
+ args.with_defaults aws_id: ENV['AWS_ID'], aws_secret: ENV['AWS_SECRET'], to: ENV['RAILS_ENV']
5
+ raise "Must specify target environment (e.g., staging)!" unless args[:to]
6
+ raise "Must set aws_id and aws_secret!" unless args[:aws_id] && args[:aws_secret]
7
+ end
8
+
9
+ def cookbooks_s3_key(to)
10
+ "#{stack_name(to)}.zip"
11
+ end
12
+
13
+ def stack_name(to)
14
+ "#{Momentum.config[:app_base_name]}-#{to}"
15
+ end
16
+
17
+ def cookbooks_zip
18
+ "#{Momentum.config[:cookbooks_install_path]}.zip"
19
+ end
@@ -0,0 +1,3 @@
1
+ module Momentum
2
+ VERSION = "0.0.3"
3
+ end
data/lib/momentum.rb ADDED
@@ -0,0 +1,21 @@
1
+ require "momentum/version"
2
+ require 'momentum/railtie' if defined?(::Rails)
3
+
4
+ module Momentum
5
+
6
+ DEFAULT_CONFIG = {
7
+ cookbooks_install_path: 'tmp/cookbooks',
8
+ custom_cookbooks_bucket: 'artsy-cookbooks',
9
+ rails_console_layer: 'rails-app',
10
+ app_layers: ['rails-app']
11
+ }
12
+
13
+ def self.config
14
+ @@config ||= DEFAULT_CONFIG.dup
15
+ end
16
+
17
+ def self.configure(&block)
18
+ yield self.config
19
+ end
20
+
21
+ end
@@ -0,0 +1,6 @@
1
+ namespace :momentum do
2
+
3
+ desc "Initialize a project with librarian-chef, etc."
4
+ task :init => ['librarian:config', 'librarian:init']
5
+
6
+ end
@@ -0,0 +1,28 @@
1
+ namespace :librarian do
2
+
3
+ LIBRARIAN_CONFIG = <<-EOF
4
+ ---
5
+ LIBRARIAN_CHEF_PATH: #{Momentum.config[:cookbooks_install_path]}
6
+ LIBRARIAN_CHEF_INSTALL__STRIP_DOT_GIT: '1'
7
+ EOF
8
+
9
+ task :config do
10
+ FileUtils.mkdir_p './.librarian/chef'
11
+ File.open('./.librarian/chef/config', 'w+') do |f|
12
+ f.write(LIBRARIAN_CONFIG)
13
+ end
14
+ $stderr.puts "Wrote .librarian/chef/config"
15
+ end
16
+
17
+ task :init => :require do
18
+ # librarian-chef and rails declare incompatible json dependencies,
19
+ # so librarian-chef must be installed but can't be in the bundle
20
+ Bundler.with_clean_env do
21
+ system "librarian-chef init"
22
+ end
23
+ end
24
+
25
+ task :require do
26
+ raise "librarian-chef must be installed!" if `which librarian-chef`.empty?
27
+ end
28
+ end
@@ -0,0 +1,26 @@
1
+ namespace :ow do
2
+
3
+ require 'momentum/tasks'
4
+
5
+ desc "Print current configuration values for given stack."
6
+ task :config, [:to, :aws_id, :aws_secret] do |t, args|
7
+ require_credentials!(args)
8
+ ow = Momentum::OpsWorks.client(args[:aws_id], args[:aws_secret])
9
+ Momentum::OpsWorks::Config.from_stack(ow, stack_name(args[:to])).each do |k, v|
10
+ puts "#{k}: #{v}"
11
+ end
12
+ end
13
+
14
+ namespace :config do
15
+ desc "Set configuration values from OpsWorks on the current environment. Can be chained to other tasks that need the ENV."
16
+ task :from_env, [:to, :aws_id, :aws_secret] do |t, args|
17
+ require_credentials!(args)
18
+ ow = Momentum::OpsWorks.client(args[:aws_id], args[:aws_secret])
19
+ Momentum::OpsWorks::Config.from_stack(ow, stack_name(args[:to])).each do |k, v|
20
+ ENV[k] = v.to_s
21
+ end
22
+ @ow_config_from_env = true # allow chained tasks to raise an error unless this is set
23
+ end
24
+ end
25
+
26
+ end
@@ -0,0 +1,26 @@
1
+ namespace :ow do
2
+
3
+ require 'momentum/opsworks'
4
+ require 'momentum/tasks'
5
+
6
+ desc "Open a Rails console on the given remote OpsWorks stack (uses AWS_USER as SSH username or falls back to local username)."
7
+ task :console, [:to, :env, :aws_id, :aws_secret] do |t, args|
8
+ require_credentials!(args)
9
+ ow = Momentum::OpsWorks.client(args[:aws_id], args[:aws_secret])
10
+ name = stack_name(args[:to])
11
+ stack = Momentum::OpsWorks.get_stack(ow, name)
12
+ layer = ow.describe_layers(stack_id: stack[:stack_id])[:layers].detect { |l| l[:shortname] == Momentum.config[:rails_console_layer] }
13
+ instance = Momentum::OpsWorks.get_online_instances(ow, layer_id: layer[:layer_id]).sample
14
+ raise "No online #{Momentum.config[:rails_console_layer]} instances found for #{name} stack!" unless instance
15
+
16
+ $stderr.puts "Starting remote console... (use Ctrl-D to exit cleanly)"
17
+ sh [
18
+ 'ssh -t',
19
+ (['-i', ENV['AWS_PUBLICKEY']] if ENV['AWS_PUBLICKEY']),
20
+ (['-l', ENV['AWS_USER']] if ENV['AWS_USER']),
21
+ instance[:public_dns],
22
+ "'sudo su deploy --session-command=\"cd /srv/www/#{Momentum.config[:app_base_name]}/current && RAILS_ENV=#{args[:env] || args[:to]} bundle exec rails console\"'"
23
+ ].compact.flatten.join(' ')
24
+ end
25
+
26
+ end
@@ -0,0 +1,66 @@
1
+ namespace :ow do
2
+ namespace :cookbooks do
3
+
4
+ require 'momentum/opsworks'
5
+ require 'momentum/tasks'
6
+
7
+ # TODO add dependency on librarian-chef once chef/json conflict resolved
8
+ # desc "Run librarian-chef install"
9
+ # task :install do
10
+ # `librarian-chef install`
11
+ # end
12
+
13
+ desc "Zip the #{Momentum.config[:cookbooks_install_path]} directory into #{Momentum.config[:cookbooks_install_path]}.zip"
14
+ task :zip do
15
+ raise "No cookbooks found at #{Momentum.config[:cookbooks_install_path]}! Run librarian-chef install." unless File.exists?(Momentum.config[:cookbooks_install_path])
16
+ dir = File.dirname(Momentum.config[:cookbooks_install_path])
17
+ base = File.basename(Momentum.config[:cookbooks_install_path])
18
+ system "rm -f #{cookbooks_zip} && pushd #{dir} && zip -r #{base} #{base} && popd"
19
+ $stderr.puts "Zipped cookbooks to #{cookbooks_zip}"
20
+ end
21
+
22
+ desc "Upload custom cookbooks from #{cookbooks_zip} to S3 (at bucket/appname-env.zip)."
23
+ task :upload, [:to, :aws_id, :aws_secret] => [:require_app_base_name] do |t, args|
24
+ require_credentials!(args)
25
+ require 'aws-sdk'
26
+ AWS.config(access_key_id: args[:aws_id], secret_access_key: args[:aws_secret])
27
+
28
+ key = cookbooks_s3_key(args[:to])
29
+ File.open(cookbooks_zip) do |zip|
30
+ AWS::S3.new.client.put_object bucket_name: Momentum.config[:custom_cookbooks_bucket], key: key, data: zip
31
+ end
32
+ $stderr.puts "Uploaded cookbooks.zip to #{Momentum.config[:custom_cookbooks_bucket]}/#{key}."
33
+ end
34
+
35
+ desc "Install, zip and upload custom cookbooks, then trigger update_custom_cookbooks command."
36
+ task :update, [:to, :aws_id, :aws_secret] => [:require_app_base_name, :zip, :upload] do |t, args|
37
+ require_credentials!(args)
38
+
39
+ ow = Momentum::OpsWorks.client(args[:aws_id], args[:aws_secret])
40
+ stack = Momentum::OpsWorks.get_stack(ow, stack_name(args[:to]))
41
+ instance_ids = Momentum::OpsWorks.get_online_instance_ids(ow, stack_id: stack[:stack_id])
42
+ if instance_ids.any?
43
+ ow.create_deployment(
44
+ stack_id: stack[:stack_id],
45
+ command: {name: 'update_custom_cookbooks'},
46
+ instance_ids: instance_ids
47
+ )
48
+ $stderr.puts "Triggered 'update_custom_cookbooks' command for #{stack[:name]}... (it might take a few moments)."
49
+ else
50
+ $stderr.puts "No online instances found."
51
+ end
52
+ end
53
+
54
+ namespace :update do
55
+ %w{staging production}.each do |env|
56
+ desc "Zip, upload, and propagate custom OpsWorks cookbooks to the #{env} stack."
57
+ task(env.to_sym) { Rake::Task['ow:cookbooks:update'].invoke(env) }
58
+ end
59
+ end
60
+
61
+ task :require_app_base_name do
62
+ raise "An app_base_name must be configured!" unless Momentum.config[:app_base_name]
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,21 @@
1
+ namespace :ow do
2
+
3
+ require 'momentum/tasks'
4
+
5
+ namespace :deploy do
6
+ %w{staging production}.each do |env|
7
+ desc "Deploy the #{Momentum.config[:app_base_name]} to the #{stack_name(env)} OpsWorks stack."
8
+ task(env.to_sym) { Rake::Task['ow:deploy'].invoke(env) }
9
+ end
10
+ end
11
+
12
+ desc "Deploy to the given OpsWorks stack."
13
+ task :deploy, [:to, :aws_id, :aws_secret] do |t, args|
14
+ require_credentials!(args)
15
+ deployer = Momentum::OpsWorks::Deployer.new(args[:aws_id], args[:aws_secret])
16
+ name = stack_name(args[:to])
17
+ deployment = deployer.deploy!(name)
18
+ $stderr.puts "Triggered deployment #{deployment[:deployment_id]} to #{name}..."
19
+ deployer.wait_for_success!(deployment)
20
+ end
21
+ end
data/momentum.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'momentum/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "momentum"
8
+ spec.version = Momentum::VERSION
9
+ spec.authors = ["Joey Aghion"]
10
+ spec.email = ["joey@aghion.com"]
11
+ spec.description = %q{Utilities for working with OpsWorks apps in the style of Artsy Engineering.}
12
+ spec.summary = %q{Utilities for working with OpsWorks apps in the style of Artsy Engineering.}
13
+ spec.homepage = "https://github.com/artsy/momentum"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "aws-sdk", "~> 1.30"
22
+ # spec.add_dependency "librarian-chef" # rails/chef require incompatible json versions
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: momentum
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Joey Aghion
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.30'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.30'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Utilities for working with OpsWorks apps in the style of Artsy Engineering.
56
+ email:
57
+ - joey@aghion.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - lib/momentum.rb
68
+ - lib/momentum/opsworks.rb
69
+ - lib/momentum/railtie.rb
70
+ - lib/momentum/tasks.rb
71
+ - lib/momentum/version.rb
72
+ - lib/tasks/init.rake
73
+ - lib/tasks/librarian.rake
74
+ - lib/tasks/ow-config.rake
75
+ - lib/tasks/ow-console.rake
76
+ - lib/tasks/ow-cookbooks.rake
77
+ - lib/tasks/ow-deploy.rake
78
+ - momentum.gemspec
79
+ homepage: https://github.com/artsy/momentum
80
+ licenses:
81
+ - MIT
82
+ metadata: {}
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.1.11
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: Utilities for working with OpsWorks apps in the style of Artsy Engineering.
103
+ test_files: []