engineyard 1.3.1 → 1.3.2

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.
@@ -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