engineyard 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  module EY
2
- class Account
2
+ module Model
3
3
  class Log < ApiStruct.new(:id, :role, :main, :custom)
4
4
  def instance_name
5
5
  "#{role} #{id}"
@@ -15,9 +15,9 @@ module EY
15
15
  end
16
16
 
17
17
  def urls
18
- `git config -f #{@path}/.git/config --get-regexp 'remote.*.url'`.split(/\n/).map do |c|
19
- c.split.last
20
- end
18
+ lines = `git config -f #{@path}/.git/config --get-regexp 'remote.*.url'`.split(/\n/)
19
+ raise NoRemotesError.new(@path) if lines.empty?
20
+ lines.map { |c| c.split.last }
21
21
  end
22
22
 
23
23
  end # Repo
@@ -1,8 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe EY::Account::ApiStruct do
4
- class Foo < EY::Account::ApiStruct.new(:fruit); end
5
- class FooWithAccount < EY::Account::ApiStruct.new(:fruit, :account); end
3
+ describe EY::Model::ApiStruct do
4
+ class Foo < EY::Model::ApiStruct.new(:fruit, :veggie); end
6
5
 
7
6
  it "acts like a normal struct" do
8
7
  f = Foo.new("banana")
@@ -28,10 +27,15 @@ describe EY::Account::ApiStruct do
28
27
  f.should == [Foo.new("banana")]
29
28
  end
30
29
 
31
- it "handles an account as the second argument" do
32
- f = FooWithAccount.from_array([:fruit => "banana"], "account")
33
- f.should == [FooWithAccount.new("banana", "account")]
30
+ it "handles a common-arguments hash as the second argument" do
31
+ foos = Foo.from_array(
32
+ [{:fruit => "banana"}, {:fruit => 'apple'}],
33
+ :veggie => 'kale')
34
+ foos.should == [
35
+ Foo.new("banana", "kale"),
36
+ Foo.new("apple", "kale"),
37
+ ]
34
38
  end
35
39
  end
36
40
 
