engineyard 1.3.20 → 1.3.21

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,5 +1,24 @@
1
1
  = ey
2
2
 
3
+ == Login
4
+
5
+ The first command you run will notice that you are not logged in and will ask you for your AppCloud email and password.
6
+
7
+ == Configuration
8
+
9
+ The ey.yml file allows options to be saved for each environment to which an application is deployed. Here's an example ey.yml file in RAILS_ROOT/config/ey.yml:
10
+
11
+ $ cat config/ey.yml
12
+ ---
13
+ environments:
14
+ env_production:
15
+ migrate: false
16
+ migration_command: rake fancy:migrate
17
+ branch: deploy
18
+
19
+ This ey.yml file wile turn off default migrations, set the default command to "rake fancy:migrate" and set the default deploy branch to "deploy".
20
+
21
+ == Commands
3
22
 
4
23
  Command:
5
24
  ey deploy
@@ -17,11 +36,15 @@ Command:
17
36
 
18
37
 
19
38
  Description:
20
- This command must be run with the current directory containing the app to be deployed. If ey.yml specifies a default branch then the ref parameter can be omitted. Furthermore,
21
- if a default branch is specified but a different command is supplied the deploy will fail unless --ignore-default-branch is used.
22
-
23
- Migrations are run by default with 'rake db:migrate'. A different command can be specified via --migrate "ruby do_migrations.rb". Migrations can also be skipped entirely by
24
- using --no-migrate.
39
+ This command must be run with the current directory containing the app to be
40
+ deployed. If ey.yml specifies a default branch then the ref parameter can be
41
+ omitted. Furthermore, if a default branch is specified but a different
42
+ command is supplied the deploy will fail unless --ignore-default-branch
43
+ is used.
44
+
45
+ Migrations are run by default with 'rake db:migrate'. A different command
46
+ can be specified via --migrate "ruby do_migrations.rb". Migrations can also
47
+ be skipped entirely by using --no-migrate.
25
48
 
26
49
  Command:
27
50
  ey environments
