momentum 0.0.3

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 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: []