37
- end
41
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe "EY::Model::Environment#rebuild" do
4
+ it_should_behave_like "it has an api"
5
+
6
+ it "hits the rebuild action in the API" do
7
+ env = EY::Model::Environment.from_hash({
8
+ "id" => 46534,
9
+ "api" => @api,
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
21
+
22
+ describe "EY::Model::Environment#instances" do
23
+ it_should_behave_like "it has an api"
24
+
25
+ it "returns instances" do
26
+ env = EY::Model::Environment.from_hash({
27
+ "id" => 10291,
28
+ "api" => @api,
29
+ })
30
+
31
+ instance_data = {
32
+ "id" => "1",
33
+ "role" => "app_master",
34
+ "amazon_id" => "i-likebeer",
35
+ "public_hostname" => "banana_master"
36
+ }
37
+ FakeWeb.register_uri(:get,
38
+ "https://cloud.engineyard.com/api/v2/environments/#{env.id}/instances",
39
+ :body => {"instances" => [instance_data]}.to_json)
40
+
41
+
42
+ env.should have(1).instances
43
+ env.instances.first.should == EY::Model::Instance.from_hash(instance_data.merge(:environment => env))
44
+ end
45
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ describe "EY::Model::Instance's script for checking ey-deploy's version" do
4
+
5
+ def fake_out_no_ey_deploy
6
+ Gem.should_receive(:source_index).and_return(Gem::SourceIndex.new)
7
+ end
8
+
9
+ def fake_out_installed_ey_deploy_version(version)
10
+ net_sftp_gem = Gem::Specification.new do |s|
11
+ s.authors = ["Jamis Buck"]
12
+ s.autorequire = "net/sftp"
13
+ s.date = Time.utc(2008, 2, 24)
14
+ s.email = "jamis@jamisbuck.org"
15
+ s.files = ["doc/faq",
16
+ # snip
17
+ "test/protocol/tc_driver.rb"]
18
+ s.homepage = "http://net-ssh.rubyforge.org/sftp"
19
+ s.name = "net-sftp"
20
+ s.require_paths = ["lib"]
21
+ s.rubygems_version = "1.3.5"
22
+ s.specification_version = 2
23
+ s.summary = "Net::SFTP is a pure-Ruby implementation of the SFTP client protocol."
24
+ s.test_files = ["test/ALL-TESTS.rb"]
25
+ s.version = Gem::Version.new("1.1.1")
26
+ end
27
+
28
+ ey_deploy_gem = Gem::Specification.new do |s|
29
+ s.name = 'ey-deploy'
30
+ s.authors = ["EY Cloud Team"]
31
+ s.date = Time.utc(2010, 1, 2)
32
+ s.files = ['lib/engineyard/ey-deploy.rb'] # or something
33
+ s.specification_version = 2
34
+ s.version = Gem::Version.new(version)
35
+ end
36
+
37
+ fake_source_index = Gem::SourceIndex.new(
38
+ 'net-sftp-1.1.1' => net_sftp_gem,
39
+ "ey-deploy-#{version}" => ey_deploy_gem
40
+ )
41
+ Gem.should_receive(:source_index).and_return(fake_source_index)
42
+ end
43
+
44
+ def script_exit_status
45
+ eval EY::Model::Instance::CHECK_SCRIPT
46
+ rescue SystemExit => e
47
+ return e.status
48
+ end
49
+
50
+ it "exits 104 if the ey-deploy gem is not installed" do
51
+ fake_out_no_ey_deploy
52
+ script_exit_status.should == 104
53
+ end
54
+
55
+ it "exits 70 if the installed ey-deploy is too old" do
56
+ fake_out_installed_ey_deploy_version('0.0.1')
57
+ script_exit_status.should == 70
58
+ end
59
+
60
+ it "exits 17 if the installed ey-deploy is too new" do
61
+ fake_out_installed_ey_deploy_version('1000.0.0')
62
+ script_exit_status.should == 17
63
+ end
64
+
65
+ it "exits 0 if the version number is correct" do
66
+ correct_version = EY::Model::Instance::EYSD_VERSION.gsub(/[^\d\.]/, '')
67
+ fake_out_installed_ey_deploy_version(correct_version)
68
+ script_exit_status.should == 0
69
+ end
70
+ end
@@ -26,26 +26,29 @@ describe EY::Repo do
26
26
  it "returns the urls of the remotes" do
27
27
  origin_url = "git://github.com/engineyard/engineyard.git"
28
28
  other_url = "git@github.com:engineyard/engineyard.git"
29
- set_url origin_url
30
- set_url other_url, "other"
29
+ set_url origin_url, "origin"
30
+ set_url other_url, "other"
31
31
  @r.urls.should include(origin_url)
32
32
  @r.urls.should include(other_url)
33
33
  end
34
34
 
35
- it "returns nil if there is no origin remote" do
36
- set_url nil
37
- @r.urls.should be_empty
35
+ it "raises EY::NoRemotesError if there is no origin remote" do
36
+ clear_urls
37
+ lambda { @r.urls }.should raise_error(EY::NoRemotesError)
38
38
  end
39
39
 
40
- def set_url(url, remote="origin")
41
- @config_path = @path+"config"
42
- # This has to all shell out because FakeFS is enabled
43
- if url
44
- system("mkdir -p #{@path} && cd #{@path} && git init -q")
45
- system("git config -f #{@config_path} remote.#{remote}.url #{url}")
46
- else
47
- system("rm -rf #{@config_path}")
48
- end
40
+ def config_path
41
+ @path+"config"
42
+ end
43
+
44
+ # This has to all shell out because FakeFS is enabled
45
+ def set_url(url, remote)
46
+ system("mkdir -p #{@path} && cd #{@path} && git init -q")
47
+ system("git config -f #{config_path} remote.#{remote}.url #{url}")
48
+ end
49
+
50
+ def clear_urls
51
+ system("rm -rf #{config_path}")
49
52
  end
50
53
  end # url
51
54
 
@@ -1,38 +1,24 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "ey deploy" do
4
- # like the "an integration test" setup, but without the ~/.eyrc file
5
- # so we can test creating it
6
- before(:all) do
7
- FakeFS.deactivate!
8
- ENV['EYRC'] = "/tmp/eyrc"
9
- ENV['CLOUD_URL'] = EY.fake_awsm
10
- FakeWeb.allow_net_connect = true
11
- end
3
+ describe "ey deploy without an eyrc file" do
12
4
 
13
- after(:all) do
14
- ENV['CLOUD_URL'] = nil
15
- FakeFS.activate!
16
- FakeWeb.allow_net_connect = false
5
+ it_should_behave_like "an integration test without an eyrc file"
6
+
7
+ before(:each) do
8
+ FileUtils.rm_rf(ENV['EYRC'])
9
+ api_scenario "one app, one environment"
17
10
  end
18
11
 
19
- describe "without an eyrc file" do
20
- before(:each) do
21
- FileUtils.rm_rf(ENV['EYRC'])
22
- api_scenario "one app, one environment"
12
+ it "prompts for authentication before continuing" do
13
+ ey("deploy", :hide_err => true) do |input|
14
+ input.puts("test@test.test")
15
+ input.puts("test")
23
16
  end
24
17
 
25
- it "prompts for authentication before continuing" do
26
- ey("deploy", :hide_err => true) do |input|
27
- input.puts("test@test.test")
28
- input.puts("test")
29
- end
30
-
31
- @out.should include("We need to fetch your API token, please login")
32
- @out.should include("Email:")
33
- @out.should include("Password:")
34
- @ssh_commands.should_not be_empty
35
- end
18
+ @out.should include("We need to fetch your API token, please login")
19
+ @out.should include("Email:")
20
+ @out.should include("Password:")
21
+ @ssh_commands.should_not be_empty
36
22
  end
37
23
  end
38
24
 
@@ -42,25 +28,25 @@ describe "ey deploy" do
42
28
  context "with invalid input" do
43
29
  it "complains when there is no app" do
44
30
  api_scenario "empty"
45
- ey "deploy", :hide_err => true, :expect_failure => true
31
+ ey "deploy", :expect_failure => true
46
32
  @err.should include(%|no application configured|)
47
33
  end
48
34
 
49
35
  it "complains when you specify a nonexistent environment" do
50
36
  api_scenario "one app, one environment"
51
- ey "deploy typo-happens-here master", :hide_err => true, :expect_failure => true
37
+ ey "deploy typo-happens-here master", :expect_failure => true
52
38
  @err.should match(/no environment named 'typo-happens-here'/i)
53
39
  end
54
40
 
55
41
  it "complains when the specified environment does not contain the app" do
56
42
  api_scenario "one app, one environment, not linked"
57
- ey "deploy giblets master", :hide_err => true, :expect_failure => true
43
+ ey "deploy giblets master", :expect_failure => true
58
44
  @err.should match(/doesn't run this application/i)
59
45
  end
60
46
 
61
47
  it "complains when environment is ambiguous" do
62
48
  api_scenario "one app, two environments"
63
- ey "deploy", :hide_err => true, :expect_failure => true
49
+ ey "deploy", :expect_failure => true
64
50
  @err.should match(/was called incorrectly/i)
65
51
  end
66
52
  end
@@ -85,7 +71,7 @@ describe "ey deploy" do
85
71
  it "defaults to 'rake db:migrate'" do
86
72
  ey "deploy"
87
73
  @ssh_commands.last.should =~ /eysd deploy/
88
- @ssh_commands.last.should =~ /--migrate='rake db:migrate'/
74
+ @ssh_commands.last.should =~ /--migrate 'rake db:migrate'/
89
75
  end
90
76
 
91
77
  it "can be disabled with --no-migrate" do
@@ -98,12 +84,6 @@ describe "ey deploy" do
98
84
  ey "deploy --no-migrate giblets master"
99
85
  @ssh_commands.last.should_not =~ /--migrate/
100
86
  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
87
  end
108
88
 
109
89
  context "choosing something to deploy" do
@@ -127,6 +107,8 @@ describe "ey deploy" do
127
107
  [
128
108
  # initial repo setup
129
109
  'git init >/dev/null 2>&1',
110
+ 'git config user.email deploy@spec.test',
111
+ 'git config user.name "Deploy Spec"',
130
112
  'git remote add origin "user@git.host/path/to/repo.git"',
131
113
 
132
114
  # we'll have one commit on master
@@ -171,6 +153,22 @@ describe "ey deploy" do
171
153
  end
172
154
  end
173
155
 
156
+ context "when there is extra configuration" do
157
+ before(:all) do
158
+ write_yaml({"environments" => {"giblets" => {"bert" => "ernie"}}},
159
+ File.join(@local_git_dir, "ey.yml"))
160
+ end
161
+
162
+ after(:all) do
163
+ File.unlink(File.join(@local_git_dir, "ey.yml"))
164
+ end
165
+
166
+ it "gets passed along to eysd" do
167
+ ey "deploy"
168
+ @ssh_commands.last.should =~ /--config '\{\"bert\":\"ernie\"\}'/
169
+ end
170
+ end
171
+
174
172
  context "with a configured default branch" do
175
173
  before(:all) do
176
174
  write_yaml({"environments" => {"giblets" => {"branch" => "master"}}},
@@ -187,7 +185,7 @@ describe "ey deploy" do
187
185
  end
188
186
 
189
187
  it "complains about a non-default branch without --force" do
190
- ey "deploy giblets current-branch", :hide_err => true, :expect_failure => true
188
+ ey "deploy giblets current-branch", :expect_failure => true
191
189
  @err.should =~ /deploy branch is set to "master"/
192
190
  end
193
191
 
@@ -198,25 +196,77 @@ describe "ey deploy" do
198
196
  end
199
197
  end
200
198
 
199
+ context "specifying an environment" do
200
+ before(:all) do
201
+ api_scenario "one app, many similarly-named environments"
202
+ end
203
+
204
+ it "lets you choose by unambiguous substring" do
205
+ ey "deploy prod"
206
+ @out.should match(/Running deploy for 'railsapp_production'/)
207
+ end
208
+
209
+ it "lets you choose by complete name even if the complete name is ambiguous" do
210
+ ey "deploy railsapp_staging"
211
+ @out.should match(/Running deploy for 'railsapp_staging'/)
212
+ end
213
+
214
+ it "complains when given an ambiguous substring" do
215
+ # NB: there's railsapp_staging and railsapp_staging_2
216
+ ey "deploy staging", :hide_err => true, :expect_failure => true
217
+ @err.should match(/'staging' is ambiguous/)
218
+ end
219
+ end
220
+
201
221
  context "eysd install" do
202
222
  before(:all) do
203
223
  api_scenario "one app, one environment"
204
224
  end
205
225
 
206
- after(:all) do
226
+ before(:each) do
227
+ ENV.delete "NO_SSH"
228
+ end
229
+
230
+ after(:each) do
207
231
  ENV['NO_SSH'] = "true"
208
232
  end
209
233
 
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/"
234
+ def exiting_ssh(exit_code)
235
+ "#!/usr/bin/env ruby\n exit!(#{exit_code}) if ARGV.to_s =~ /Base64.decode64/"
236
+ end
237
+
238
+ it "raises an error if SSH fails" do
239
+ ey "deploy", :prepend_to_path => {'ssh' => exiting_ssh(255)}, :expect_failure => true
240
+ @err.should =~ /SSH connection to \S+ failed/
241
+ end
213
242
 
214
- ey "deploy", :prepend_to_path => {'ssh' => fake_ssh_no_eysd}
243
+ it "installs ey-deploy if it's missing" do
244
+ ey "deploy", :prepend_to_path => {'ssh' => exiting_ssh(104)}
215
245
 
216
246
  gem_install_command = @ssh_commands.find do |command|
217
247
  command =~ /gem install ey-deploy/
218
248
  end
219
249
  gem_install_command.should =~ %r{/usr/local/ey_resin/ruby/bin/gem install}
220
250
  end
251
+
252
+ it "upgrades ey-deploy if it's too old" do
253
+ ey "deploy", :prepend_to_path => {'ssh' => exiting_ssh(70)}
254
+ @ssh_commands.should have_command_like(/gem uninstall -a -x ey-deploy/)
255
+ @ssh_commands.should have_command_like(/gem install ey-deploy/)
256
+ end
257
+
258
+ it "raises an error if ey-deploy is too new" do
259
+ ey "deploy", :prepend_to_path => {'ssh' => exiting_ssh(17)}, :expect_failure => true
260
+ @ssh_commands.should_not have_command_like(/gem install ey-deploy/)
261
+ @ssh_commands.should_not have_command_like(/eysd deploy/)
262
+ @err.should match(/too new/i)
263
+ end
264
+
265
+ it "does not change ey-deploy if its version is satisfactory" do
266
+ ey "deploy", :prepend_to_path => {'ssh' => exiting_ssh(0)}
267
+ @ssh_commands.should_not have_command_like(/gem install ey-deploy/)
268
+ @ssh_commands.should_not have_command_like(/gem uninstall.* ey-deploy/)
269
+ @ssh_commands.should have_command_like(/eysd deploy/)
270
+ end
221
271
  end
222
272
  end
@@ -1,6 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "ey environments" do
4
+
4
5
  it_should_behave_like "an integration test"
5
6
 
6
7
  before(:all) do
@@ -10,7 +11,16 @@ describe "ey environments" do
10
11
  it "lists the environments your app is in" do
11
12
  ey "environments"
12
13
  @out.should =~ /giblets/
13
- @out.should =~ /ham/
14
+ @out.should =~ /bakon/
15
+ end
16
+
17
+ it "reports failure to find a git repo when not in one" do
18
+ api_git_remote('dontcare')
19
+ Dir.chdir("/tmp") do
20
+ ey "environments", :expect_failure => true
21
+ @err.should =~ /fatal: No git remotes found in .*\/tmp/
22
+ @out.should_not =~ /no application configured/
23
+ end
14
24
  end
15
25
 
16
26
  end