engineyard 1.4.29 → 1.7.0.pre2
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/README.rdoc +139 -4
- data/bin/ey +1 -7
- data/lib/engineyard.rb +1 -22
- data/lib/engineyard/cli.rb +192 -94
- data/lib/engineyard/cli/#recipes.rb# +32 -0
- data/lib/engineyard/cli/api.rb +42 -28
- data/lib/engineyard/cli/recipes.rb +13 -6
- data/lib/engineyard/cli/ui.rb +103 -42
- data/lib/engineyard/cli/web.rb +16 -10
- data/lib/engineyard/config.rb +92 -18
- data/lib/engineyard/deploy_config.rb +66 -0
- data/lib/engineyard/deploy_config/migrate.rb +125 -0
- data/lib/engineyard/deploy_config/ref.rb +56 -0
- data/lib/engineyard/error.rb +38 -78
- data/lib/engineyard/repo.rb +75 -27
- data/lib/engineyard/serverside_runner.rb +133 -0
- data/lib/engineyard/thor.rb +110 -18
- data/lib/engineyard/version.rb +1 -1
- data/spec/engineyard/cli/api_spec.rb +10 -16
- data/spec/engineyard/cli_spec.rb +0 -11
- data/spec/engineyard/config_spec.rb +1 -8
- data/spec/engineyard/deploy_config_spec.rb +203 -0
- data/spec/engineyard/eyrc_spec.rb +2 -0
- data/spec/engineyard/repo_spec.rb +57 -34
- data/spec/ey/deploy_spec.rb +102 -52
- data/spec/ey/list_environments_spec.rb +69 -14
- data/spec/ey/login_spec.rb +11 -7
- data/spec/ey/logout_spec.rb +4 -4
- data/spec/ey/logs_spec.rb +6 -6
- data/spec/ey/recipes/apply_spec.rb +1 -1
- data/spec/ey/recipes/download_spec.rb +1 -1
- data/spec/ey/recipes/upload_spec.rb +6 -6
- data/spec/ey/rollback_spec.rb +3 -3
- data/spec/ey/ssh_spec.rb +9 -9
- data/spec/ey/status_spec.rb +2 -2
- data/spec/ey/whoami_spec.rb +9 -8
- data/spec/spec_helper.rb +18 -15
- data/spec/support/{fake_awsm.rb → git_repos.rb} +0 -14
- data/spec/support/helpers.rb +84 -28
- data/spec/support/matchers.rb +0 -16
- data/spec/support/shared_behavior.rb +83 -103
- metadata +65 -51
- data/lib/engineyard/api.rb +0 -117
- data/lib/engineyard/collection.rb +0 -7
- data/lib/engineyard/collection/abstract.rb +0 -71
- data/lib/engineyard/collection/apps.rb +0 -8
- data/lib/engineyard/collection/environments.rb +0 -8
- data/lib/engineyard/model.rb +0 -12
- data/lib/engineyard/model/account.rb +0 -8
- data/lib/engineyard/model/api_struct.rb +0 -33
- data/lib/engineyard/model/app.rb +0 -32
- data/lib/engineyard/model/deployment.rb +0 -90
- data/lib/engineyard/model/environment.rb +0 -194
- data/lib/engineyard/model/instance.rb +0 -166
- data/lib/engineyard/model/log.rb +0 -9
- data/lib/engineyard/model/user.rb +0 -6
- data/lib/engineyard/resolver.rb +0 -134
- data/lib/engineyard/rest_client_ext.rb +0 -9
- data/lib/engineyard/ruby_ext.rb +0 -9
- data/spec/engineyard/api_spec.rb +0 -39
- data/spec/engineyard/collection/apps_spec.rb +0 -16
- data/spec/engineyard/collection/environments_spec.rb +0 -16
- data/spec/engineyard/model/api_struct_spec.rb +0 -41
- data/spec/engineyard/model/environment_spec.rb +0 -198
- data/spec/engineyard/model/instance_spec.rb +0 -27
- data/spec/engineyard/resolver_spec.rb +0 -112
- data/spec/support/fake_awsm.ru +0 -245
- data/spec/support/scenarios.rb +0 -417
@@ -0,0 +1,32 @@
|
|
1
|
+
module EY
|
2
|
+
class CLI
|
3
|
+
class Recipes < EY::Thor
|
4
|
+
X1gx1GGG desc "recipes apply [ENVIRONMENT]", <<-DESC
|
5
|
+
Run uploaded chef recipes on specified environment.
|
6
|
+
|
7
|
+
This is similar to '#{banner_base} rebuild' except Engine Yard's main
|
8
|
+
configuration step is skipped.
|
9
|
+
DESC
|
10
|
+
|
11
|
+
def apply(name = nil)
|
12
|
+
environment = fetch_environment(name)
|
13
|
+
environment.run_custom_recipes
|
14
|
+
EY.ui.say "Uploaded recipes started for #{environment.name}"
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "recipes upload [ENVIRONMENT]", <<-DESC
|
18
|
+
Upload custom chef recipes to specified environment.
|
19
|
+
|
20
|
+
The current directory should contain a subdirectory named "cookbooks" to be
|
21
|
+
uploaded.
|
22
|
+
DESC
|
23
|
+
|
24
|
+
def upload(name = nil)
|
25
|
+
environment = fetch_environment(name)
|
26
|
+
environment.upload_recipes
|
27
|
+
EY.ui.say "Recipes uploaded successfully for #{environment.name}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/lib/engineyard/cli/api.rb
CHANGED
@@ -1,44 +1,58 @@
|
|
1
1
|
require 'highline'
|
2
|
-
require 'engineyard
|
2
|
+
require 'engineyard-cloud-client'
|
3
|
+
require 'engineyard/eyrc'
|
3
4
|
|
4
5
|
module EY
|
5
6
|
class CLI
|
6
|
-
class API
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
class API
|
8
|
+
def self.authenticate(ui)
|
9
|
+
ui.info("We need to fetch your API token; please log in.")
|
10
|
+
begin
|
11
|
+
email = ui.ask("Email: ")
|
12
|
+
password = ui.ask("Password: ", true)
|
13
|
+
token = EY::CloudClient.authenticate(email, password, ui)
|
14
|
+
EY::EYRC.load.api_token = token
|
15
|
+
token
|
16
|
+
rescue EY::CloudClient::InvalidCredentials
|
17
|
+
ui.warn "Invalid username or password; please try again."
|
18
|
+
retry
|
12
19
|
end
|
13
|
-
@token ||= EY::EYRC.load.api_token
|
14
|
-
@token ||= self.class.fetch_token
|
15
|
-
raise EY::Error, "Sorry, we couldn't get your API token." unless @token
|
16
20
|
end
|
17
21
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
attr_reader :token
|
23
|
+
|
24
|
+
def initialize(endpoint, ui)
|
25
|
+
@ui = ui
|
26
|
+
EY::CloudClient.endpoint = endpoint
|
27
|
+
|
28
|
+
@token = ENV['ENGINEYARD_API_TOKEN'] if ENV['ENGINEYARD_API_TOKEN']
|
29
|
+
@token ||= EY::EYRC.load.api_token
|
30
|
+
@token ||= self.class.authenticate(ui)
|
31
|
+
|
32
|
+
unless @token
|
33
|
+
raise EY::Error, "Sorry, we couldn't get your API token."
|
25
34
|
end
|
35
|
+
|
36
|
+
@api = EY::CloudClient.new(@token, @ui)
|
26
37
|
end
|
27
38
|
|
28
|
-
def
|
29
|
-
|
39
|
+
def respond_to?(*a)
|
40
|
+
super or @api.respond_to?(*a)
|
30
41
|
end
|
31
42
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
EY.ui.warn "Invalid username or password; please try again."
|
40
|
-
retry
|
43
|
+
protected
|
44
|
+
|
45
|
+
def method_missing(meth, *args, &block)
|
46
|
+
if @api.respond_to?(meth)
|
47
|
+
@api.send(meth, *args, &block)
|
48
|
+
else
|
49
|
+
super
|
41
50
|
end
|
51
|
+
rescue EY::CloudClient::InvalidCredentials
|
52
|
+
ui.warn "Authentication failed."
|
53
|
+
@token = self.class.authenticate(@ui)
|
54
|
+
@api = EY::CloudClient.new(@token, @ui)
|
55
|
+
retry
|
42
56
|
end
|
43
57
|
|
44
58
|
end
|
@@ -12,8 +12,10 @@ module EY
|
|
12
12
|
DESC
|
13
13
|
|
14
14
|
method_option :environment, :type => :string, :aliases => %w(-e),
|
15
|
+
:required => true, :default => '',
|
15
16
|
:desc => "Environment in which to apply recipes"
|
16
17
|
method_option :account, :type => :string, :aliases => %w(-c),
|
18
|
+
:required => true, :default => '',
|
17
19
|
:desc => "Name of the account in which the environment can be found"
|
18
20
|
def apply
|
19
21
|
environment = fetch_environment(options[:environment], options[:account])
|
@@ -35,12 +37,15 @@ module EY
|
|
35
37
|
DESC
|
36
38
|
|
37
39
|
method_option :environment, :type => :string, :aliases => %w(-e),
|
40
|
+
:required => true, :default => '',
|
38
41
|
:desc => "Environment that will receive the recipes"
|
39
42
|
method_option :account, :type => :string, :aliases => %w(-c),
|
43
|
+
:required => true, :default => '',
|
40
44
|
:desc => "Name of the account in which the environment can be found"
|
41
45
|
method_option :apply, :type => :boolean,
|
42
46
|
:desc => "Apply the recipes immediately after they are uploaded"
|
43
47
|
method_option :file, :type => :string, :aliases => %w(-f),
|
48
|
+
:required => true, :default => '',
|
44
49
|
:desc => "Specify a gzipped tar file (.tgz) for upload instead of cookbooks/ directory"
|
45
50
|
def upload
|
46
51
|
environment = fetch_environment(options[:environment], options[:account])
|
@@ -53,16 +58,16 @@ module EY
|
|
53
58
|
no_tasks do
|
54
59
|
def apply_recipes(environment)
|
55
60
|
environment.run_custom_recipes
|
56
|
-
|
61
|
+
ui.say "Uploaded recipes started for #{environment.name}"
|
57
62
|
end
|
58
63
|
|
59
64
|
def upload_recipes(environment, filename)
|
60
|
-
if
|
61
|
-
environment.upload_recipes_at_path(
|
62
|
-
|
65
|
+
if filename && filename != ''
|
66
|
+
environment.upload_recipes_at_path(filename)
|
67
|
+
ui.say "Recipes file #{filename} uploaded successfully for #{environment.name}"
|
63
68
|
else
|
64
69
|
environment.tar_and_upload_recipes_in_cookbooks_dir
|
65
|
-
|
70
|
+
ui.say "Recipes in cookbooks/ uploaded successfully for #{environment.name}"
|
66
71
|
end
|
67
72
|
end
|
68
73
|
end
|
@@ -76,13 +81,15 @@ module EY
|
|
76
81
|
If the cookbooks directory already exists, an error will be raised.
|
77
82
|
DESC
|
78
83
|
method_option :environment, :type => :string, :aliases => %w(-e),
|
84
|
+
:required => true, :default => '',
|
79
85
|
:desc => "Environment for which to download the recipes"
|
80
86
|
method_option :account, :type => :string, :aliases => %w(-c),
|
87
|
+
:required => true, :default => '',
|
81
88
|
:desc => "Name of the account in which the environment can be found"
|
82
89
|
def download
|
83
90
|
environment = fetch_environment(options[:environment], options[:account])
|
84
91
|
environment.download_recipes
|
85
|
-
|
92
|
+
ui.say "Recipes downloaded successfully for #{environment.name}"
|
86
93
|
end
|
87
94
|
|
88
95
|
end
|
data/lib/engineyard/cli/ui.rb
CHANGED
@@ -1,29 +1,84 @@
|
|
1
|
+
require 'highline'
|
2
|
+
|
1
3
|
module EY
|
2
4
|
class CLI
|
3
5
|
class UI < Thor::Base.shell
|
4
6
|
|
7
|
+
class Tee
|
8
|
+
def initialize(*ios)
|
9
|
+
@ios = ios
|
10
|
+
end
|
11
|
+
|
12
|
+
def <<(str)
|
13
|
+
@ios.each { |io| io << str }
|
14
|
+
self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
5
18
|
class Prompter
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
@answers << arg
|
10
|
-
end
|
11
|
-
def ask(*args, &block)
|
12
|
-
@questions ||= []
|
13
|
-
@questions << args.first
|
14
|
-
@answers.pop
|
15
|
-
end
|
16
|
-
attr_reader :questions
|
19
|
+
def self.add_answer(arg)
|
20
|
+
@answers ||= []
|
21
|
+
@answers << arg
|
17
22
|
end
|
23
|
+
|
24
|
+
def self.questions
|
25
|
+
@questions
|
26
|
+
end
|
27
|
+
|
18
28
|
def self.enable_mock!
|
19
|
-
@
|
29
|
+
@questions = []
|
30
|
+
@answers = []
|
31
|
+
@mock = true
|
20
32
|
end
|
21
|
-
|
22
|
-
|
23
|
-
@
|
33
|
+
|
34
|
+
def self.highline
|
35
|
+
@highline ||= HighLine.new($stdin)
|
24
36
|
end
|
25
|
-
|
26
|
-
|
37
|
+
|
38
|
+
def self.interactive?
|
39
|
+
@mock || ($stdin && $stdin.tty?)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.ask(question, password = false, default = nil)
|
43
|
+
if @mock
|
44
|
+
@questions ||= []
|
45
|
+
@questions << question
|
46
|
+
answer = @answers.shift
|
47
|
+
(answer == '' && default) ? default : answer
|
48
|
+
else
|
49
|
+
timeout_if_not_interactive do
|
50
|
+
highline.ask(question) do |q|
|
51
|
+
q.echo = "*" if password
|
52
|
+
q.default = default if default
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.agree(question, default)
|
59
|
+
if @mock
|
60
|
+
@questions ||= []
|
61
|
+
@questions << question
|
62
|
+
answer = @answers.shift
|
63
|
+
answer == '' ? default : %w[y yes].include?(answer)
|
64
|
+
else
|
65
|
+
timeout_if_not_interactive do
|
66
|
+
answer = highline.agree(question) {|q| q.default = default ? 'Y/n' : 'N/y' }
|
67
|
+
case answer
|
68
|
+
when 'Y/n' then true
|
69
|
+
when 'N/y' then false
|
70
|
+
else answer
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.timeout_if_not_interactive(&block)
|
77
|
+
if interactive?
|
78
|
+
block.call
|
79
|
+
else
|
80
|
+
Timeout.timeout(5, &block)
|
81
|
+
end
|
27
82
|
end
|
28
83
|
end
|
29
84
|
|
@@ -58,27 +113,27 @@ module EY
|
|
58
113
|
end
|
59
114
|
end
|
60
115
|
|
61
|
-
def
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
else
|
68
|
-
Prompter.ask(message) {|q| q.readline = true }
|
69
|
-
end
|
70
|
-
rescue EOFError
|
71
|
-
return ''
|
72
|
-
end
|
116
|
+
def interactive?
|
117
|
+
Prompter.interactive?
|
118
|
+
end
|
119
|
+
|
120
|
+
def agree(message, default)
|
121
|
+
Prompter.agree(message, default)
|
73
122
|
end
|
74
123
|
|
75
|
-
def
|
124
|
+
def ask(message, password = false, default = nil)
|
125
|
+
Prompter.ask(message, password, default)
|
126
|
+
rescue EOFError
|
127
|
+
return ''
|
128
|
+
end
|
129
|
+
|
130
|
+
def print_envs(apps, default_env_name = nil, simple = false, endpoint = 'https://cloud.engineyard.com')
|
76
131
|
if simple
|
77
132
|
envs = apps.map{ |app| app.environments.to_a }
|
78
133
|
puts envs.flatten.map{|env| env.name }.uniq
|
79
134
|
else
|
80
135
|
apps.each do |app|
|
81
|
-
puts "#{app.name}
|
136
|
+
puts "#{app.account.name}/#{app.name}"
|
82
137
|
if app.environments.any?
|
83
138
|
app.environments.each do |env|
|
84
139
|
short_name = env.shorten_name_for(app)
|
@@ -91,7 +146,7 @@ module EY
|
|
91
146
|
puts " #{short_name}#{default_text} (#{icount} #{iname})"
|
92
147
|
end
|
93
148
|
else
|
94
|
-
puts " (This application is not in any environments; you can make one at #{
|
149
|
+
puts " (This application is not in any environments; you can make one at #{endpoint})"
|
95
150
|
end
|
96
151
|
|
97
152
|
puts ""
|
@@ -100,27 +155,25 @@ module EY
|
|
100
155
|
end
|
101
156
|
|
102
157
|
def show_deployment(dep)
|
103
|
-
puts "# Status of last deployment of #{dep.app.account.name}/#{dep.app.name}/#{dep.environment.name}:"
|
104
|
-
puts "#"
|
105
|
-
|
106
158
|
output = []
|
107
159
|
output << ["Account", dep.app.account.name]
|
108
160
|
output << ["Application", dep.app.name]
|
109
161
|
output << ["Environment", dep.environment.name]
|
110
162
|
output << ["Input Ref", dep.ref]
|
111
|
-
output << ["Resolved Ref", dep.
|
112
|
-
output << ["Commit", dep.commit || '(
|
163
|
+
output << ["Resolved Ref", dep.resolved_ref]
|
164
|
+
output << ["Commit", dep.commit || '(not resolved)']
|
113
165
|
output << ["Migrate", dep.migrate]
|
114
166
|
output << ["Migrate command", dep.migrate_command] if dep.migrate
|
115
|
-
output << ["Deployed by", dep.
|
116
|
-
output << ["
|
117
|
-
output << ["Finished at", dep.finished_at]
|
167
|
+
output << ["Deployed by", dep.deployed_by]
|
168
|
+
output << ["Started at", dep.created_at] if dep.created_at
|
169
|
+
output << ["Finished at", dep.finished_at] if dep.finished_at
|
118
170
|
|
119
171
|
output.each do |att, val|
|
120
|
-
puts "#\t%-
|
172
|
+
puts "#\t%-16s %s" % ["#{att}:", val.to_s]
|
121
173
|
end
|
122
|
-
|
174
|
+
end
|
123
175
|
|
176
|
+
def deployment_result(dep)
|
124
177
|
if dep.successful?
|
125
178
|
info 'This deployment was successful.'
|
126
179
|
elsif dep.finished_at.nil?
|
@@ -153,6 +206,14 @@ module EY
|
|
153
206
|
($stdout.tty? || ENV['THOR_SHELL']) ? super : string
|
154
207
|
end
|
155
208
|
|
209
|
+
def err
|
210
|
+
$stderr
|
211
|
+
end
|
212
|
+
|
213
|
+
def out
|
214
|
+
$stdout
|
215
|
+
end
|
216
|
+
|
156
217
|
end
|
157
218
|
end
|
158
219
|
end
|
data/lib/engineyard/cli/web.rb
CHANGED
@@ -4,17 +4,20 @@ module EY
|
|
4
4
|
desc "enable [--environment/-e ENVIRONMENT]",
|
5
5
|
"Remove the maintenance page for this application in the given environment."
|
6
6
|
method_option :environment, :type => :string, :aliases => %w(-e),
|
7
|
+
:required => true, :default => '',
|
7
8
|
:desc => "Environment on which to take down the maintenance page"
|
8
9
|
method_option :app, :type => :string, :aliases => %w(-a),
|
10
|
+
:required => true, :default => '',
|
9
11
|
:desc => "Name of the application whose maintenance page will be removed"
|
10
|
-
method_option :verbose, :type => :boolean, :aliases => %w(-v),
|
11
|
-
:desc => "Be verbose"
|
12
12
|
method_option :account, :type => :string, :aliases => %w(-c),
|
13
|
+
:required => true, :default => '',
|
13
14
|
:desc => "Name of the account in which the environment can be found"
|
15
|
+
method_option :verbose, :type => :boolean, :aliases => %w(-v),
|
16
|
+
:desc => "Be verbose"
|
14
17
|
def enable
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
+
app_env = fetch_app_environment(options[:app], options[:environment], options[:account])
|
19
|
+
ui.info "Taking down maintenance page for '#{app_env.app.name}' in '#{app_env.environment.name}'"
|
20
|
+
serverside_runner(app_env, options[:verbose]).take_down_maintenance_page.call(ui.out, ui.err)
|
18
21
|
end
|
19
22
|
|
20
23
|
desc "disable [--environment/-e ENVIRONMENT]",
|
@@ -31,17 +34,20 @@ module EY
|
|
31
34
|
* public/system/maintenance.html.default
|
32
35
|
DESC
|
33
36
|
method_option :environment, :type => :string, :aliases => %w(-e),
|
37
|
+
:required => true, :default => '',
|
34
38
|
:desc => "Environment on which to put up the maintenance page"
|
35
39
|
method_option :app, :type => :string, :aliases => %w(-a),
|
40
|
+
:required => true, :default => '',
|
36
41
|
:desc => "Name of the application whose maintenance page will be put up"
|
37
|
-
method_option :verbose, :type => :boolean, :aliases => %w(-v),
|
38
|
-
:desc => "Be verbose"
|
39
42
|
method_option :account, :type => :string, :aliases => %w(-c),
|
43
|
+
:required => true, :default => '',
|
40
44
|
:desc => "Name of the account in which the environment can be found"
|
45
|
+
method_option :verbose, :type => :boolean, :aliases => %w(-v),
|
46
|
+
:desc => "Be verbose"
|
41
47
|
def disable
|
42
|
-
|
43
|
-
|
44
|
-
|
48
|
+
app_env = fetch_app_environment(options[:app], options[:environment], options[:account])
|
49
|
+
ui.info "Putting up maintenance page for '#{app_env.app.name}' in '#{app_env.environment.name}'"
|
50
|
+
serverside_runner(app_env, options[:verbose]).put_up_maintenance_page.call(ui.out, ui.err)
|
45
51
|
end
|
46
52
|
end
|
47
53
|
end
|
data/lib/engineyard/config.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
require 'uri'
|
2
|
+
require 'yaml'
|
2
3
|
require 'engineyard/error'
|
3
4
|
|
4
5
|
module EY
|
5
6
|
class Config
|
6
|
-
CONFIG_FILES = ["config/ey.yml", "ey.yml"]
|
7
|
+
CONFIG_FILES = ["config/ey.yml", "ey.yml"].map {|path| Pathname.new(path)}.freeze
|
8
|
+
|
9
|
+
attr_reader :path
|
7
10
|
|
8
11
|
def initialize(file = nil)
|
9
|
-
|
10
|
-
@
|
11
|
-
@config
|
12
|
-
@config["environments"] = {} unless @config["environments"]
|
12
|
+
@path = file || CONFIG_FILES.find{|pathname| pathname.exist? }
|
13
|
+
@config = (@path ? YAML.load_file(@path.to_s) : {}) || {} # load_file returns `false' when the file is empty
|
14
|
+
@config["environments"] ||= {}
|
13
15
|
end
|
14
16
|
|
15
17
|
def method_missing(meth, *args, &blk)
|
@@ -27,17 +29,15 @@ module EY
|
|
27
29
|
end
|
28
30
|
|
29
31
|
def endpoint
|
30
|
-
|
32
|
+
env_var_endpoint || default_endpoint
|
31
33
|
end
|
32
34
|
|
33
35
|
def env_var_endpoint
|
34
|
-
|
35
|
-
assert_valid_endpoint endpoint, "CLOUD_URL"
|
36
|
-
end
|
36
|
+
ENV["CLOUD_URL"]
|
37
37
|
end
|
38
38
|
|
39
39
|
def default_endpoint
|
40
|
-
|
40
|
+
"https://cloud.engineyard.com/"
|
41
41
|
end
|
42
42
|
|
43
43
|
def default_endpoint?
|
@@ -51,20 +51,94 @@ module EY
|
|
51
51
|
d && d.first
|
52
52
|
end
|
53
53
|
|
54
|
-
def
|
55
|
-
|
56
|
-
|
54
|
+
def environment_config(environment_name)
|
55
|
+
environments[environment_name] ||= {}
|
56
|
+
EnvironmentConfig.new(environments[environment_name], environment_name, self)
|
57
57
|
end
|
58
58
|
|
59
|
-
|
59
|
+
def set_environment_option(environment_name, key, value)
|
60
|
+
environments[environment_name] ||= {}
|
61
|
+
environments[environment_name][key] = value
|
62
|
+
ensure_path
|
63
|
+
@path.open('w') do |f|
|
64
|
+
YAML.dump(@config, f)
|
65
|
+
end
|
66
|
+
end
|
60
67
|
|
61
|
-
def
|
62
|
-
|
63
|
-
|
68
|
+
def ensure_path
|
69
|
+
return if @path && @path.exist?
|
70
|
+
unless EY::Repo.exist?
|
71
|
+
raise "Not in application directory. Unable to save configuration."
|
72
|
+
end
|
73
|
+
@path = Pathname.new('config/ey.yml')
|
74
|
+
@path.dirname.mkpath
|
75
|
+
@path
|
76
|
+
end
|
64
77
|
|
65
|
-
|
78
|
+
class EnvironmentConfig
|
79
|
+
attr_reader :name
|
80
|
+
|
81
|
+
def initialize(config, name, parent)
|
82
|
+
@config = config || {}
|
83
|
+
@name = name
|
84
|
+
@parent = parent
|
85
|
+
end
|
86
|
+
|
87
|
+
def path
|
88
|
+
@parent.path
|
89
|
+
end
|
90
|
+
|
91
|
+
def fetch(key, default = nil, &block)
|
92
|
+
if block
|
93
|
+
@config.fetch(key.to_s, &block)
|
94
|
+
else
|
95
|
+
@config.fetch(key.to_s, default)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def set(key, val)
|
100
|
+
@config[key.to_s] = val
|
101
|
+
@parent.set_environment_option(@name, key, val)
|
102
|
+
val
|
103
|
+
end
|
104
|
+
|
105
|
+
def merge(other)
|
106
|
+
to_clean_hash.merge(other)
|
107
|
+
end
|
108
|
+
|
109
|
+
def to_clean_hash
|
110
|
+
@config.reject { |k,v| %w[branch migrate migration_command verbose].include?(k) }
|
111
|
+
end
|
112
|
+
|
113
|
+
def branch
|
114
|
+
fetch('branch', nil)
|
115
|
+
end
|
116
|
+
|
117
|
+
def migrate(&block)
|
118
|
+
fetch('migrate', &block)
|
119
|
+
end
|
120
|
+
|
121
|
+
def migrate=(mig)
|
122
|
+
set('migrate', mig)
|
123
|
+
end
|
124
|
+
|
125
|
+
def migration_command
|
126
|
+
fetch('migration_command', nil)
|
127
|
+
end
|
128
|
+
|
129
|
+
def migration_command=(cmd)
|
130
|
+
set('migration_command', cmd)
|
131
|
+
end
|
132
|
+
alias migrate_command migration_command
|
133
|
+
alias migrate_command= migration_command=
|
134
|
+
|
135
|
+
def verbose
|
136
|
+
fetch('verbose', false)
|
137
|
+
end
|
66
138
|
end
|
67
139
|
|
140
|
+
private
|
141
|
+
|
68
142
|
class ConfigurationError < EY::Error
|
69
143
|
def initialize(key, value, source, message=nil)
|
70
144
|
super %|"#{key}" from #{source} has invalid value: #{value.inspect}#{": #{message}" if message}|
|