dual_burner 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b12d52c907a72c8b457e012cd28033a272da5975
4
+ data.tar.gz: e46f66e90b6c1709d21a6726d2ea32ece06176c7
5
+ SHA512:
6
+ metadata.gz: c3d7ca6bad54f606ecd793a301e54a4967d5099a9fbfbd21bdea96bbbba7b73c4d7c1268a2f8942923575aaba8e5dc8aaa934c74a51f140b1278dddc236d34b5
7
+ data.tar.gz: 3ebc133f63dfb06afd11540936bf1a61bfcc0ec0a04494d78d0ba41e429198b1d5bd07e4735de63003c03954b8a9f9669704e163f37f9106011eee58b019ab03
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /**/Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /**/*.swp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,25 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.3
3
+ Include:
4
+ - Rakefile
5
+ Exclude:
6
+ - bin/**/*
7
+ - vendor/bundle/**/*
8
+
9
+ Metrics/AbcSize:
10
+ Max: 50
11
+
12
+ Metrics/LineLength:
13
+ Max: 120
14
+
15
+ Metrics/MethodLength:
16
+ Max: 20
17
+
18
+ Metrics/ParameterLists:
19
+ Max: 6
20
+
21
+ Style/Documentation:
22
+ Enabled: false
23
+
24
+ Style/SignalException:
25
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.3.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dual_burner.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,108 @@
1
+ # Dual Burner
2
+
3
+ Cause a two burner stove is better than one!
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'dual_burner', require: false
11
+ ```
12
+
13
+ Or to grab a particular branch:
14
+
15
+ ```ruby
16
+ gem 'dual_burner', git: 'git://github.com/blueapron/dual_burner.git', branch: 'something_neat'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ ```
22
+ $ bundle
23
+ ```
24
+
25
+ Or install it yourself as:
26
+
27
+ ```
28
+ $ gem install dual_burner
29
+ ```
30
+
31
+ ## Configuration
32
+
33
+ ### Dual Burner YML
34
+
35
+ The YML file manages the environment and clustering information.
36
+
37
+ ```
38
+ staging:
39
+ - remote_url: 'git@heroku.com:blueapron-alpha.git'
40
+ name: 'Alpha'
41
+ color: 'blue'
42
+ - remote_url: 'git@heroku.com:blueapron-alpha.git'
43
+ name: 'Bravo'
44
+ color: 'green'
45
+ production:
46
+ - remote_url: 'git@heroku.com:blueapron-api.git
47
+ name: 'API'
48
+ color: 'blue'
49
+ - remote_url: 'git@heroku.com:blueapron-admin.git'
50
+ name: 'Admin'
51
+ color: 'green'
52
+ - remote_url: 'git@heroku.com:blueapron-www.git'
53
+ name: 'WWW'
54
+ color: 'yellow'
55
+ ```
56
+
57
+ These are the possible configurations for your application.
58
+
59
+ | Key | Required | Use |
60
+ | ----------------|:-------------:| ----- |
61
+ | remote_url | yes | The git target for deploy and release information. |
62
+ | name | yes | The presentation name for the app. |
63
+ | color | no | The presentation color for display. |
64
+ | heroku_app_name | no | The heroku app name. Needed only for Heroku related commands i.e. `dual_burner config_set`. |
65
+
66
+ ## Deploying
67
+
68
+ Use the `dual_burner deploy` executable to deploy your projects.
69
+
70
+ Below are some examples.
71
+
72
+ #### Deploy of Master to Staging
73
+
74
+ `dual_burner deploy -e staging -g master`
75
+
76
+ #### Deploy of Master to Staging with Force
77
+
78
+ You can use a string for any git reference you would normally do.
79
+
80
+ `dual_burner deploy -e staging -g 'master --force'`
81
+
82
+ #### Deploy of Master to Staging from Different Configuration Files
83
+
84
+ You can pass in file locations of your deploy configuration if it is not under `/config`.
85
+
86
+ `dual_burner deploy -c config/dual_burner.yml -e staging -g master`
87
+
88
+ ## Latest Release
89
+
90
+ You can verify that all versions are consistent with the following command.
91
+
92
+ `dual_burner last_release --e wms_testing`
93
+
94
+ ## Heroku Config Management
95
+
96
+ You can set, unset, and verify consistency of Heroku configurations.
97
+
98
+ #### Set A Key For All Clusters
99
+
100
+ `dual_burner config_set -e wms_testing -k FOO -v BAR`
101
+
102
+ #### Ensure A Key Is The Same Across Clusters
103
+
104
+ `dual_burner config_get -e wms_testing -k FOO`
105
+
106
+ #### Remove A Key Across Clusters
107
+
108
+ `dual_burner config_unset -e wms_testing -k FOO`
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'dual_burner'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ require 'pry'
11
+ Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/circle.yml ADDED
@@ -0,0 +1,9 @@
1
+ machine:
2
+ ruby:
3
+ version: 2.1.6
4
+ dependencies:
5
+ pre:
6
+ - gem update bundler
7
+ test:
8
+ pre:
9
+ - bundle exec rubocop -D -fp -fh -o $CIRCLE_ARTIFACTS/rubocop.html
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dual_burner/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dual_burner"
8
+ spec.version = DualBurner::VERSION
9
+ spec.authors = ['Blue Apron Engineering']
10
+ spec.email = ['engineering@blueapron.com']
11
+
12
+ spec.summary = %q{Blue Apron Dual Burner}
13
+ spec.description = %q{A simply Ruby utility to push to many Heroku applications.}
14
+ spec.homepage = 'https://github.com/blueapron/dual_burner'
15
+
16
+ # Note: Files must be registered with git for things to package properly....
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = 'exe'
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_dependency 'colorize', '~> 0.7'
23
+ spec.add_dependency 'thor', '~> 0.19'
24
+
25
+ spec.add_development_dependency 'bundler', '~> 1.11'
26
+ spec.add_development_dependency 'rake', '~> 10.0'
27
+ spec.add_development_dependency 'rspec', '~> 3.0'
28
+ spec.add_development_dependency 'pry'
29
+ spec.add_development_dependency 'rubocop'
30
+ spec.add_development_dependency 'simplecov'
31
+ end
data/exe/dual_burner ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'thor'
4
+ require 'dual_burner'
5
+
6
+ DualBurner::Runner.start
@@ -0,0 +1,122 @@
1
+ require 'yaml'
2
+ require 'open3'
3
+
4
+ module DualBurner
5
+ class BaseCommand
6
+ attr_reader \
7
+ :configuration,
8
+ :env
9
+
10
+ def initialize(env:, configuration:)
11
+ @configuration = configuration
12
+ @env = env
13
+ end
14
+
15
+ protected
16
+
17
+ def apps
18
+ @apps ||= get_apps_for_environment
19
+ end
20
+
21
+ def get_apps_for_environment
22
+ raise ArgumentError, 'ENV IS NOT PRESENT!' if env.nil?
23
+ raise DualBurner::ConfigurationError, 'CONFIG IS NOT PRESENT!' unless File.exists?(configuration.deploy_file)
24
+ config = YAML.load(File.read(configuration.deploy_file))[env]
25
+ raise DualBurner::EnvironmentNotFoundError, "ENV #{env} NOT FOUND!" if config.nil?
26
+ config.map { |c| app_instance(c) }
27
+ end
28
+
29
+ def result_struct
30
+ Struct.new(:value, :lines, :app)
31
+ end
32
+
33
+ def result_instance
34
+ result_struct.new(-1, [], nil)
35
+ end
36
+
37
+ def app_struct
38
+ Struct.new(:remote_url, :name, :color, :heroku_app_name)
39
+ end
40
+
41
+ #
42
+ # Return a simple object-esque instance of App.
43
+ def app_instance(options)
44
+ app_struct.new(
45
+ options.fetch('remote_url'),
46
+ options.fetch('name'),
47
+ options.fetch('color', nil),
48
+ options.fetch('heroku_app_name', nil)
49
+ )
50
+ end
51
+
52
+ ##
53
+ # Determine of all processes return exit 0 status.
54
+ def all_processes_exit_0?(processes)
55
+ if processes.select { |p| p.exitstatus == 0 }.size == processes.size
56
+ true
57
+ else
58
+ false
59
+ end
60
+ end
61
+
62
+ ##
63
+ # Execute a command and capture the output.
64
+ #
65
+ # https://nickcharlton.net/posts/ruby-subprocesses-with-stdout-stderr-streams.html
66
+ def execute_command(command, app:, print_lines: true)
67
+ puts "#{app.name} #{Time.now} - executing command [#{command}]".send(app.color)
68
+
69
+ result = result_instance
70
+ Open3.popen2e(command) do |stdin, stdout_and_stderr, thread|
71
+ Thread.new do
72
+ until (raw_line = stdout_and_stderr.gets).nil? do
73
+ # There is a newline automatically appended from the stream.
74
+ print "#{app.name} #{Time.now} - #{raw_line}".send(app.color) if print_lines
75
+ result.lines << raw_line
76
+ end
77
+ end
78
+
79
+ # Return the value of the command line thread.
80
+ result.value = thread.value
81
+ result.app = app
82
+ end
83
+
84
+ result
85
+ end
86
+
87
+ ##
88
+ # Given an array of apps and values, determine if they are all consistent or not.
89
+ def verify_single_value(results:, context:)
90
+ # Yield to get the transformation to the value.
91
+ values = []
92
+ results.each do |result|
93
+ values << yield(result)
94
+ end
95
+
96
+ # We have different commit hashes, env variables, whatever, we need to warn.
97
+ if values.uniq.size > 1
98
+ puts "Inconsistent #{context} found!".red.blink
99
+ puts ""
100
+
101
+ results.each_with_index do |result, i|
102
+ print result.app.name.send(result.app.color)
103
+ print " is at #{context} "
104
+ print values[i].bold
105
+ puts ""
106
+ end
107
+
108
+ false
109
+ # Everything is fine!
110
+ elsif values.uniq.size == 1
111
+ puts ""
112
+ print "All apps "
113
+ print results.map { |r| r.app.name }.join(', ').bold
114
+ print " are on #{context} "
115
+ print values.first.green
116
+ puts ""
117
+
118
+ true
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,76 @@
1
+ module DualBurner
2
+ module Commands
3
+ class Deployer < DualBurner::BaseCommand
4
+ def deploy(git_reference: 'master')
5
+ # Need to handle the explicit passing of nil too....
6
+ if git_reference.nil? || git_reference.strip.empty?
7
+ git_reference = 'master'
8
+ end
9
+
10
+ challenge_user!(git_reference: git_reference) if configuration.interactive?
11
+
12
+ threads = []
13
+ results = []
14
+
15
+ apps.each do |app|
16
+ # Execute each command in a separate thread.
17
+ # Deploys can take a long time....
18
+ threads << Thread.new do
19
+ results << execute_command(
20
+ build_deploy_command(app: app, git_reference: git_reference),
21
+ app: app
22
+ )
23
+ end
24
+ end
25
+
26
+ # Wait for all commands to complete.
27
+ threads.map(&:join)
28
+
29
+ puts "Completed all deploys [#{threads.size}]!"
30
+
31
+ all_processes_exit_0?(results.map { |r| r.value })
32
+ end
33
+
34
+ def build_deploy_command(app:, git_reference:)
35
+ remote = app.remote_url
36
+ raise DualBurner::RemoteNotFoundException if remote.nil? || remote.strip.empty?
37
+ "git push #{remote} #{git_reference}"
38
+ end
39
+
40
+ ##
41
+ # Make sure the user knows what he/she is doing!
42
+ def challenge_user!(git_reference:)
43
+ # Show the user what Heroku apps are involved.
44
+ puts "\n"
45
+
46
+ print "You are about to deploy "
47
+ print git_reference.bold
48
+ print " to "
49
+ print env.bold
50
+ print " on the following Apps: "
51
+ print apps.map { |a| a.name }.join(', ').bold
52
+
53
+ puts "\n" * 2
54
+
55
+ # Show the user what we are about to do on their machine.
56
+ puts "These commands will be executed:"
57
+ apps.each do |app|
58
+ puts build_deploy_command(app: app, git_reference: git_reference).send(app.color).bold
59
+ end
60
+
61
+ puts "\n"
62
+
63
+ # Ensure the user really wants to don this (CSV importer looking at you!).
64
+ challenge = "#{env}_#{apps.size}"
65
+ puts "If this is ok, please type in the following: #{challenge}"
66
+ response = STDIN.gets.chomp
67
+ if challenge != response
68
+ puts "You didn't enter the right challenge. Aborting!".red.bold
69
+ exit(1)
70
+ else
71
+ puts "Preparing to deploy...."
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,39 @@
1
+ module DualBurner
2
+ module Commands
3
+ class HerokuConfig < DualBurner::BaseCommand
4
+ def get(key:)
5
+ results = execute_command_with_apps do |app|
6
+ "heroku config:get #{key} -a #{app.heroku_app_name}"
7
+ end
8
+
9
+ verify_single_value(results: results, context: 'ruby ENV') do |result|
10
+ result.lines.join
11
+ end
12
+ end
13
+
14
+ def set( key:, value:)
15
+ results = execute_command_with_apps do |app|
16
+ "heroku config:set #{key}=#{value} -a #{app.heroku_app_name}"
17
+ end
18
+ all_processes_exit_0?(results.map { |r| r.value })
19
+ end
20
+
21
+ def unset(key:)
22
+ results = execute_command_with_apps do |app|
23
+ "heroku config:unset #{key} -a #{app.heroku_app_name}"
24
+ end
25
+ all_processes_exit_0?(results.map { |r| r.value })
26
+ end
27
+
28
+ def execute_command_with_apps
29
+ results = []
30
+ apps.each do |app|
31
+ raise DualBurner::ConfigurationError, 'HEROKU APP NAME NOT CONFIGURED' if app.heroku_app_name.nil?
32
+ command = yield(app)
33
+ results << execute_command(command, app: app)
34
+ end
35
+ results
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,31 @@
1
+ module DualBurner
2
+ module Commands
3
+ class LastRelease < DualBurner::BaseCommand
4
+ def verify_apps
5
+ results = []
6
+ commit_hashes = []
7
+
8
+ apps.each do |app|
9
+ remote = app.remote_url
10
+ command = "git ls-remote #{remote} HEAD"
11
+ results << execute_command(
12
+ command,
13
+ app: app,
14
+ print_lines: false
15
+ )
16
+ end
17
+
18
+ verify_single_value(results: results, context: 'git commit') do |result|
19
+ get_commit_hash(content: result.lines.join)
20
+ end
21
+ end
22
+
23
+ def get_commit_hash(content:)
24
+ match = content.match(/^([A-Za-z0-9]+)(\s+)HEAD$/)
25
+ return nil if match.nil?
26
+
27
+ match.captures.first
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,17 @@
1
+ module DualBurner
2
+ class Configuration
3
+ ##
4
+ # The location of the deploy file.
5
+ attr_accessor :deploy_file
6
+
7
+ ##
8
+ # Enable or disable user interaction.
9
+ attr_accessor :interactive
10
+
11
+ alias_method :interactive?, :interactive
12
+
13
+ def initialize
14
+ @interactive = true
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,4 @@
1
+ module DualBurner
2
+ class ConfigurationError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DualBurner
2
+ class EnvironmentNotFoundError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,75 @@
1
+ require 'dual_burner'
2
+
3
+ module DualBurner
4
+ class Runner < Thor
5
+
6
+ ENV_DESC = 'The cluster environment.'.freeze unless defined?(ENV_DESC)
7
+ CONFIG_DESC = 'Your configuration file if not .config/dual_burner.yml'.freeze unless defined?(CONFIG_DESC)
8
+ HEROKU_KEY_DESC = 'The key to set on the Heroku app.'.freeze unless defined?(HEROKU_KEY_DESC)
9
+
10
+ desc 'last_release', 'Finds the HEAD git revision for all applications in cluster <ENV>.'
11
+ method_option :env, aliases: '-e', type: :string, required: true, desc: ENV_DESC
12
+ method_option :config, aliases: '-c', type: :string, optional: true, desc: CONFIG_DESC
13
+ def last_release
14
+ ::DualBurner::Commands::LastRelease.new(
15
+ env: options.fetch('env'),
16
+ configuration: get_configuration_instance(deploy_file: options['config'])
17
+ ).verify_apps ? exit(0) : exit(1)
18
+ end
19
+
20
+ desc 'deploy', 'Deploy <REF> to all applications in cluster <ENV>.'
21
+ method_option :env, aliases: '-e', type: :string, required: true, desc: ENV_DESC
22
+ method_option :config, aliases: '-c', type: :string, optional: true, desc: CONFIG_DESC
23
+ method_option :git_reference, aliases: '-g', default: 'master', type: :string, required: false, desc: 'The git reference to deploy.'
24
+ def deploy
25
+ ::DualBurner::Commands::Deployer.new(
26
+ env: options.fetch('env'),
27
+ configuration: get_configuration_instance(deploy_file: options['config'])
28
+ ).deploy(git_reference: options['git_reference']) ? exit(0) : exit(1)
29
+ end
30
+
31
+ desc 'config_set', 'Set <KEY> to <VALUE> for all Heroku appslocations in cluster <ENV>.'
32
+ method_option :env, aliases: '-e', type: :string, required: true, desc: ENV_DESC
33
+ method_option :config, aliases: '-c', type: :string, optional: true, desc: CONFIG_DESC
34
+ method_option :key, aliases: '-k', type: :string, required: true, desc: HEROKU_KEY_DESC
35
+ method_option :value, aliases: '-v', type: :string, required: true, desc: 'The value to set on the Heroku app.'
36
+ def config_set
37
+ ::DualBurner::Commands::HerokuConfig.new(
38
+ env: options.fetch('env'),
39
+ configuration: get_configuration_instance(deploy_file: options['config'])
40
+ ).set(key: options.fetch('key'), value: options['value']) ? exit(0) : exit(1)
41
+ end
42
+
43
+ desc 'config_get', 'Get <KEY> for all Heroku appslocations in cluster <ENV>.'
44
+ method_option :env, aliases: '-e', type: :string, required: true, desc: ENV_DESC
45
+ method_option :config, aliases: '-c', type: :string, optional: true, desc: CONFIG_DESC
46
+ method_option :key, aliases: '-k', type: :string, required: true, desc: HEROKU_KEY_DESC
47
+ def config_get
48
+ ::DualBurner::Commands::HerokuConfig.new(
49
+ env: options.fetch('env'),
50
+ configuration: get_configuration_instance(deploy_file: options['config'])
51
+ ).get(key: options.fetch('key')) ? exit(0) : exit(1)
52
+ end
53
+
54
+ desc 'config_unset', 'Unset <KEY> for all Heroku appslocations in cluster <ENV>.'
55
+ method_option :env, aliases: '-e', type: :string, required: true, desc: ENV_DESC
56
+ method_option :config, aliases: '-c', type: :string, optional: true, desc: CONFIG_DESC
57
+ method_option :key, aliases: '-k', type: :string, required: true, desc: HEROKU_KEY_DESC
58
+ def config_unset
59
+ ::DualBurner::Commands::HerokuConfig.new(
60
+ env: options.fetch('env'),
61
+ configuration: get_configuration_instance(deploy_file: options['config'])
62
+ ).unset(key: options.fetch('key')) ? exit(0) : exit(1)
63
+ end
64
+
65
+ protected
66
+
67
+ def get_configuration_instance(deploy_file: nil)
68
+ deploy_file ||= File.join(Dir.getwd, 'config', 'dual_burner.yml')
69
+
70
+ c = DualBurner::Configuration.new
71
+ c.deploy_file = deploy_file
72
+ c
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,3 @@
1
+ module DualBurner
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,11 @@
1
+ require 'thor'
2
+ require 'colorize'
3
+ require 'dual_burner/version'
4
+ require 'dual_burner/configuration'
5
+ require 'dual_burner/configuration_error'
6
+ require 'dual_burner/environment_not_found_error'
7
+ require 'dual_burner/base_command'
8
+ require 'dual_burner/commands/deployer'
9
+ require 'dual_burner/commands/heroku_config'
10
+ require 'dual_burner/commands/last_release'
11
+ require 'dual_burner/runner'
metadata ADDED
@@ -0,0 +1,178 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dual_burner
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Blue Apron Engineering
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-02-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: colorize
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.19'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.19'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.11'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.11'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: A simply Ruby utility to push to many Heroku applications.
126
+ email:
127
+ - engineering@blueapron.com
128
+ executables:
129
+ - dual_burner
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - ".gitignore"
134
+ - ".rspec"
135
+ - ".rubocop.yml"
136
+ - ".ruby-version"
137
+ - Gemfile
138
+ - README.md
139
+ - Rakefile
140
+ - bin/console
141
+ - bin/setup
142
+ - circle.yml
143
+ - dual_burner.gemspec
144
+ - exe/dual_burner
145
+ - lib/dual_burner.rb
146
+ - lib/dual_burner/base_command.rb
147
+ - lib/dual_burner/commands/deployer.rb
148
+ - lib/dual_burner/commands/heroku_config.rb
149
+ - lib/dual_burner/commands/last_release.rb
150
+ - lib/dual_burner/configuration.rb
151
+ - lib/dual_burner/configuration_error.rb
152
+ - lib/dual_burner/environment_not_found_error.rb
153
+ - lib/dual_burner/runner.rb
154
+ - lib/dual_burner/version.rb
155
+ homepage: https://github.com/blueapron/dual_burner
156
+ licenses: []
157
+ metadata: {}
158
+ post_install_message:
159
+ rdoc_options: []
160
+ require_paths:
161
+ - lib
162
+ required_ruby_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ required_rubygems_version: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ version: '0'
172
+ requirements: []
173
+ rubyforge_project:
174
+ rubygems_version: 2.5.1
175
+ signing_key:
176
+ specification_version: 4
177
+ summary: Blue Apron Dual Burner
178
+ test_files: []