engineyard 1.3.1 → 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -11,28 +11,24 @@ module EY
11
11
  @repo ||= EY::Repo.new
12
12
  end
13
13
 
14
- # if an app is supplied, it is used as a constraint for implied environment lookup
15
- def fetch_environment(env_name, app = nil)
16
- env_name ||= EY.config.default_environment
17
- if env_name
18
- (app || api).environments.match_one!(env_name)
19
- else
20
- (app || api.app_for_repo!(repo)).sole_environment!
21
- end
22
- end
23
-
24
- def fetch_environment_without_app(env_name)
25
- fetch_environment(env_name)
26
- rescue EY::AmbiguousGitUriError
27
- raise EY::AmbiguousEnvironmentGitUriError.new(api.environments)
14
+ def fetch_environment(environment_name, account_name=nil)
15
+ environment_name ||= EY.config.default_environment
16
+ options = {
17
+ :environment_name => environment_name,
18
+ :account_name => account_name
19
+ }
20
+ options.merge! :repo => repo if repo.exists?
21
+ api.resolver.environment(options)
28
22
  end
29
23
 
30
- def fetch_app(app_name = nil)
31
- if app_name
32
- api.apps.match_one!(app_name)
33
- else
34
- api.app_for_repo!(repo)
35
- end
24
+ def fetch_app_and_environment(app_name = nil, environment_name = nil, account_name=nil)
25
+ options = {
26
+ :app_name => app_name,
27
+ :environment_name => environment_name,
28
+ :account_name => account_name
29
+ }
30
+ options.merge! :repo => repo if repo.exists?
31
+ api.resolver.app_and_environment(options)
36
32
  end
37
33
 
38
34
  def get_apps(all_apps = false)
@@ -1,3 +1,3 @@
1
1
  module EY
2
- VERSION = '1.3.1'
2
+ VERSION = '1.3.2'
3
3
  end
@@ -53,34 +53,4 @@ describe EY::API do
53
53
  }.should raise_error(EY::Error)
54
54
  end
55
55
 