@@ -0,0 +1,135 @@
1
+ require 'engineyard/model'
2
+
3
+ module EngineYard
4
+ class APIClient
5
+ attr_reader :token
6
+
7
+ USER_AGENT_STRING = "EngineYardAPIClient/#{VERSION}"
8
+
9
+ def initialize(token = nil)
10
+ @token ||= token
11
+ @token ||= self.class.read_token
12
+ raise ArgumentError, "EY Cloud API token required" unless @token
13
+ end
14
+
15
+ def ==(other)
16
+ raise ArgumentError unless other.is_a?(self.class)
17
+ self.token == other.token
18
+ end
19
+
20
+ def request(url, opts={})
21
+ opts[:headers] ||= {}
22
+ opts[:headers]["X-EY-Cloud-Token"] = token
23
+ EY.ui.debug("Token", token)
24
+ self.class.request(url, opts)
25
+ end
26
+
27
+ def environments
28
+ @environments ||= Environment.from_array(request('/environments')["environments"], :api => self)
29
+ end
30
+
31
+ def apps
32
+ @apps ||= App.from_array(request('/apps')["apps"], :api => self)
33
+ end
34
+
35
+ def resolver
36
+ @resolver ||= Resolver.new(self)
37
+ end
38
+
39
+ def apps_for_repo(repo)
40
+ repo.fail_on_no_remotes!
41
+ apps.find_all {|a| repo.has_remote?(a.repository_uri) }
42
+ end
43
+
44
+ class InvalidCredentials < EY::AppCloudClient::Error; end
45
+ class RequestFailed < EY::AppCloudClient::Error; end
46
+
47
+ def self.request(path, opts={})
48
+ require 'rest_client'
49
+ require 'json'
50
+
51
+ url = EY.config.endpoint + "api/v2#{path}"
52
+ method = (opts.delete(:method) || 'get').to_s.downcase.to_sym
53
+ params = opts.delete(:params) || {}
54
+ headers = opts.delete(:headers) || {}
55
+ headers["Accept"] ||= "application/json"
56
+ headers["User-Agent"] = USER_AGENT_STRING
57
+
58
+ begin
59
+ EY.ui.debug("Request", "#{method.to_s.upcase} #{url}")
60
+ case method
61
+ when :get, :delete, :head
62
+ url.query = RestClient::Payload::UrlEncoded.new(params).to_s
63
+ resp = RestClient.send(method, url.to_s, headers)
64
+ else
65
+ resp = RestClient.send(method, url.to_s, params, headers)
66
+ end
67
+ rescue RestClient::Unauthorized
68
+ raise InvalidCredentials
69
+ rescue Errno::ECONNREFUSED
70
+ raise RequestFailed, "Could not reach the cloud API"
71
+ rescue RestClient::ResourceNotFound
72
+ raise RequestFailed, "The requested resource could not be found"
73
+ rescue RestClient::BadGateway
74
+ raise RequestFailed, "AppCloud API is temporarily unavailable. Please try again soon."
75
+ rescue RestClient::RequestFailed => e
76
+ raise RequestFailed, "#{e.message} #{e.response}"
77
+ rescue OpenSSL::SSL::SSLError
78
+ raise RequestFailed, "SSL is misconfigured on your cloud"
79
+ end
80
+
81
+ if resp.body.empty?
82
+ data = ''
83
+ elsif resp.headers[:content_type] =~ /application\/json/
84
+ begin
85
+ data = JSON.parse(resp.body)
86
+ EY.ui.debug("Response", data)
87
+ rescue JSON::ParserError
88
+ EY.ui.debug("Raw response", resp.body)
89
+ raise RequestFailed, "Response was not valid JSON."
90
+ end
91
+ else
92
+ data = resp.body
93
+ end
94
+
95
+ data
96
+ end
97
+
98
+ def self.fetch_token(email, password)
99
+ api_token = request("/authenticate", :method => "post",
100
+ :params => { :email => email, :password => password })["api_token"]
101
+ save_token(api_token)
102
+ api_token
103
+ end
104
+
105
+ def self.read_token(file = nil)
106
+ file ||= ENV['EYRC'] || File.expand_path("~/.eyrc")
107
+ return false unless File.exists?(file)
108
+
109
+ require 'yaml'
110
+
111
+ data = YAML.load_file(file)
112
+ if EY.config.default_endpoint?
113
+ data["api_token"]
114
+ else
115
+ (data[EY.config.endpoint.to_s] || {})["api_token"]
116
+ end
117
+ end
118
+
119
+ def self.save_token(token, file = nil)
120
+ file ||= ENV['EYRC'] || File.expand_path("~/.eyrc")
121
+ require 'yaml'
122
+
123
+ data = File.exists?(file) ? YAML.load_file(file) : {}
124
+ if EY.config.default_endpoint?
125
+ data.merge!("api_token" => token)
126
+ else
127
+ data.merge!(EY.config.endpoint.to_s => {"api_token" => token})
128
+ end
129
+
130
+ File.open(file, "w"){|f| YAML.dump(data, f) }
131
+ true
132
+ end
133
+
134
+ end # API
135
+ end # EY
@@ -122,7 +122,7 @@ module EY
122
122
  message << "The following environments contain those applications:\n\n"
123
123
  EY.ui.warn(message)
124
124
  elsif apps.empty?
125
- EY.ui.warn(NoAppError.new(repo).message)
125
+ EY.ui.warn(NoAppError.new(repo).message + "\nUse #{self.class.send(:banner_base)} environments --all to see all environments.")
126
126
  end
127
127
 
128
128
  EY.ui.print_envs(apps, EY.config.default_environment, options[:simple])
@@ -11,9 +11,9 @@ Specify --account ACCOUNT_NAME to resolve this ambiguity.
11
11
  def named(name, account_name=nil)
12
12
  candidates = find_all do |x|
13
13
  if account_name
14
- x.name == name && x.account.name == account_name
14
+ x.name.downcase == name.downcase && x.account.name.downcase == account_name.downcase
15
15
  else
16
- x.name == name
16
+ x.name.downcase == name.downcase
17
17
  end
18
18
  end
19
19
  if candidates.size > 1
