engineyard 1.3.20 → 1.3.21

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/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