56
- it "raises an error when using a git repo that is attached to multiple applications" do
57
- repo = mock("repo", :urls => %w[git://github.com/engineyard/dup.git])
58
- apps = {"apps" => [
59
- {"id" => 1234, "name" => "app_production", :repository_uri => 'git://github.com/engineyard/prod.git'},
60
- {"id" => 4532, "name" => "app_dup1", :repository_uri => 'git://github.com/engineyard/dup.git'},
61
- {"id" => 4533, "name" => "app_dup2", :repository_uri => 'git://github.com/engineyard/dup.git'},
62
- ]}
63
-
64
- FakeWeb.register_uri(:get, "https://cloud.engineyard.com/api/v2/apps", :status => 200, :content_type => 'application/json',
65
- :body => apps.to_json)
66
-
67
- lambda do
68
- EY::API.new("asdf").app_for_repo(repo)
69
- end.should raise_error(EY::AmbiguousGitUriError)
70
- end
71
-
72
- it "returns the application when given a unique git repo" do
73
- repo = mock("repo", :urls => %w[git://github.com/engineyard/prod.git])
74
- apps = {"apps" => [
75
- {"id" => 1234, "name" => "app_production", :repository_uri => 'git://github.com/engineyard/prod.git'},
76
- {"id" => 4532, "name" => "app_dup1", :repository_uri => 'git://github.com/engineyard/dup.git'},
77
- {"id" => 4533, "name" => "app_dup2", :repository_uri => 'git://github.com/engineyard/dup.git'},
78
- ]}
79
-
80
- FakeWeb.register_uri(:get, "https://cloud.engineyard.com/api/v2/apps", :status => 200, :content_type => 'application/json',
81
- :body => apps.to_json)
82
-
83
- EY::API.new("asdf").app_for_repo(repo).name.should == "app_production"
84
- end
85
-
86
56
  end
@@ -0,0 +1,116 @@
1
+ require 'spec_helper'
2
+
3
+ describe EY::Resolver do
4
+ def api
5
+ return @api if @api
6
+ apps = Object.new
7
+ def apps.named(name, *args)
8
+ result = EY::Model::App.from_hash(:name => name)
9
+ result.stub!(:environments => [])
10
+ result
11
+ end
12
+ environments = Object.new
13
+ def environments.named(name, *args)
14
+ result = EY::Model::Environment.from_hash(:name => name)
15
+ result.stub!(:apps => [])
16
+ result
17
+ end
18
+ @api = mock("api", :apps => apps, :environments => environments)
19
+ end
20
+
21
+ def resolver
22
+ @resolver ||= EY::Resolver.new(api).tap do |r|
23
+ r.instance_variable_set("@app_deployments", [])
24
+ end
25
+ end
26
+
27
+ def new_app_deployment(options)
28
+ resolver.instance_variable_get("@app_deployments") << options
29
+ options
30
+ end
31
+
32
+
33
+ before do
34
+ @production = new_app_deployment(:environment_name => "app_production", :app_name => "app", :account_name => "ey", :repository_uri => "git://github.com/repo/app.git")
35
+ @staging = new_app_deployment(:environment_name => "app_staging" , :app_name => "app", :account_name => "ey", :repository_uri => "git://github.com/repo/app.git")
36
+ @big = new_app_deployment(:environment_name => "bigapp_staging", :app_name => "bigapp", :account_name => "ey", :repository_uri => "git://github.com/repo/bigapp.git")
37
+ @ey_dup = new_app_deployment(:environment_name => "app_duplicate" , :app_name => "app_duplicate", :account_name => "ey", :repository_uri => "git://github.com/repo/dup.git")
38
+ @sumo = new_app_deployment(:environment_name => "sumo_wrestler" , :app_name => "app_duplicate", :account_name => "ey", :repository_uri => "git://github.com/repo/dup.git")
39
+ @me_dup = new_app_deployment(:environment_name => "app_duplicate" , :app_name => "app_duplicate", :account_name => "me", :repository_uri => "git://github.com/repo/dup.git")
40
+ end
41
+
42
+ def repo(url)
43
+ mock("repo", :urls => [url])
44
+ end
45
+
46
+ def resolve_to(expected)
47
+ simple_matcher "resolve to" do |(app,environment), _|
48
+ app.name.should == expected[:app_name]
49
+ environment.name.should == expected[:environment_name]
50
+ end
51
+ end
52
+
53
+ describe "#fetch" do
54
+ it "raises argument error if the conditions are empty" do
55
+ lambda { resolver.app_and_environment({}) }.should raise_error(ArgumentError)
56
+ end
57
+
58
+ it "raises when there is no app match" do
59
+ lambda { resolver.app_and_environment(:environment_name => 'app_duplicate', :app_name => 'smallapp') }.should raise_error(EY::InvalidAppError)
60
+ end
61
+
62
+ it "raises when the git repo does not match any apps" do
63
+ lambda { resolver.app_and_environment(:environment_name => 'app_duplicate', :repo => repo("git://github.com/no-such/app.git")) }.should raise_error(EY::NoAppError)
64
+ end
65
+
66
+ it "raises when there is no environment match" do
67
+ lambda { resolver.app_and_environment(:environment_name => 'gibberish', :app_name => 'app') }.should raise_error(EY::NoEnvironmentError)
68
+ end
69
+
70
+ it "raises when there are no matches" do
71
+ lambda { resolver.app_and_environment(:environment_name => 'app_duplicate', :app_name => 'bigapp') }.should raise_error(EY::NoMatchesError)
72
+ lambda { resolver.app_and_environment(:repo => repo("git://github.com/repo/app.git"), :environment_name => 'app_duplicate') }.should raise_error(EY::NoMatchesError)
73
+ end
74
+
75
+ it "raises when there is more than one match" do
76
+ lambda { resolver.app_and_environment(:app_name => "app") }.should raise_error(EY::MultipleMatchesError)
77
+ lambda { resolver.app_and_environment(:account_name => "ey", :app_name => "app") }.should raise_error(EY::MultipleMatchesError)
78
+ lambda { resolver.app_and_environment(:repo => repo("git://github.com/repo/dup.git")) }.should raise_error(EY::MultipleMatchesError)
79
+ lambda { resolver.app_and_environment(:repo => repo("git://github.com/repo/app.git")) }.should raise_error(EY::MultipleMatchesError)
80
+ end
81
+
82
+ it "does not include duplicate copies of apps across accounts when raising a more than one match error" do
83
+ do_include = "--environment='sumo_wrestler' --app='app_duplicate' --account='ey'"
84
+ do_not_include = "--environment='sumo_wrestler' --app='app_duplicate' --account='me'"
85
+ lambda do
86
+ resolver.app_and_environment(:repo => repo("git://github.com/repo/dup.git"))
87
+ end.should raise_error(EY::MultipleMatchesError) {|e|
88
+ e.message.should include(do_include)
89
+ e.message.should_not include(do_not_include)
90
+ }
91
+ end
92
+
93
+ it "returns one deployment whene there is only one match" do
94
+ resolver.app_and_environment(:account_name => "ey", :app_name => "big").should resolve_to(@big)
95
+ resolver.app_and_environment(:environment_name => "production").should resolve_to(@production)
96
+ resolver.app_and_environment(:repo => repo("git://github.com/repo/bigapp.git")).should resolve_to(@big)
97
+ resolver.app_and_environment(:repo => repo("git://github.com/repo/app.git"), :environment_name => "staging").should resolve_to(@staging)
98
+ end
99
+
100
+ it "returns the match when an app is specified even when there is a repo" do
101
+ resolver.app_and_environment(:account_name => "ey", :app_name => "bigapp", :repo => repo("git://github.com/repo/app.git")).should resolve_to(@big)
102
+ end
103
+
104
+ it "returns the specific match even if there is a partial match" do
105
+ resolver.app_and_environment(:environment_name => 'app_staging', :app_name => 'app').should resolve_to(@staging)
106
+ resolver.app_and_environment(:environment_name => "app_staging").should resolve_to(@staging)
107
+ resolver.app_and_environment(:app_name => "app", :environment_name => "staging").should resolve_to(@staging)
108
+ end
109
+
110
+ it "scopes searches under the correct account" do
111
+ resolver.app_and_environment(:account_name => "ey", :environment_name => "dup", :app_name => "dup").should resolve_to(@ey_dup)
112
+ resolver.app_and_environment(:account_name => "me", :environment_name => "dup").should resolve_to(@me_dup)
113
+ resolver.app_and_environment(:account_name => "me", :app_name => "dup").should resolve_to(@me_dup)
114
+ end
115
+ end
116
+ end
@@ -26,12 +26,13 @@ end
26
26
  describe "ey deploy" do
27
27
  given "integration"
28
28
 
29
- def command_to_run(options)
29
+ def command_to_run(opts)
30
30
  cmd = "deploy"
31
- cmd << " --environment #{options[:env]}" if options[:env]
32
- cmd << " --app #{options[:app]}" if options[:app]
33
- cmd << " --ref #{options[:ref]}" if options[:ref]
34
- cmd << " --verbose" if options[:verbose]
31
+ cmd << " --environment #{opts[:environment]}" if opts[:environment]
32
+ cmd << " --app #{opts[:app]}" if opts[:app]
33
+ cmd << " --account #{opts[:account]}" if opts[:account]
34
+ cmd << " --ref #{opts[:ref]}" if opts[:ref]
35
+ cmd << " --verbose" if opts[:verbose]
35
36
  cmd
36
37
  end
37
38
 
@@ -41,8 +42,7 @@ describe "ey deploy" do
41
42
  end
42
43
 
43
44
  # common behavior
44
- it_should_behave_like "it takes an environment name"
45
- it_should_behave_like "it takes an app name"
45
+ it_should_behave_like "it takes an environment name and an app name and an account name"
46
46
  it_should_behave_like "it invokes engineyard-serverside"
47
47
  end
48
48
 
@@ -59,13 +59,13 @@ describe "ey deploy" do
59
59
  it "complains when the specified environment does not contain the app" do
60
60
  api_scenario "one app, one environment, not linked"
61
61
  ey "deploy -e giblets -r master", :expect_failure => true
62
- @err.should match(/does not run this application/i)
62
+ @err.should match(/there is no application configured/i)
63
63
  end
64
64
 
65
65
  it "complains when environment is not specified and app is in >1 environment" do
66
66
  api_scenario "one app, many environments"
67
67
  ey "deploy", :expect_failure => true
68
- @err.should match(/single environment.*2/i)
68
+ @err.should match(/multiple app deployments possible/i)
69
69
  end
70
70
 
71
71
  it "complains when the app master is in a non-running state" do
@@ -354,4 +354,5 @@ describe "ey deploy" do
354
354
  @deploy_command.should =~ /--stack nginx_mongrel/
355
355
  end
356
356
  end
357
+
357
358
  end
@@ -10,6 +10,7 @@ describe "ey environments" do
10
10
 
11
11
  it "lists the environments your app is in" do
12
12
  ey "environments"
13
+ @out.should include('rails232app (main)')
13
14
  @out.should =~ /giblets/
14
15
  @out.should =~ /bakon/
15
16
  end
data/spec/ey/logs_spec.rb CHANGED
@@ -14,7 +14,7 @@ describe "ey logs" do
14
14
  it "complains when it can't infer the environment" do
15
15
  api_scenario "one app, many environments"
16
16
  ey "logs", :expect_failure => true
17
- @err.should =~ /single environment/
17
+ @err.should =~ /repository url in this directory is ambiguous/i
18
18
  end
19
19
  end
20
20
 
@@ -23,7 +23,8 @@ describe "ey logs" do
23
23
 
24
24
  def command_to_run(opts)
25
25
  cmd = "logs"
26
- cmd << " --environment #{opts[:env]}" if opts[:env]
26
+ cmd << " --environment #{opts[:environment]}" if opts[:environment]
27
+ cmd << " --account #{opts[:account]}" if opts[:account]
27
28
  cmd
28
29
  end
29
30
 
@@ -31,5 +32,5 @@ describe "ey logs" do
31
32
  @out.should match(/Main logs for #{scenario[:environment]}/)
32
33
  end
33
34
 
34
- it_should_behave_like "it takes an environment name"
35
+ it_should_behave_like "it takes an environment name and an account name"
35
36
  end
@@ -5,7 +5,8 @@ describe "ey rebuild" do
5
5
 
6
6
  def command_to_run(opts)
7
7
  cmd = "rebuild"
8
- cmd << " --environment #{opts[:env]}" if opts[:env]
8
+ cmd << " --environment #{opts[:environment]}" if opts[:environment]
9
+ cmd << " --account #{opts[:account]}" if opts[:account]
9
10
  cmd
10
11
  end
11
12
 
@@ -13,5 +14,5 @@ describe "ey rebuild" do
13
14
  @out.should =~ /Rebuilding #{scenario[:environment]}/
14
15
  end
15
16
 
16
- it_should_behave_like "it takes an environment name"
17
+ it_should_behave_like "it takes an environment name and an account name"
17
18
  end
@@ -5,7 +5,8 @@ describe "ey recipes apply" do
5
5
 
6
6
  def command_to_run(opts)
7
7
  cmd = "recipes apply"
8
- cmd << " -e #{opts[:env]}" if opts[:env]
8
+ cmd << " -e #{opts[:environment]}" if opts[:environment]
9
+ cmd << " --account #{opts[:account]}" if opts[:account]
9
10
  cmd
10
11
  end
11
12
 
@@ -13,7 +14,7 @@ describe "ey recipes apply" do
13
14
  @out.should =~ /Uploaded recipes started for #{scenario[:environment]}/
14
15
  end
15
16
 
16
- it_should_behave_like "it takes an environment name"
17
+ it_should_behave_like "it takes an environment name and an account name"
17
18
  end
18
19
 
19
20
  describe "ey recipes apply with an ambiguous git repo" do
@@ -2,14 +2,22 @@ require 'spec_helper'
2
2
 
3
3
  describe "ey recipes download" do
4
4
  given "integration"
5
+ use_git_repo('default')
5
6
 
6
- after(:each) do
7
+ before(:each) do
7
8
  FileUtils.rm_rf('cookbooks')
8
9
  end
9
10
 
11
+ after(:each) do
12
+ # This test creates + destroys the cookbooks/ directory, thus
13
+ # rendering the git repo unsuitable for reuse.
14
+ refresh_git_repo('default')
15
+ end
16
+
10
17
  def command_to_run(opts)
11
18
  cmd = "recipes download"
12
- cmd << " --environment #{opts[:env]}" if opts[:env]
19
+ cmd << " --environment #{opts[:environment]}" if opts[:environment]
20
+ cmd << " --account #{opts[:account]}" if opts[:account]
13
21
  cmd
14
22
  end
15
23
 
@@ -18,7 +26,7 @@ describe "ey recipes download" do
18
26
  File.read('cookbooks/README').should == "Remove this file to clone an upstream git repository of cookbooks\n"
19
27
  end
20
28
 
21
- it_should_behave_like "it takes an environment name"
29
+ it_should_behave_like "it takes an environment name and an account name"
22
30
 
23
31
  it "fails when cookbooks/ already exists" do
24
32
  api_scenario "one app, one environment"
@@ -11,7 +11,8 @@ describe "ey recipes upload" do
11
11
 
12
12
  def command_to_run(opts)
13
13
  cmd = "recipes upload"
14
- cmd << " --environment #{opts[:env]}" if opts[:env]
14
+ cmd << " --environment #{opts[:environment]}" if opts[:environment]
15
+ cmd << " --account #{opts[:account]}" if opts[:account]
15
16
  cmd
16
17
  end
17
18
 
@@ -19,7 +20,7 @@ describe "ey recipes upload" do
19
20
  @out.should =~ /Recipes uploaded successfully for #{scenario[:environment]}/
20
21
  end
21
22
 
22
- it_should_behave_like "it takes an environment name"
23
+ it_should_behave_like "it takes an environment name and an account name"
23
24
  end
24
25
 
25
26
  describe "ey recipes upload with an ambiguous git repo" do
@@ -5,8 +5,9 @@ describe "ey rollback" do
5
5
 
6
6
  def command_to_run(opts)
7
7
  cmd = "rollback"
8
- cmd << " -e #{opts[:env]}" if opts[:env]
8
+ cmd << " -e #{opts[:environment]}" if opts[:environment]
9
9
  cmd << " -a #{opts[:app]}" if opts[:app]
10
+ cmd << " -c #{opts[:account]}" if opts[:account]
10
11
  cmd << " --verbose" if opts[:verbose]
11
12
  cmd
12
13
  end
@@ -17,8 +18,7 @@ describe "ey rollback" do
17
18
  @ssh_commands.last.should match(/engineyard-serverside.*deploy rollback.*--app #{scenario[:application]}/)
18
19
  end
19
20
 
20
- it_should_behave_like "it takes an environment name"
21
- it_should_behave_like "it takes an app name"
21
+ it_should_behave_like "it takes an environment name and an app name and an account name"
22
22
  it_should_behave_like "it invokes engineyard-serverside"
23
23
 
24
24
  it "passes along the web server stack to engineyard-serverside" do
data/spec/ey/ssh_spec.rb CHANGED
@@ -22,13 +22,13 @@ shared_examples_for "running ey ssh for select role" do
22
22
  def command_to_run(opts)
23
23
  cmd = "ssh #{opts[:ssh_command]}"
24
24
  cmd << " #{@ssh_flag}"
25
- cmd << " --environment #{opts[:env]}" if opts[:env]
25
+ cmd << " --environment #{opts[:environment]}" if opts[:environment]
26
26
  cmd
27
27
  end
28
28
 
29
29
  it "runs the command on the right servers" do
30
30
  api_scenario "one app, one environment"
31
- run_ey(:ssh_command => "ls", :env => 'giblets', :verbose => true)
31
+ run_ey(:ssh_command => "ls", :environment => 'giblets', :verbose => true)
32
32
  @hosts.each do |host|
33
33
  @raw_ssh_commands.select do |command|
34
34
  command =~ /^ssh turkey@#{host}.+ ls$/
@@ -41,13 +41,13 @@ shared_examples_for "running ey ssh for select role" do
41
41
 
42
42
  it "raises an error when there are no matching hosts" do
43
43
  api_scenario "one app, one environment, no instances"
44
- run_ey({:ssh_command => "ls", :env => 'giblets', :verbose => true}, :expect_failure => true)
44
+ run_ey({:ssh_command => "ls", :environment => 'giblets', :verbose => true}, :expect_failure => true)
45
45
  end
46
46
 
47
47
  it "responds correctly when there is no command" do
48
48
  if @hosts.count != 1
49
49
  api_scenario "one app, one environment"
50
- run_ey({:env => 'giblets', :verbose => true}, :expect_failure => true)
50
+ run_ey({:environment => 'giblets', :verbose => true}, :expect_failure => true)
51
51
  end
52
52
  end
53
53
  end
@@ -77,7 +77,8 @@ describe "ey ssh without a command" do
77
77
 
78
78
  def command_to_run(opts)
79
79
  cmd = "ssh"
80
- cmd << " --environment #{opts[:env]}" if opts[:env]
80
+ cmd << " --environment #{opts[:environment]}" if opts[:environment]
81
+ cmd << " --account #{opts[:account]}" if opts[:account]
81
82
  cmd
82
83
  end
83
84
 
@@ -86,7 +87,7 @@ describe "ey ssh without a command" do
86
87
  @raw_ssh_commands.should == ["ssh #{ssh_target}"]
87
88
  end
88
89
 
89
- it_should_behave_like "it takes an environment name"
90
+ it_should_behave_like "it takes an environment name and an account name"
90
91
  end
91
92
 
92
93
  describe "ey ssh with a command" do
@@ -94,7 +95,8 @@ describe "ey ssh with a command" do
94
95
 
95
96
  def command_to_run(opts)
96
97
  cmd = "ssh ls"
97
- cmd << " --environment #{opts[:env]}" if opts[:env]
98
+ cmd << " --environment #{opts[:environment]}" if opts[:environment]
99
+ cmd << " --account #{opts[:account]}" if opts[:account]
98
100
  cmd
99
101
  end
100
102
 
@@ -103,7 +105,7 @@ describe "ey ssh with a command" do
103
105
  @raw_ssh_commands.should == ["ssh #{ssh_target} ls"]
104
106
  end
105
107
 
106
- it_should_behave_like "it takes an environment name"
108
+ it_should_behave_like "it takes an environment name and an account name"
107
109
  end
108
110
 
109
111
  describe "ey ssh --all" do