heroku-rails-saas 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.
- data/CHANGELOG +39 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +46 -0
- data/LICENSE +65 -0
- data/README.md +211 -0
- data/Rakefile +43 -0
- data/TODO +0 -0
- data/heroku-rails.gemspec +38 -0
- data/lib/generators/heroku/config_generator.rb +19 -0
- data/lib/generators/templates/heroku.rake +33 -0
- data/lib/generators/templates/heroku.yml +52 -0
- data/lib/heroku-rails.rb +4 -0
- data/lib/heroku-rails/config.rb +146 -0
- data/lib/heroku-rails/hash_recursive_merge.rb +11 -0
- data/lib/heroku-rails/railtie.rb +8 -0
- data/lib/heroku-rails/runner.rb +278 -0
- data/lib/heroku/rails/tasks.rb +246 -0
- data/spec/fixtures/awesomeapp.yml +32 -0
- data/spec/fixtures/heroku-config.yml +16 -0
- data/spec/fixtures/mediocreapp.yml +14 -0
- data/spec/heroku/rails/heroku_config_spec.rb +157 -0
- data/spec/heroku/rails/heroku_runner_spec.rb +15 -0
- data/spec/spec_helper.rb +17 -0
- metadata +109 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
module Heroku
|
2
|
+
module Generators
|
3
|
+
class ConfigGenerator < ::Rails::Generators::Base
|
4
|
+
desc "Generates a Heroku Config file at config/heroku.yml"
|
5
|
+
|
6
|
+
def self.source_root
|
7
|
+
@_heroku_gen_source_root ||= File.expand_path("../../templates", __FILE__)
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_config_file
|
11
|
+
template 'heroku.yml', File.join('config', "heroku.yml")
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_rake_file
|
15
|
+
template 'heroku.rake', File.join('lib', 'tasks', "heroku.rake")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# ### Shortcuts: uncomment these for easier to type deployments
|
2
|
+
# ### e.g. rake deploy (instead of rake heroku:deploy)
|
3
|
+
# ###
|
4
|
+
# task :deploy => ["heroku:deploy"]
|
5
|
+
# task :console => ["heroku:console"]
|
6
|
+
# task :setup => ["heroku:setup"]
|
7
|
+
# task :logs => ["heroku:logs"]
|
8
|
+
# task :restart => ["heroku:restart"]
|
9
|
+
|
10
|
+
# Heroku Deploy Callbacks
|
11
|
+
namespace :heroku do
|
12
|
+
|
13
|
+
# runs before all the deploys complete
|
14
|
+
task :before_deploy do
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
# runs before each push to a particular heroku deploy environment
|
19
|
+
task :before_each_deploy, [:app_name] do |t,args|
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
# runs after each push to a particular heroku deploy environment
|
24
|
+
task :after_each_deploy, [:app_name] do |t,args|
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
# runs after all the deploys complete
|
29
|
+
task :after_deploy do
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# Configuration settings for specific apps and thier environments should be located here
|
2
|
+
# 'config/heroku/' and named appropiately they will be merged with the rest of the
|
3
|
+
# configuration settings
|
4
|
+
|
5
|
+
# The following is an example config file 'config/heroku/awesomeapp.yml'
|
6
|
+
# which map the apps and associated environments to your desired heroku app names
|
7
|
+
# for example,
|
8
|
+
# awesomeapp:staging
|
9
|
+
# would create the RACK_ENV=staging
|
10
|
+
# and deploy to http://awesomeapp-staging.heroku.com
|
11
|
+
|
12
|
+
# apps:
|
13
|
+
# production: awesomeapp
|
14
|
+
# staging: awesomeapp-staging
|
15
|
+
# legacy: awesomeapp-legacy
|
16
|
+
|
17
|
+
# stacks:
|
18
|
+
# bamboo-mri-1.9.2
|
19
|
+
|
20
|
+
# production:
|
21
|
+
# CONFIG_VAR1: "config1-production"
|
22
|
+
|
23
|
+
# collaborators
|
24
|
+
# - "awesomeapp@somedomain.com"
|
25
|
+
|
26
|
+
# domains:
|
27
|
+
# production:
|
28
|
+
# - "awesomeapp.com"
|
29
|
+
# - "www.awesomeapp.com"
|
30
|
+
|
31
|
+
# production:
|
32
|
+
# - ssl:piggyback
|
33
|
+
# - cron:daily
|
34
|
+
# - newrelic:bronze
|
35
|
+
|
36
|
+
|
37
|
+
# The following are configuration settings formally under the :all key
|
38
|
+
# for all apps and thier environments
|
39
|
+
config:
|
40
|
+
BUNDLE_WITHOUT: "test:development"
|
41
|
+
CONFIG_VAR1: "config1"
|
42
|
+
CONFIG_VAR2: "config2"
|
43
|
+
|
44
|
+
# Be sure to add yourself as a collaborator, otherwise your
|
45
|
+
# access to the app will be revoked.
|
46
|
+
collaborators:
|
47
|
+
- "my-heroku-email@somedomain.com"
|
48
|
+
- "another-heroku-email@somedomain.com"
|
49
|
+
|
50
|
+
addons:
|
51
|
+
- scheduler:standard
|
52
|
+
# add any other addons here
|
data/lib/heroku-rails.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module HerokuRails
|
4
|
+
class Config
|
5
|
+
|
6
|
+
SEPERATOR = ":"
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def root
|
10
|
+
@heroku_rails_root || ENV["RAILS_ROOT"] || "."
|
11
|
+
end
|
12
|
+
|
13
|
+
def root=(root)
|
14
|
+
@heroku_rails_root = root
|
15
|
+
end
|
16
|
+
|
17
|
+
def app_name(app, env)
|
18
|
+
"#{app}#{SEPERATOR}#{env}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def extract_environment_from(app_env)
|
22
|
+
name, env = app_env.split(SEPERATOR)
|
23
|
+
env
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_accessor :settings
|
28
|
+
|
29
|
+
def initialize(config_files)
|
30
|
+
self.settings = aggregate_heroku_configs(config_files)
|
31
|
+
end
|
32
|
+
|
33
|
+
def apps
|
34
|
+
self.settings['apps'] || []
|
35
|
+
end
|
36
|
+
|
37
|
+
def app_names
|
38
|
+
apps.keys
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns the app name on heroku froma string format like so: `app:env`
|
42
|
+
# Allows for `rake <app:env> [<app:env>] <command>`
|
43
|
+
def app_name_on_heroku(string)
|
44
|
+
app_name, env = string.split(SEPERATOR)
|
45
|
+
apps[app_name][env]
|
46
|
+
end
|
47
|
+
|
48
|
+
# return all enviromnets in this format app:env
|
49
|
+
def app_environments(env_filter="")
|
50
|
+
apps.each_with_object([]) do |(app, hsh), arr|
|
51
|
+
hsh.each { |env, app_name| arr << self.class.app_name(app, env) if (env_filter.nil? || env_filter.empty?) || env == env_filter }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# return all environments e.g. staging, production, development
|
56
|
+
def all_environments
|
57
|
+
environments = apps.each_with_object([]) do |(app, hsh), arr|
|
58
|
+
hsh.each { |env, app_name| arr << env }
|
59
|
+
end
|
60
|
+
environments.uniq
|
61
|
+
end
|
62
|
+
|
63
|
+
# return the stack setting for a particular app environment
|
64
|
+
def stack(app_env)
|
65
|
+
name, env = app_env.split(SEPERATOR)
|
66
|
+
stacks = self.settings['stacks'] || {}
|
67
|
+
(stacks[name] && stacks[name][env]) || stacks['all']
|
68
|
+
end
|
69
|
+
|
70
|
+
def cmd(app_env)
|
71
|
+
if self.stack(app_env) =~ /cedar/i
|
72
|
+
'heroku run '
|
73
|
+
else
|
74
|
+
'heroku '
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# pull out the config setting hash for a particular app environment
|
79
|
+
def config(app_env)
|
80
|
+
name, env = app_env.split(SEPERATOR)
|
81
|
+
config = self.settings['config'] || {}
|
82
|
+
all = config['all'] || {}
|
83
|
+
|
84
|
+
app_configs = (config[name] && config[name].reject { |k,v| v.class == Hash }) || {}
|
85
|
+
# overwrite app configs with the environment specific ones
|
86
|
+
merged_environment_configs = app_configs.merge((config[name] && config[name][env]) || {})
|
87
|
+
|
88
|
+
# overwrite all configs with the environment specific ones
|
89
|
+
all.merge(merged_environment_configs)
|
90
|
+
end
|
91
|
+
|
92
|
+
# return a list of domains for a particular app environment
|
93
|
+
def domains(app_env)
|
94
|
+
name, env = app_env.split(SEPERATOR)
|
95
|
+
domains = self.settings['domains'] || {}
|
96
|
+
(domains[name] && domains[name][env]) || []
|
97
|
+
end
|
98
|
+
# return a list of collaborators for a particular app environment
|
99
|
+
def collaborators(app_env)
|
100
|
+
app_setting_list('collaborators', app_env)
|
101
|
+
end
|
102
|
+
|
103
|
+
# return a list of addons for a particular app environment
|
104
|
+
def addons(app_env)
|
105
|
+
app_setting_list('addons', app_env)
|
106
|
+
end
|
107
|
+
|
108
|
+
protected
|
109
|
+
|
110
|
+
def app_setting_list(setting_key, app_env)
|
111
|
+
name, env = app_env.split(SEPERATOR)
|
112
|
+
setting = self.settings[setting_key] || {}
|
113
|
+
all = setting['all'] || []
|
114
|
+
|
115
|
+
# add in collaborators from app environment to the ones defined in all
|
116
|
+
(all + ((setting[name] && setting[name][env]) || [])).uniq
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def parse_yml(config_filepath, options)
|
122
|
+
if File.exists?(config_filepath)
|
123
|
+
config_hash = YAML.load(ERB.new(File.read(config_filepath)).result)
|
124
|
+
config_hash = add_all_namespace(config_hash) if options == :default
|
125
|
+
config_hash = add_app_namespace(File.basename(config_filepath, ".yml"), config_hash) if options == :apps
|
126
|
+
config_hash
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def add_all_namespace(hsh)
|
131
|
+
hsh.each_with_object({}) { |(k,v), h| h[k] = Hash["all" => v] }
|
132
|
+
end
|
133
|
+
|
134
|
+
def add_app_namespace(app_name, hsh)
|
135
|
+
hsh["apps"] = hsh.delete("env") if hsh.has_key?("env")
|
136
|
+
hsh.each_with_object({}) { |(k,v), h| h[k] = Hash[app_name => v] }
|
137
|
+
end
|
138
|
+
|
139
|
+
def aggregate_heroku_configs(config_files)
|
140
|
+
hsh = {}
|
141
|
+
config_files[:apps].each_with_object(hsh) { |file, h| h.rmerge!(parse_yml(file, :apps)) }
|
142
|
+
# overwrite all configs with the environment specific ones
|
143
|
+
hsh.rmerge!(parse_yml(config_files[:default], :default))
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,278 @@
|
|
1
|
+
require 'heroku/client'
|
2
|
+
|
3
|
+
module HerokuRails
|
4
|
+
class Runner
|
5
|
+
def initialize(config)
|
6
|
+
@config = config
|
7
|
+
@environments = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def authorize
|
11
|
+
@heroku ||= Heroku::Client.new(*Heroku::Auth.get_credentials)
|
12
|
+
end
|
13
|
+
|
14
|
+
# add a specific environment to the run list
|
15
|
+
def add_environment(env)
|
16
|
+
@environments << env
|
17
|
+
end
|
18
|
+
|
19
|
+
# use all environments or filter out production environments
|
20
|
+
def all_environments(filter=false)
|
21
|
+
@environments = @config.app_environments
|
22
|
+
filter ? @environments.reject! { |app| app[production_regex] } : @environments
|
23
|
+
end
|
24
|
+
|
25
|
+
# use all heroku apps filtered by environments
|
26
|
+
def environments(env)
|
27
|
+
@environments = @config.app_environments(env)
|
28
|
+
end
|
29
|
+
|
30
|
+
# setup apps (create if necessary)
|
31
|
+
def setup_apps
|
32
|
+
authorize unless @heroku
|
33
|
+
|
34
|
+
# get a list of all my current apps on Heroku (so we don't create dupes)
|
35
|
+
@my_apps = @heroku.list.map{|a| a.first}
|
36
|
+
|
37
|
+
each_heroku_app do |heroku_env, app_name, repo|
|
38
|
+
next if @my_apps.include?(app_name)
|
39
|
+
|
40
|
+
stack = @config.stack(heroku_env)
|
41
|
+
stack_option = " --stack #{stack}" if stack.to_s.size > 0
|
42
|
+
creation_command "heroku create #{app_name}#{stack_option} --remote #{app_name}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# setup the stacks for each app (migrating if necessary)
|
47
|
+
def setup_stacks
|
48
|
+
authorize unless @heroku
|
49
|
+
each_heroku_app do |heroku_env, app_name, repo|
|
50
|
+
# get the intended stack setting
|
51
|
+
stack = @config.stack(heroku_env)
|
52
|
+
|
53
|
+
# get the remote info about the app from heroku
|
54
|
+
heroku_app_info = @heroku.info(app_name) || {}
|
55
|
+
|
56
|
+
# if the stacks don't match, then perform a migration
|
57
|
+
if stack != heroku_app_info[:stack]
|
58
|
+
puts "Migrating the app: #{app_name} to the stack: #{stack}"
|
59
|
+
creation_command "heroku stack:migrate #{stack} --app #{app_name}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# setup the list of collaborators
|
65
|
+
def setup_collaborators
|
66
|
+
authorize unless @heroku
|
67
|
+
each_heroku_app do |heroku_env, app_name, repo|
|
68
|
+
# get the remote info about the app from heroku
|
69
|
+
heroku_app_info = @heroku.info(app_name) || {}
|
70
|
+
|
71
|
+
# get the intended list of collaborators to add
|
72
|
+
collaborator_emails = @config.collaborators(heroku_env)
|
73
|
+
|
74
|
+
# add current user to collaborator list (always)
|
75
|
+
collaborator_emails << @heroku.user unless collaborator_emails.include?(@heroku.user)
|
76
|
+
collaborator_emails << heroku_app_info[:owner] unless collaborator_emails.include?(heroku_app_info[:owner])
|
77
|
+
|
78
|
+
# get existing collaborators
|
79
|
+
existing_emails = heroku_app_info[:collaborators].to_a.map{|c| c[:email]}
|
80
|
+
|
81
|
+
# get the list of collaborators to delete
|
82
|
+
existing_emails.each do |existing_email|
|
83
|
+
# check to see if we need to delete this person
|
84
|
+
unless collaborator_emails.include?(existing_email)
|
85
|
+
# delete that collaborator if they arent on the approved list
|
86
|
+
destroy_command "heroku sharing:remove #{existing_email} --app #{app_name}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# get the list of collaborators to add
|
91
|
+
collaborator_emails.each do |collaborator_email|
|
92
|
+
# check to see if we need to add this person
|
93
|
+
unless existing_emails.include?(collaborator_email)
|
94
|
+
# add the collaborator if they are not already on the server
|
95
|
+
creation_command "heroku sharing:add #{collaborator_email} --app #{app_name}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# display the destructive commands
|
100
|
+
output_destroy_commands(app_name)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# setup configuration
|
105
|
+
def setup_config
|
106
|
+
authorize unless @heroku
|
107
|
+
each_heroku_app do |app_env, app_name, repo|
|
108
|
+
# get the configuration that we are aiming towards
|
109
|
+
new_config = @config.config(app_env)
|
110
|
+
|
111
|
+
# default RACK_ENV and RAILS_ENV to the heroku_env (unless its manually set to something else)
|
112
|
+
new_config["RACK_ENV"] = HerokuRails::Config.extract_environment_from(app_env) unless new_config["RACK_ENV"]
|
113
|
+
new_config["RAILS_ENV"] = HerokuRails::Config.extract_environment_from(app_env) unless new_config["RAILS_ENV"]
|
114
|
+
# get the existing config from heroku's servers
|
115
|
+
existing_config = @heroku.config_vars(app_name) || {}
|
116
|
+
|
117
|
+
# find the config variables to add
|
118
|
+
add_config = {}
|
119
|
+
new_config.each do |new_key, new_val|
|
120
|
+
add_config[new_key] = new_val unless existing_config[new_key] == new_val
|
121
|
+
end
|
122
|
+
|
123
|
+
# persist the changes onto heroku
|
124
|
+
unless add_config.empty?
|
125
|
+
# add the config
|
126
|
+
set_config = ""
|
127
|
+
add_config.each do |key, val|
|
128
|
+
set_config << "#{key}='#{val}' "
|
129
|
+
end
|
130
|
+
creation_command "heroku config:add #{set_config} --app #{app_name}"
|
131
|
+
system_with_echo("#{@config.cmd(app_env)} rails runner 'Rails.cache.clear' --app #{app_name}")
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# setup the addons for heroku
|
137
|
+
def setup_addons
|
138
|
+
authorize unless @heroku
|
139
|
+
each_heroku_app do |heroku_env, app_name, repo|
|
140
|
+
# get the addons that we are aiming towards
|
141
|
+
addons = @config.addons(heroku_env)
|
142
|
+
|
143
|
+
# get the addons that are already on the servers
|
144
|
+
existing_addons = (@heroku.installed_addons(app_name) || []).map{|a| a["name"]}
|
145
|
+
|
146
|
+
# all apps need the shared database
|
147
|
+
addons << "shared-database:5mb" unless addons.any? {|x| x[/heroku-postgresql|shared-database|heroku-shared-postgresql|amazon_rds/]}
|
148
|
+
|
149
|
+
# remove the addons that need to be removed
|
150
|
+
existing_addons.each do |existing_addon|
|
151
|
+
# check to see if we need to delete this addon
|
152
|
+
unless addons.include?(existing_addon)
|
153
|
+
# delete this addon if they arent on the approved list
|
154
|
+
destroy_command "heroku addons:remove #{existing_addon} --app #{app_name} --confirm #{app_name}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# add the addons that dont exist already
|
159
|
+
addons.each do |addon|
|
160
|
+
# check to see if we need to add this addon
|
161
|
+
unless existing_addons.include?(addon)
|
162
|
+
# add this addon if they are not already added
|
163
|
+
creation_command "heroku addons:add #{addon} --app #{app_name}"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
# display the destructive commands
|
168
|
+
output_destroy_commands(app_name)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# setup the domains for heroku
|
173
|
+
def setup_domains
|
174
|
+
authorize unless @heroku
|
175
|
+
each_heroku_app do |heroku_env, app_name, repo|
|
176
|
+
# get the domains that we are aiming towards
|
177
|
+
domains = @config.domains(heroku_env)
|
178
|
+
|
179
|
+
# get the domains that are already on the servers
|
180
|
+
existing_domains = (@heroku.list_domains(app_name) || []).map{|a| a[:domain]}
|
181
|
+
|
182
|
+
# remove the domains that need to be removed
|
183
|
+
existing_domains.each do |existing_domain|
|
184
|
+
# check to see if we need to delete this domain
|
185
|
+
unless domains.include?(existing_domain)
|
186
|
+
# delete this domain if they arent on the approved list
|
187
|
+
destroy_command "heroku domains:remove #{existing_domain} --app #{app_name}"
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# add the domains that dont exist already
|
192
|
+
domains.each do |domain|
|
193
|
+
# check to see if we need to add this domain
|
194
|
+
unless existing_domains.include?(domain)
|
195
|
+
# add this domain if they are not already added
|
196
|
+
creation_command "heroku domains:add #{domain} --app #{app_name}"
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# display the destructive commands
|
201
|
+
output_destroy_commands(app_name)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# cycles through each configured heroku app
|
206
|
+
# yields the environment name, the app name, and the repo url
|
207
|
+
def each_heroku_app
|
208
|
+
|
209
|
+
if @config.apps.size == 0
|
210
|
+
puts "\nNo heroku apps are configured. Run:
|
211
|
+
rails generate heroku:config\n\n"
|
212
|
+
puts "this will generate a default config/heroku.yml that you should edit"
|
213
|
+
puts "and then try running this command again"
|
214
|
+
|
215
|
+
exit(1)
|
216
|
+
end
|
217
|
+
|
218
|
+
if (@environments.nil? || @environments.empty?) && @config.apps.size == 1
|
219
|
+
@environments = [all_environments(true).try(:first)].compact
|
220
|
+
end
|
221
|
+
|
222
|
+
if @environments.present?
|
223
|
+
@environments.each do |env|
|
224
|
+
app_name = @config.app_name_on_heroku(env)
|
225
|
+
yield(env, app_name, "git@heroku.com:#{app_name}.git")
|
226
|
+
end
|
227
|
+
else
|
228
|
+
puts "\nYou must first specify at least one Heroku app:
|
229
|
+
rake <app>:<environment> [<app>:<environment>] <command>
|
230
|
+
rake awesomeapp:production restart
|
231
|
+
rake demo:staging deploy"
|
232
|
+
|
233
|
+
puts "\n\nYou can use also command all Heroku apps(except production environments) for this project:
|
234
|
+
rake all heroku:setup\n"
|
235
|
+
|
236
|
+
exit(1)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def system_with_echo(*args)
|
241
|
+
puts args.join(' ')
|
242
|
+
command(*args)
|
243
|
+
end
|
244
|
+
|
245
|
+
def creation_command(*args)
|
246
|
+
system_with_echo(*args)
|
247
|
+
end
|
248
|
+
|
249
|
+
def destroy_command(*args)
|
250
|
+
# puts args.join(' ')
|
251
|
+
@destroy_commands ||= []
|
252
|
+
@destroy_commands << args.join(' ')
|
253
|
+
end
|
254
|
+
|
255
|
+
def output_destroy_commands(app)
|
256
|
+
if @destroy_commands.try(:any?)
|
257
|
+
puts "The #{app} had a few things removed from the heroku.yml."
|
258
|
+
puts "If they are no longer neccessary, then run the following commands:\n\n"
|
259
|
+
@destroy_commands.each do |destroy_command|
|
260
|
+
puts destroy_command
|
261
|
+
end
|
262
|
+
puts "\n\nthese commands may cause data loss so make sure you know that these are necessary"
|
263
|
+
end
|
264
|
+
# clear destroy commands
|
265
|
+
@destroy_commands = []
|
266
|
+
end
|
267
|
+
|
268
|
+
def command(*args)
|
269
|
+
raise "*** command \"#{args.join ' '}\" failed" unless system(*args)
|
270
|
+
end
|
271
|
+
|
272
|
+
private
|
273
|
+
|
274
|
+
def production_regex
|
275
|
+
Regexp.new("#{@config.class::SEPERATOR}(production|prod|live)")
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|