engineyard 0.2.11 → 0.2.12
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/lib/engineyard.rb +4 -3
- data/lib/engineyard/#repo.rb# +24 -0
- data/lib/engineyard/account.rb +32 -11
- data/lib/engineyard/account/api_struct.rb +25 -0
- data/lib/engineyard/account/app.rb +11 -10
- data/lib/engineyard/account/app_master.rb +1 -7
- data/lib/engineyard/account/environment.rb +31 -16
- data/lib/engineyard/account/instance.rb +6 -0
- data/lib/engineyard/account/log.rb +7 -16
- data/lib/engineyard/action/deploy.rb +138 -0
- data/lib/engineyard/action/list_environments.rb +22 -0
- data/lib/engineyard/action/rebuild.rb +31 -0
- data/lib/engineyard/action/show_logs.rb +26 -0
- data/lib/engineyard/action/ssh.rb +19 -0
- data/lib/engineyard/action/upload_recipes.rb +17 -0
- data/lib/engineyard/action/util.rb +47 -0
- data/lib/engineyard/cli.rb +24 -150
- data/lib/engineyard/cli/thor_fixes.rb +26 -0
- data/lib/engineyard/error.rb +48 -0
- data/lib/engineyard/repo.rb +1 -1
- data/lib/engineyard/ruby_ext.rb +9 -0
- data/spec/engineyard/account/api_struct_spec.rb +37 -0
- data/spec/engineyard/account/environment_spec.rb +20 -0
- data/spec/engineyard/account_spec.rb +18 -0
- data/spec/engineyard/cli_spec.rb +3 -3
- data/spec/ey/deploy_spec.rb +166 -28
- data/spec/ey/ey_spec.rb +3 -3
- data/spec/ey/list_environments_spec.rb +16 -0
- data/spec/ey/logs_spec.rb +2 -17
- data/spec/ey/rebuild_spec.rb +25 -0
- data/spec/ey/ssh_spec.rb +24 -0
- data/spec/ey/upload_recipes_spec.rb +21 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/fake_awsm.ru +25 -1
- data/spec/support/helpers.rb +72 -7
- metadata +44 -56
- data/lib/engineyard/cli/error.rb +0 -44
- data/spec/spec.opts +0 -2
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "EY::Account::Environment#rebuild" do
|
4
|
+
it_should_behave_like "it has an account"
|
5
|
+
|
6
|
+
it "hits the rebuild action in the API" do
|
7
|
+
env = EY::Account::Environment.from_hash({
|
8
|
+
"id" => 46534,
|
9
|
+
"account" => @account
|
10
|
+
})
|
11
|
+
|
12
|
+
FakeWeb.register_uri(:put,
|
13
|
+
"https://cloud.engineyard.com/api/v2/environments/#{env.id}/rebuild",
|
14
|
+
:body => {}.to_json)
|
15
|
+
|
16
|
+
env.rebuild
|
17
|
+
|
18
|
+
FakeWeb.should have_requested(:put, "https://cloud.engineyard.com/api/v2/environments/#{env.id}/rebuild")
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EY::Account do
|
4
|
+
it_should_behave_like "it has an account"
|
5
|
+
|
6
|
+
it "returns instances" do
|
7
|
+
@env = EY::Account::Environment.from_hash({
|
8
|
+
"id" => 1, "name" => "banana", "instances_count" => 3,
|
9
|
+
"ssh_username" => "monkey", "apps" => {}, "account" => @account
|
10
|
+
})
|
11
|
+
@instance_data = {"id" => "1", "role" => "app_master",
|
12
|
+
"amazon_id" => "amazon_1", "public_hostname" => "banana_master"}
|
13
|
+
FakeWeb.register_uri(:get, "https://cloud.engineyard.com/api/v2/environments/#{@env.id}/instances",
|
14
|
+
:body => {"instances" => [@instance_data]}.to_json)
|
15
|
+
|
16
|
+
@account.instances_for(@env).first.should == EY::Account::Instance.from_hash(@instance_data)
|
17
|
+
end
|
18
|
+
end
|
data/spec/engineyard/cli_spec.rb
CHANGED
@@ -12,9 +12,9 @@ describe EY::CLI do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
it "provides error classes" do
|
15
|
-
EY::
|
16
|
-
EY::
|
17
|
-
EY::
|
15
|
+
EY::EnvironmentError.should be
|
16
|
+
EY::BranchMismatch.should be
|
17
|
+
EY::DeployArgumentError.should be
|
18
18
|
end
|
19
19
|
|
20
20
|
end # EY::CLI
|
data/spec/ey/deploy_spec.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe "ey deploy" do
|
4
|
+
# like the "an integration test" setup, but without the ~/.eyrc file
|
5
|
+
# so we can test creating it
|
4
6
|
before(:all) do
|
5
7
|
FakeFS.deactivate!
|
6
8
|
ENV['EYRC'] = "/tmp/eyrc"
|
@@ -17,9 +19,10 @@ describe "ey deploy" do
|
|
17
19
|
describe "without an eyrc file" do
|
18
20
|
before(:each) do
|
19
21
|
FileUtils.rm_rf(ENV['EYRC'])
|
22
|
+
api_scenario "one app, one environment"
|
20
23
|
end
|
21
24
|
|
22
|
-
it "prompts for authentication" do
|
25
|
+
it "prompts for authentication before continuing" do
|
23
26
|
ey("deploy", :hide_err => true) do |input|
|
24
27
|
input.puts("test@test.test")
|
25
28
|
input.puts("test")
|
@@ -28,57 +31,192 @@ describe "ey deploy" do
|
|
28
31
|
@out.should include("We need to fetch your API token, please login")
|
29
32
|
@out.should include("Email:")
|
30
33
|
@out.should include("Password:")
|
34
|
+
@ssh_commands.should_not be_empty
|
31
35
|
end
|
32
36
|
end
|
37
|
+
end
|
33
38
|
|
34
|
-
|
35
|
-
|
36
|
-
token = { ENV['CLOUD_URL'] => {
|
37
|
-
"api_token" => "f81a1706ddaeb148cfb6235ddecfc1cf"} }
|
38
|
-
File.open(ENV['EYRC'], "w"){|f| YAML.dump(token, f) }
|
39
|
-
end
|
39
|
+
describe "ey deploy" do
|
40
|
+
it_should_behave_like "an integration test"
|
40
41
|
|
42
|
+
context "with invalid input" do
|
41
43
|
it "complains when there is no app" do
|
42
44
|
api_scenario "empty"
|
43
|
-
ey "deploy", :hide_err => true
|
45
|
+
ey "deploy", :hide_err => true, :expect_failure => true
|
44
46
|
@err.should include(%|no application configured|)
|
45
47
|
end
|
46
48
|
|
47
|
-
it "complains when
|
48
|
-
api_scenario "one app, one environment
|
49
|
-
ey "deploy
|
50
|
-
@err.should match(/
|
49
|
+
it "complains when you specify a nonexistent environment" do
|
50
|
+
api_scenario "one app, one environment"
|
51
|
+
ey "deploy typo-happens-here master", :hide_err => true, :expect_failure => true
|
52
|
+
@err.should match(/no environment named 'typo-happens-here'/i)
|
51
53
|
end
|
52
54
|
|
53
|
-
it "
|
54
|
-
api_scenario "one app, one environment"
|
55
|
-
ey "deploy", :hide_err => true
|
56
|
-
@
|
57
|
-
@err.should be_empty
|
55
|
+
it "complains when the specified environment does not contain the app" do
|
56
|
+
api_scenario "one app, one environment, not linked"
|
57
|
+
ey "deploy giblets master", :hide_err => true, :expect_failure => true
|
58
|
+
@err.should match(/doesn't run this application/i)
|
58
59
|
end
|
59
60
|
|
60
61
|
it "complains when environment is ambiguous" do
|
61
62
|
api_scenario "one app, two environments"
|
62
|
-
ey "deploy", :hide_err => true
|
63
|
+
ey "deploy", :hide_err => true, :expect_failure => true
|
63
64
|
@err.should match(/was called incorrectly/i)
|
64
65
|
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it "runs when environment is known" do
|
69
|
+
api_scenario "one app, one environment"
|
70
|
+
ey "deploy", :hide_err => true
|
71
|
+
@out.should match(/running deploy/i)
|
72
|
+
@err.should be_empty
|
73
|
+
end
|
74
|
+
|
75
|
+
context "migration command" do
|
76
|
+
before(:each) do
|
77
|
+
api_scenario "one app, one environment"
|
78
|
+
end
|
79
|
+
|
80
|
+
it "finds eysd despite its being buried in the filesystem" do
|
81
|
+
ey "deploy"
|
82
|
+
@ssh_commands.last.should =~ %r{/usr/local/ey_resin/ruby/bin/eysd}
|
83
|
+
end
|
84
|
+
|
85
|
+
it "defaults to 'rake db:migrate'" do
|
86
|
+
ey "deploy"
|
87
|
+
@ssh_commands.last.should =~ /eysd deploy/
|
88
|
+
@ssh_commands.last.should =~ /--migrate='rake db:migrate'/
|
89
|
+
end
|
90
|
+
|
91
|
+
it "can be disabled with --no-migrate" do
|
92
|
+
ey "deploy --no-migrate"
|
93
|
+
@ssh_commands.last.should =~ /eysd deploy/
|
94
|
+
@ssh_commands.last.should_not =~ /--migrate/
|
95
|
+
end
|
96
|
+
|
97
|
+
it "can be disabled with --no-migrate in the middle of the command line" do
|
98
|
+
ey "deploy --no-migrate giblets master"
|
99
|
+
@ssh_commands.last.should_not =~ /--migrate/
|
100
|
+
end
|
101
|
+
|
102
|
+
it "can be disabled with --no-migrate" do
|
103
|
+
ey "deploy --no-migrate"
|
104
|
+
@ssh_commands.last.should =~ /eysd deploy/
|
105
|
+
@ssh_commands.last.should_not =~ /--migrate/
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "choosing something to deploy" do
|
110
|
+
before(:all) do
|
111
|
+
api_scenario "one app, one environment"
|
112
|
+
api_git_remote("user@git.host/path/to/repo.git")
|
113
|
+
end
|
114
|
+
|
115
|
+
after(:all) do
|
116
|
+
api_git_remote(nil)
|
117
|
+
end
|
118
|
+
|
119
|
+
before(:all) do
|
120
|
+
@local_git_dir = File.join(
|
121
|
+
Dir.tmpdir,
|
122
|
+
"ey_test_git_#{Time.now.tv_sec}_#{Time.now.tv_usec}_#{$$}")
|
123
|
+
|
124
|
+
Dir.mkdir(@local_git_dir)
|
125
|
+
|
126
|
+
Dir.chdir(@local_git_dir) do
|
127
|
+
[
|
128
|
+
# initial repo setup
|
129
|
+
'git init >/dev/null 2>&1',
|
130
|
+
'git remote add origin "user@git.host/path/to/repo.git"',
|
131
|
+
|
132
|
+
# we'll have one commit on master
|
133
|
+
"echo 'source :gemcutter' > Gemfile",
|
134
|
+
"git add Gemfile",
|
135
|
+
"git commit -m 'initial commit' >/dev/null 2>&1",
|
136
|
+
|
137
|
+
# and a tag
|
138
|
+
"git tag -a -m 'version one' v1",
|
139
|
+
|
140
|
+
# and we need a non-master branch
|
141
|
+
"git checkout -b current-branch >/dev/null 2>&1",
|
142
|
+
].each do |cmd|
|
143
|
+
system("#{cmd}") or raise "#{cmd} failed"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
before(:each) do
|
149
|
+
@original_dir = Dir.getwd
|
150
|
+
Dir.chdir(@local_git_dir)
|
151
|
+
end
|
152
|
+
|
153
|
+
after(:each) do
|
154
|
+
Dir.chdir(@original_dir)
|
155
|
+
end
|
65
156
|
|
66
|
-
context "
|
67
|
-
|
68
|
-
|
157
|
+
context "without a configured default branch" do
|
158
|
+
it "defaults to the checked-out local branch" do
|
159
|
+
ey "deploy"
|
160
|
+
@ssh_commands.last.should =~ /--branch current-branch/
|
69
161
|
end
|
70
162
|
|
71
|
-
it "
|
163
|
+
it "deploys another branch if given" do
|
164
|
+
ey "deploy giblets master"
|
165
|
+
@ssh_commands.last.should =~ /--branch master/
|
166
|
+
end
|
167
|
+
|
168
|
+
it "deploys a tag if given" do
|
169
|
+
ey "deploy giblets v1"
|
170
|
+
@ssh_commands.last.should =~ /--branch v1/
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context "with a configured default branch" do
|
175
|
+
before(:all) do
|
176
|
+
write_yaml({"environments" => {"giblets" => {"branch" => "master"}}},
|
177
|
+
File.join(@local_git_dir, "ey.yml"))
|
178
|
+
end
|
179
|
+
|
180
|
+
after(:all) do
|
181
|
+
File.unlink(File.join(@local_git_dir, "ey.yml"))
|
182
|
+
end
|
183
|
+
|
184
|
+
it "deploys the default branch by default" do
|
72
185
|
ey "deploy"
|
73
|
-
@ssh_commands.
|
74
|
-
@ssh_commands.first.should =~ /--migrate='rake db:migrate'/
|
186
|
+
@ssh_commands.last.should =~ /--branch master/
|
75
187
|
end
|
76
188
|
|
77
|
-
it "
|
78
|
-
ey "deploy
|
79
|
-
@
|
80
|
-
|
189
|
+
it "complains about a non-default branch without --force" do
|
190
|
+
ey "deploy giblets current-branch", :hide_err => true, :expect_failure => true
|
191
|
+
@err.should =~ /deploy branch is set to "master"/
|
192
|
+
end
|
193
|
+
|
194
|
+
it "deploys a non-default branch with --force" do
|
195
|
+
ey "deploy giblets current-branch --force"
|
196
|
+
@ssh_commands.last.should =~ /--branch current-branch/
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
context "eysd install" do
|
202
|
+
before(:all) do
|
203
|
+
api_scenario "one app, one environment"
|
204
|
+
end
|
205
|
+
|
206
|
+
after(:all) do
|
207
|
+
ENV['NO_SSH'] = "true"
|
208
|
+
end
|
209
|
+
|
210
|
+
it "installs eysd if 'eysd check' fails" do
|
211
|
+
ENV.delete('NO_SSH')
|
212
|
+
fake_ssh_no_eysd = "#!/usr/bin/env ruby\n exit!(127) if ARGV.last =~ /eysd check/"
|
213
|
+
|
214
|
+
ey "deploy", :prepend_to_path => {'ssh' => fake_ssh_no_eysd}
|
215
|
+
|
216
|
+
gem_install_command = @ssh_commands.find do |command|
|
217
|
+
command =~ /gem install ey-deploy/
|
81
218
|
end
|
219
|
+
gem_install_command.should =~ %r{/usr/local/ey_resin/ruby/bin/gem install}
|
82
220
|
end
|
83
221
|
end
|
84
222
|
end
|
data/spec/ey/ey_spec.rb
CHANGED
@@ -3,14 +3,14 @@ require 'spec_helper'
|
|
3
3
|
describe "ey" do
|
4
4
|
context "run without arguments" do
|
5
5
|
it "prints usage information" do
|
6
|
-
ey.should include
|
6
|
+
ey.should include("Tasks:")
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
10
|
context "run with an argument that is not a command" do
|
11
11
|
it "tells the user that is not a command" do
|
12
12
|
ey "foobarbaz", :hide_err => true
|
13
|
-
@err.should include
|
13
|
+
@err.should include("Could not find task")
|
14
14
|
end
|
15
15
|
end
|
16
|
-
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "ey environments" do
|
4
|
+
it_should_behave_like "an integration test"
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
api_scenario "one app, two environments"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "lists the environments your app is in" do
|
11
|
+
ey "environments"
|
12
|
+
@out.should =~ /giblets/
|
13
|
+
@out.should =~ /ham/
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
data/spec/ey/logs_spec.rb
CHANGED
@@ -1,24 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe "ey logs" do
|
4
|
-
|
5
|
-
ENV['CLOUD_URL'] = EY.fake_awsm
|
6
|
-
FakeWeb.allow_net_connect = true
|
4
|
+
it_should_behave_like "an integration test"
|
7
5
|
|
8
|
-
|
9
|
-
ENV['EYRC'] = "/tmp/eyrc"
|
10
|
-
token = { ENV['CLOUD_URL'] => {
|
11
|
-
"api_token" => "f81a1706ddaeb148cfb6235ddecfc1cf"} }
|
12
|
-
File.open(ENV['EYRC'], "w"){|f| YAML.dump(token, f) }
|
13
|
-
end
|
14
|
-
|
15
|
-
after(:all) do
|
16
|
-
ENV['CLOUD_URL'] = nil
|
17
|
-
FakeFS.activate!
|
18
|
-
FakeWeb.allow_net_connect = false
|
19
|
-
end
|
20
|
-
|
21
|
-
it "runs when environment is known" do
|
6
|
+
it "prints logs returned by awsm" do
|
22
7
|
api_scenario "one app, one environment"
|
23
8
|
ey "logs giblets"
|
24
9
|
@out.should match(/MAIN LOG OUTPUT/)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "ey rebuild" do
|
4
|
+
it_should_behave_like "an integration test"
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
api_scenario "one app, one environment"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "works when the environment name is valid" do
|
11
|
+
ey "rebuild giblets"
|
12
|
+
@out.should =~ /Rebuilding giblets/i
|
13
|
+
end
|
14
|
+
|
15
|
+
it "rebuilds the current environment by default" do
|
16
|
+
ey "rebuild"
|
17
|
+
@out.should =~ /Rebuilding giblets/i
|
18
|
+
end
|
19
|
+
|
20
|
+
it "fails when the environment name is bogus" do
|
21
|
+
ey "rebuild typo", :hide_err => true, :expect_failure => true
|
22
|
+
@err.should match(/No environment named 'typo'/)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
data/spec/ey/ssh_spec.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "ey ssh" do
|
4
|
+
it_should_behave_like "an integration test"
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
api_scenario "one app, one environment"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "SSH-es into the right environment" do
|
11
|
+
print_my_args = "#!/bin/sh\necho ssh $*"
|
12
|
+
|
13
|
+
ey "ssh giblets", :prepend_to_path => {'ssh' => print_my_args}
|
14
|
+
@ssh_commands.should == ["ssh turkey@174.129.198.124"]
|
15
|
+
end
|
16
|
+
|
17
|
+
it "complains if you give it a bogus environment" do
|
18
|
+
print_my_args = "#!/bin/sh\necho ssh $*"
|
19
|
+
|
20
|
+
ey "ssh bogusenv", :prepend_to_path => {'ssh' => print_my_args}, :hide_err => true
|
21
|
+
@ssh_commands.should be_empty
|
22
|
+
@out.should =~ /could not find.*bogusenv/i
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "ey upload_recipes" do
|
4
|
+
it_should_behave_like "an integration test"
|
5
|
+
|
6
|
+
it "posts the recipes to the correct url" do
|
7
|
+
api_scenario "one app, one environment"
|
8
|
+
dir = Pathname.new("/tmp/#{$$}")
|
9
|
+
dir.mkdir
|
10
|
+
Dir.chdir(dir) do
|
11
|
+
dir.join("cookbooks").mkdir
|
12
|
+
File.open(dir.join("cookbooks/file"), "w"){|f| f << "boo" }
|
13
|
+
`git init`
|
14
|
+
`git add .`
|
15
|
+
`git commit -m "OMG"`
|
16
|
+
ey "upload_recipes giblets", :debug => true
|
17
|
+
end
|
18
|
+
|
19
|
+
@out.should =~ /recipes uploaded successfully/i
|
20
|
+
end
|
21
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
if self.class.const_defined?(:EY_ROOT)
|
2
|
+
raise "don't require the spec helper twice!"
|
3
|
+
end
|
4
|
+
|
1
5
|
EY_ROOT = File.expand_path("../..", __FILE__)
|
2
6
|
begin
|
3
7
|
require File.join(EY_ROOT, ".bundle/environment.rb")
|
@@ -8,6 +12,7 @@ end
|
|
8
12
|
|
9
13
|
# Bundled gems
|
10
14
|
require 'fakeweb'
|
15
|
+
require 'fakeweb_matcher'
|
11
16
|
require 'fakefs/safe'
|
12
17
|
|
13
18
|
# Engineyard gem
|
@@ -37,3 +42,30 @@ Spec::Runner.configure do |config|
|
|
37
42
|
EY.instance_eval{ @config = nil }
|
38
43
|
end
|
39
44
|
end
|
45
|
+
|
46
|
+
# Use this in conjunction with the 'ey' helper method
|
47
|
+
shared_examples_for "an integration test" do
|
48
|
+
before(:all) do
|
49
|
+
FakeFS.deactivate!
|
50
|
+
ENV['EYRC'] = "/tmp/eyrc"
|
51
|
+
ENV['CLOUD_URL'] = EY.fake_awsm
|
52
|
+
FakeWeb.allow_net_connect = true
|
53
|
+
|
54
|
+
token = { ENV['CLOUD_URL'] => {
|
55
|
+
"api_token" => "f81a1706ddaeb148cfb6235ddecfc1cf"} }
|
56
|
+
File.open(ENV['EYRC'], "w"){|f| YAML.dump(token, f) }
|
57
|
+
end
|
58
|
+
|
59
|
+
after(:all) do
|
60
|
+
ENV['CLOUD_URL'] = nil
|
61
|
+
FakeFS.activate!
|
62
|
+
FakeWeb.allow_net_connect = false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
shared_examples_for "it has an account" do
|
67
|
+
before(:all) do
|
68
|
+
write_yaml({"api_token" => "asdf"}, "~/.eyrc")
|
69
|
+
@account = EY::Account.new(EY::API.new)
|
70
|
+
end
|
71
|
+
end
|