@@ -33,7 +33,7 @@ Specify --account ACCOUNT_NAME to resolve this ambiguity.
33
33
  private
34
34
 
35
35
  def find_by_unambiguous_substring(name_part)
36
- candidates = find_all{|e| e.name[name_part] }
36
+ candidates = find_all{|e| e.name.downcase[name_part.downcase] }
37
37
  if candidates.size > 1
38
38
  raise ambiguous_error(name_part, candidates.map {|e| e.name})
39
39
  end
@@ -83,7 +83,7 @@ module EY
83
83
  def upload_recipes_at_path(recipes_path)
84
84
  recipes_path = Pathname.new(recipes_path)
85
85
  if recipes_path.exist?
86
- upload_recipes recipes_path.open('r')
86
+ upload_recipes recipes_path.open('rb')
87
87
  else
88
88
  raise EY::Error, "Recipes file not found: #{recipes_path}"
89
89
  end
@@ -64,7 +64,7 @@ module EY
64
64
  message = "Multiple app deployments possible, please be more specific:\n\n"
65
65
  candidates.map{|c| [c[:account_name], c[:app_name]]}.uniq.each do |account_name, app_name|
66
66
  message << "#{app_name}\n"
67
- candidates.select {|x| x[:app_name] == app_name && x[:account_name] == account_name}.map{|x| x[:environment_name]}.uniq.each do |env_name|
67
+ candidates.select {|c| c[:app_name] == app_name && c[:account_name] == account_name}.map{|c| c[:environment_name]}.uniq.each do |env_name|
68
68
  message << "\t#{env_name} # ey <command> --environment='#{env_name}' --app='#{app_name}' --account='#{account_name}'\n"
69
69
  end
70
70
  end
@@ -80,10 +80,10 @@ module EY
80
80
  @app_deployments ||= api.apps.map do |app|
81
81
  app.environments.map do |environment|
82
82
  {
83
- :app_name => app.name,
83
+ :app_name => app.name.downcase,
84
84
  :repository_uri => app.repository_uri,
85
- :environment_name => environment.name,
86
- :account_name => app.account.name,
85
+ :environment_name => environment.name.downcase,
86
+ :account_name => app.account.name.downcase,
87
87
  }
88
88
  end
89
89
  end.flatten
@@ -122,10 +122,10 @@ module EY
122
122
  end
123
123
 
124
124
  def filter_candidates_by(type, options, candidates)
125
- if options[type] && candidates.any?{|c| c[type] == options[type] }
126
- candidates.select {|c| c[type] == options[type] }
125
+ if options[type] && candidates.any?{|c| c[type] == options[type].downcase }
126
+ candidates.select {|c| c[type] == options[type].downcase }
127
127
  elsif options[type]
128
- candidates.select {|c| c[type][options[type]] }
128
+ candidates.select {|c| c[type][options[type].downcase] }
129
129
  else
130
130
  candidates
131
131
  end
@@ -1,3 +1,3 @@
1
1
  module EY
2
- VERSION = '1.3.20'
2
+ VERSION = '1.3.21'
3
3
  end
@@ -95,6 +95,11 @@ describe EY::Resolver do
95
95
  resolver.app_and_environment(:repo => repo("git://github.com/repo/app.git"), :environment_name => "staging").should resolve_to(@staging)
96
96
  end
97
97
 
98
+ it "doesn't care about case" do
99
+ resolver.app_and_environment(:account_name => "EY", :app_name => "big").should resolve_to(@big)
100
+ resolver.app_and_environment(:account_name => "ey", :app_name => "BiG").should resolve_to(@big)
101
+ end
102
+
98
103
  it "returns the match when an app is specified even when there is a repo" do
99
104
  resolver.app_and_environment(:account_name => "ey", :app_name => "bigapp", :repo => repo("git://github.com/repo/app.git")).should resolve_to(@big)
100
105
  end
@@ -4,41 +4,53 @@ describe "ey environments" do
4
4
 
5
5
  given "integration"
6
6
 
7
- before(:all) do
8
- api_scenario "one app, many environments"
9
- end
7
+ context "with no apps" do
8
+ before do
9
+ api_scenario "empty"
10
+ end
10
11
 
11
- it "lists the environments your app is in" do
12
- ey %w[environments]
13
- @out.should include('rails232app (main)')
14
- @out.should =~ /giblets/
15
- @out.should =~ /bakon/
12
+ it "suggests that you use environments --all" do
13
+ ey %w[environments]
14
+ @out.should =~ /Use ey environments --all to see all environments./
15
+ end
16
16
  end
17
17
 
18
- it "reports failure to find a git repo when not in one" do
19
- Dir.chdir("/tmp") do
20
- ey %w[environments], :expect_failure => true
21
- @err.should =~ /fatal: No git remotes found in .*\/tmp/
22
- @out.should_not =~ /no application configured/
18
+ context "with apps" do
19
+ before(:all) do
20
+ api_scenario "one app, many environments"
23
21
  end
24
- end
25
22
 
26
- it "lists all environments that have apps with -a" do
27
- ey %w[environments -a]
28
- @out.should include("bakon")
29
- @out.should include("giblets")
30
- end
23
+ it "lists the environments your app is in" do
24
+ ey %w[environments]
25
+ @out.should include('rails232app (main)')
26
+ @out.should =~ /giblets/
27
+ @out.should =~ /bakon/
28
+ end
31
29
 
32
- it "outputs simply with -s" do
33
- ey %w[environments -s], :debug => false
34
- @out.split(/\n/).sort.should == ["bakon", "giblets"]
35
- end
30
+ it "reports failure to find a git repo when not in one" do
31
+ Dir.chdir("/tmp") do
32
+ ey %w[environments], :expect_failure => true
33
+ @err.should =~ /fatal: No git remotes found in .*\/tmp/
34
+ @out.should_not =~ /no application configured/
35
+ end
36
+ end
36
37
 
37
- it "outputs all environments (including ones with no apps) simply with -a and -s" do
38
- ey %w[environments -a -s], :debug => false
39
- @out.split(/\n/).sort.should == ["bakon", "beef", "giblets"]
40
- end
38
+ it "lists all environments that have apps with -a" do
39
+ ey %w[environments -a]
40
+ @out.should include("bakon")
41
+ @out.should include("giblets")
42
+ end
41
43
 
44
+ it "outputs simply with -s" do
45
+ ey %w[environments -s], :debug => false
46
+ @out.split(/\n/).sort.should == ["bakon", "giblets"]
47
+ end
48
+
49
+ it "outputs all environments (including ones with no apps) simply with -a and -s" do
50
+ ey %w[environments -a -s], :debug => false
51
+ @out.split(/\n/).sort.should == ["bakon", "beef", "giblets"]
52
+ end
53
+ end
42
54
  end
43
55
 
44
56
  describe "ey environments with an ambiguous git repo" do
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: engineyard
3
3
  version: !ruby/object:Gem::Version
4
- hash: 51
4
+ hash: 49
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 3
9
- - 20
10
- version: 1.3.20
9
+ - 21
10
+ version: 1.3.21
11
11
  platform: ruby
12
12
  authors:
13
13
  - EY Cloud Team
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-05-27 00:00:00 -07:00
18
+ date: 2011-08-03 00:00:00 -07:00
19
19
  default_executable: ey
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -102,12 +102,12 @@ dependencies:
102
102
  requirements:
103
103
  - - "="
104
104
  - !ruby/object:Gem::Version
105
- hash: 5
105
+ hash: 3
106
106
  segments:
107
107
  - 1
108
108
  - 4
109
- - 1
110
- version: 1.4.1
109
+ - 2
110
+ version: 1.4.2
111
111
  name: engineyard-serverside-adapter
112
112
  prerelease: false
113
113
  type: :runtime
@@ -297,6 +297,7 @@ files:
297
297
  - lib/engineyard/ruby_ext.rb
298
298
  - lib/engineyard/thor.rb
299
299
  - lib/engineyard/version.rb
300
+ - lib/engineyard-api-client.rb
300
301
  - lib/engineyard.rb
301
302
  - LICENSE
302
303
  - README.rdoc