pagoda 0.3.2 → 0.5.0

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.
Files changed (65) hide show
  1. data/.DS_Store +0 -0
  2. data/Gemfile +3 -3
  3. data/Gemfile.lock +33 -24
  4. data/README.md +68 -0
  5. data/Rakefile +4 -7
  6. data/bin/pagoda +100 -8
  7. data/lib/pagoda/cli/commands/clone.rb +13 -0
  8. data/lib/pagoda/cli/commands/create.rb +13 -0
  9. data/lib/pagoda/cli/commands/deploy.rb +12 -0
  10. data/lib/pagoda/cli/commands/destroy.rb +16 -0
  11. data/lib/pagoda/cli/commands/info.rb +13 -0
  12. data/lib/pagoda/cli/commands/init.rb +13 -0
  13. data/lib/pagoda/cli/commands/list.rb +20 -0
  14. data/lib/pagoda/cli/commands/rename.rb +17 -0
  15. data/lib/pagoda/cli/commands/rollback.rb +12 -0
  16. data/lib/pagoda/cli/commands/ssh_key.rb +27 -0
  17. data/lib/pagoda/cli/commands/tunnel.rb +18 -0
  18. data/lib/pagoda/cli/commands.rb +11 -0
  19. data/lib/pagoda/{helpers.rb → cli/core_ext.rb} +10 -118
  20. data/lib/pagoda/cli/helpers/app.rb +143 -0
  21. data/lib/pagoda/cli/helpers/base.rb +199 -0
  22. data/lib/pagoda/cli/helpers/key.rb +69 -0
  23. data/lib/pagoda/cli/helpers/tunnel.rb +36 -0
  24. data/lib/pagoda/cli/helpers.rb +127 -0
  25. data/lib/pagoda/cli/override.rb +23 -0
  26. data/lib/pagoda/cli/version.rb +5 -0
  27. data/lib/pagoda/cli.rb +11 -0
  28. data/lib/pagoda-cli.rb +1 -0
  29. data/pagoda.gemspec +20 -24
  30. data/pagoda.rdoc +139 -0
  31. data/pkg/newpagoda-0.1.10.gem +0 -0
  32. data/pkg/newpagoda-0.1.11.gem +0 -0
  33. data/pkg/newpagoda-0.1.12.gem +0 -0
  34. data/pkg/newpagoda-0.1.13.gem +0 -0
  35. data/pkg/newpagoda-0.1.15.gem +0 -0
  36. data/pkg/newpagoda-0.1.4.gem +0 -0
  37. data/pkg/newpagoda-0.1.6.gem +0 -0
  38. data/pkg/newpagoda-0.1.7.gem +0 -0
  39. data/pkg/newpagoda-0.1.8.gem +0 -0
  40. data/pkg/newpagoda-0.1.9.gem +0 -0
  41. data/pkg/newpagoda-0.5.0.gem +0 -0
  42. data/spec/lib/helper_spec.rb +32 -0
  43. data/spec/lib/helpers/app_spec.rb +104 -0
  44. data/spec/lib/helpers/base_spec.rb +27 -0
  45. data/spec/lib/helpers/key_spec.rb +42 -0
  46. data/spec/lib/helpers/tunnel_spec.rb +30 -0
  47. data/spec/spec_helper.rb +17 -0
  48. metadata +74 -50
  49. data/.bundle/config +0 -1
  50. data/README +0 -3
  51. data/lib/pagoda/client.rb +0 -225
  52. data/lib/pagoda/command.rb +0 -96
  53. data/lib/pagoda/commands/app.rb +0 -247
  54. data/lib/pagoda/commands/auth.rb +0 -149
  55. data/lib/pagoda/commands/base.rb +0 -184
  56. data/lib/pagoda/commands/db.rb +0 -18
  57. data/lib/pagoda/commands/help.rb +0 -100
  58. data/lib/pagoda/commands/tunnel.rb +0 -49
  59. data/lib/pagoda/tunnel_proxy.rb +0 -130
  60. data/lib/pagoda/version.rb +0 -3
  61. data/lib/pagoda.rb +0 -3
  62. data/spec/base.rb +0 -21
  63. data/spec/client_spec.rb +0 -255
  64. data/spec/command_spec.rb +0 -26
  65. data/spec/commands/auth_spec.rb +0 -57
data/lib/pagoda/client.rb DELETED
@@ -1,225 +0,0 @@
1
- require 'pagoda/version'
2
- require 'rexml/document'
3
- require 'rest_client'
4
- require 'uri'
5
- require 'json/pure' unless {}.respond_to?(:to_json)
6
-
7
- class Pagoda::Client
8
-
9
- attr_reader :user, :password
10
-
11
- class << self
12
- def version
13
- Pagoda::VERSION
14
- end
15
-
16
- def gem_version_string
17
- "pagoda-gem/#{version}"
18
- end
19
- end
20
-
21
- def initialize(user, password)
22
- @user = user
23
- @password = password
24
- end
25
-
26
- def app_list
27
- doc = xml(get("/apps.xml").to_s)
28
- doc.elements['apps'].elements.to_a('//app/').inject([]) do |list, app|
29
- list << {
30
- :name => app.elements['name'].text,
31
- :instances => app.elements['instances'].text,
32
- :git_url => app.elements['git-url'].text
33
- }
34
- end
35
- end
36
-
37
- def database_exists?(app, mysql_instance)
38
- begin
39
- response = get("/apps/#{app}/databases/#{mysql_instance}.xml")
40
- true
41
- rescue RestClient::ResourceNotFound => e
42
- false
43
- end
44
-
45
- end
46
-
47
- def app_database_create(app)
48
- response = post("/apps/#{app}/databases.xml", {:mysql_instance => {:ram => 10}})
49
- end
50
-
51
- def app_create(name, git_url)
52
- doc = xml(post("/apps.xml", {:app => {:name => name, :git_url => git_url}}).to_s)
53
- doc.elements.to_a('//app/*').inject({}) do |hash, element|
54
- case element.name
55
- when "owner"
56
- hash[:owner] = {:username => element.elements['username'].text, :email => element.elements['email'].text}
57
- when "collaborators"
58
- hash[:collaborators] = element.elements.to_a('//collaborator/').inject([]) do |list, collaborator|
59
- list << {:username => collaborator.elements['username'].text, :email => collaborator.elements['email'].text}
60
- end
61
- when "transactions"
62
- hash[:transactions] = element.elements.to_a('//transaction/').inject([]) do |list, transaction|
63
- list << {
64
- :id => transaction.elements["id"].text,
65
- :name => transaction.elements["name"].text,
66
- :description => transaction.elements["description"].text,
67
- :state => transaction.elements["state"].text,
68
- :status => transaction.elements["status"].text
69
- }
70
- end
71
- else
72
- hash[element.name.gsub(/-/, '_').to_sym] = element.text
73
- end
74
- hash
75
- end
76
- end
77
-
78
- def app_info(app)
79
- doc = xml(get("/apps/#{app}.xml").to_s)
80
- doc.elements.to_a('//app/*').inject({}) do |hash, element|
81
- case element.name
82
- when "owner"
83
- hash[:owner] = {:username => element.elements['username'].text, :email => element.elements['email'].text}
84
- when "collaborators"
85
- hash[:collaborators] = element.elements.to_a('//collaborator/').inject([]) do |list, collaborator|
86
- list << {:username => collaborator.elements['username'].text, :email => collaborator.elements['email'].text}
87
- end
88
- when "transactions"
89
- hash[:transactions] = element.elements.to_a('//transaction/').inject([]) do |list, transaction|
90
- list << {
91
- :id => transaction.elements["id"].text,
92
- :name => transaction.elements["name"].text,
93
- :description => transaction.elements["description"].text,
94
- :state => transaction.elements["state"].text,
95
- :status => transaction.elements["status"].text
96
- }
97
- end
98
- else
99
- hash[element.name.gsub(/-/, '_').to_sym] = element.text
100
- end
101
- hash
102
- end
103
- end
104
-
105
- def app_update(app, updates)
106
- put("/apps/#{app}.xml", {:update => updates}).to_s
107
- end
108
-
109
- def app_destroy(app)
110
- delete("/apps/#{app}.xml").to_s
111
- end
112
-
113
- def transaction_list(app)
114
- doc = xml(get("/apps/#{app}/transactions.xml").to_s)
115
- doc.elements['transactions'].elements.to_a('//transaction/').inject([]) do |list, transaction|
116
- list << {
117
- :id => transaction.elements['id'].text,
118
- :name => transaction.elements['name'].text,
119
- :description => transaction.elements['description'].text,
120
- :state => transaction.elements['state'].text,
121
- :status => transaction.elements['status'].text
122
- }
123
- end
124
- end
125
-
126
- def transaction_status(app, transaction)
127
- doc = xml(get("/apps/#{app}/transactions/#{transaction}.xml").to_s)
128
- doc.elements.to_a('//transaction/*').inject({}) { |hash, element| hash[element.name.gsub(/-/, '_').to_sym] = element.text; hash }
129
- end
130
-
131
- def rewind(app, places=1)
132
- doc = xml(put("/apps/#{app}/rewind.xml", {:places => places}).to_s)
133
- doc.elements.to_a('//transaction/*').inject({}) { |hash, element| hash[element.name.gsub(/-/, '_').to_sym] = element.text; hash }
134
- end
135
-
136
- def fast_forward(app, places=1)
137
- doc = xml(put("/apps/#{app}/fast-forward.xml", {:places => places}).to_s)
138
- doc.elements.to_a('//transaction/*').inject({}) { |hash, element| hash[element.name.gsub(/-/, '_').to_sym] = element.text; hash }
139
- end
140
-
141
- def rollback(app)
142
- get("/apps/#{app}/rollback.xml").to_s
143
- end
144
-
145
- def deploy_latest(app)
146
- doc = xml(post("/apps/#{app}/deploy.xml").to_s)
147
- doc.elements.to_a('//transaction/*').inject({}) { |hash, element| hash[element.name.gsub(/-/, '_').to_sym] = element.text; hash }
148
- end
149
-
150
- def deploy(app, branch, commit)
151
- doc = xml(post("/apps/#{app}/deploy.xml", {:deploy => {:branch => branch, :commit => commit}}).to_s)
152
- doc.elements.to_a('//transaction/*').inject({}) { |hash, element| hash[element.name.gsub(/-/, '_').to_sym] = element.text; hash }
153
- end
154
-
155
- # def deploy(app)
156
- # doc = xml(put("/apps/#{app}/deploy.xml").to_s)
157
- # doc.elements.to_a('//transaction/*').inject({}) { |hash, element| hash[element.name.gsub(/-/, '_').to_sym] = element.text; hash }
158
- # end
159
-
160
- def scale_up(app, qty=1)
161
- doc = xml(put("/apps/#{app}/scale-up.xml").to_s)
162
- doc.elements.to_a('//transaction/*').inject({}) { |hash, element| hash[element.name.gsub(/-/, '_').to_sym] = element.text; hash }
163
- end
164
-
165
- def scale_down(app, qty=1)
166
- doc = xml(put("/apps/#{app}/scale-down.xml").to_s)
167
- doc.elements.to_a('//transaction/*').inject({}) { |hash, element| hash[element.name.gsub(/-/, '_').to_sym] = element.text; hash }
168
- end
169
-
170
- def app_databases(app)
171
- doc = xml(get("/apps/#{app}/databases.xml").to_s)
172
- doc.elements['databases'].elements.to_a('//database/').inject([]) {|list, instance| list << {:name => instance.elements['name'].text} }
173
- end
174
-
175
- def on_warning(&blk)
176
- @warning_callback = blk
177
- end
178
-
179
- protected
180
-
181
- def resource(uri)
182
- RestClient.proxy = ENV['HTTP_PROXY'] || ENV['http_proxy']
183
- if uri =~ /^https?/
184
- RestClient::Resource.new(uri, @user, @password)
185
- else
186
- # RestClient::Resource.new("http://127.0.0.1:3000#{uri}", @user, @password)
187
- RestClient::Resource.new("https://dashboard.pagodabox.com#{uri}", @user, @password)
188
- end
189
- end
190
-
191
- def get(uri, extra_headers={})
192
- process(:get, uri, extra_headers)
193
- end
194
-
195
- def post(uri, payload="", extra_headers={})
196
- process(:post, uri, extra_headers, payload)
197
- end
198
-
199
- def put(uri, payload="", extra_headers={})
200
- process(:put, uri, extra_headers, payload)
201
- end
202
-
203
- def delete(uri, extra_headers={})
204
- process(:delete, uri, extra_headers)
205
- end
206
-
207
- def process(method, uri, extra_headers={}, payload=nil)
208
- headers = pagoda_headers.merge(extra_headers)
209
- args = [method, payload, headers].compact
210
- response = resource(uri).send(*args)
211
- end
212
-
213
- def pagoda_headers
214
- {
215
- 'User-Agent' => self.class.gem_version_string,
216
- 'X-Ruby-Version' => RUBY_VERSION,
217
- 'X-Ruby-Platform' => RUBY_PLATFORM,
218
- }
219
- end
220
-
221
- def xml(raw) # :nodoc:
222
- REXML::Document.new(raw)
223
- end
224
-
225
- end
@@ -1,96 +0,0 @@
1
- require 'pagoda/helpers'
2
- require 'pagoda/tunnel_proxy'
3
- require 'pagoda/commands/base'
4
- require 'pagoda/commands/auth'
5
- require 'pagoda/commands/app'
6
- require 'pagoda/commands/db'
7
- require 'pagoda/commands/help'
8
- require 'pagoda/commands/tunnel'
9
-
10
- module Pagoda
11
- module Command
12
- class InvalidCommand < RuntimeError; end
13
- class CommandFailed < RuntimeError; end
14
-
15
- extend Pagoda::Helpers
16
-
17
- class << self
18
-
19
- def run(command, args, retries=0)
20
- begin
21
- run_internal 'auth:reauthorize', args.dup if retries > 0
22
- run_internal(command, args.dup)
23
- rescue InvalidCommand
24
- error "Unknown command: #{command}. Run 'pagoda help' for usage information."
25
- rescue RestClient::Unauthorized
26
- if retries < 3
27
- STDERR.puts "Authentication failure"
28
- run(command, args, retries+1)
29
- else
30
- error "Authentication failure"
31
- end
32
- rescue RestClient::ResourceNotFound => e
33
- error extract_not_found(e.http_body)
34
- rescue RestClient::RequestFailed => e
35
- error extract_error(e.http_body) unless e.http_code == 402 || e.http_code == 102
36
- rescue RestClient::RequestTimeout
37
- error "API request timed out. Please try again, or contact support@pagodagrid.com if this issue persists."
38
- rescue CommandFailed => e
39
- error e.message
40
- rescue Interrupt => e
41
- error "\n[canceled]"
42
- end
43
- end
44
-
45
- def run_internal(command, args)
46
- klass, method = parse(command)
47
- runner = klass.new(args)
48
- raise InvalidCommand unless runner.respond_to?(method)
49
- runner.send(method)
50
- end
51
-
52
- def parse(command)
53
- parts = command.split(':')
54
- case parts.size
55
- when 1
56
- begin
57
- return eval("Pagoda::Command::#{command.capitalize}"), :index
58
- rescue NameError, NoMethodError
59
- return Pagoda::Command::App, command.to_sym
60
- end
61
- else
62
- begin
63
- const = Pagoda::Command
64
- command = parts.pop
65
- parts.each { |part| const = const.const_get(part.capitalize) }
66
- return const, command.to_sym
67
- rescue NameError
68
- raise InvalidCommand
69
- end
70
- end
71
- end
72
-
73
- def extract_not_found(body)
74
- body =~ /^[\w\s]+ not found$/ ? body : "Resource not found"
75
- end
76
-
77
- def extract_error(body)
78
- msg = parse_error_xml(body) || parse_error_json(body) || 'Internal server error'
79
- end
80
-
81
- def parse_error_xml(body)
82
- xml_errors = REXML::Document.new(body).elements.to_a("//errors/error")
83
- msg = xml_errors.map { |a| a.text }.join(" / ")
84
- return msg unless msg.empty?
85
- rescue Exception
86
- end
87
-
88
- def parse_error_json(body)
89
- json = JSON.parse(body.to_s)
90
- json['error']
91
- rescue JSON::ParserError
92
- end
93
- end
94
-
95
- end
96
- end
@@ -1,247 +0,0 @@
1
- module Pagoda::Command
2
- class App < Base
3
-
4
- def list
5
- apps = client.app_list
6
- if !apps.empty?
7
- display
8
- display "APPS"
9
- display "//////////////////////////////////"
10
- display
11
- apps.each do |app|
12
- display "- #{app[:name]}"
13
- end
14
- else
15
- error ["looks like you haven't launched any apps", "type 'pagoda launch' to launch this project"]
16
- end
17
- display
18
- end
19
-
20
- def create
21
- if app_name = app(true)
22
- error ["This project is already launched and paired to #{app_name}.", "To unpair run 'pagoda unpair'"]
23
- end
24
-
25
- unless locate_app_root
26
- error ["Unable to find git config in this directory or in any parent directory"]
27
- end
28
-
29
- unless clone_url = extract_git_clone_url
30
- errors = []
31
- errors << "It appears you are using git (fantastic)."
32
- errors << "However we only support git repos hosted with github."
33
- errors << "Please ensure your repo is hosted with github."
34
- error errors
35
- end
36
-
37
- unless name = args.dup.shift
38
- error "Please Specify an app name ie. 'pagoda launch awesomeapp'"
39
- end
40
-
41
- display
42
- display "+> Registering #{name}"
43
- app = client.app_create(name, clone_url)
44
- display "+> Launching...", false
45
- loop_transaction(name)
46
- add_app(name, clone_url)
47
- display "+> #{name} launched"
48
-
49
- unless option_value(nil, "--latest")
50
- Pagoda::Command.run_internal("app:deploy", args)
51
- end
52
-
53
- if option_value(nil, "--with-mysql")
54
- Pagoda::Command.run_internal("db:create", args)
55
- end
56
-
57
- display "-----------------------------------------------"
58
- display
59
- display "LIVE URL : http://#{name}.pagodabox.com"
60
- display "ADMIN PANEL : http://dashboard.pagodabox.com"
61
- display
62
- display "-----------------------------------------------"
63
- display
64
-
65
- end
66
- alias :launch :create
67
- alias :register :create
68
-
69
- def destroy
70
- display
71
- if confirm ["Are you totally completely sure you want to delete #{app} forever and ever?", "THIS CANNOT BE UNDONE! (y/n)"]
72
- display "+> Destroying #{app}"
73
- client.app_destroy(app)
74
- display "+> #{app} has been successfully destroyed. RIP #{app}."
75
- remove_app(app)
76
- end
77
- display
78
- end
79
- alias :delete :destroy
80
-
81
- def info
82
- display
83
- info = client.app_info(app)
84
- display "INFO - #{info[:name]}"
85
- display "//////////////////////////////////"
86
- display "name : #{info[:name]}"
87
- display "clone_url : #{info[:git_url]}"
88
- display
89
- display "owner"
90
- display "username : #{info[:owner][:username]}", true, 2
91
- display "email : #{info[:owner][:email]}", true, 2
92
- display
93
- display "collaborators"
94
- if info[:collaborators].any?
95
- info[:collaborators].each_with_index do |collaborator, index|
96
- display "username : #{collaborator[:username]}", true, 2
97
- display "email : #{collaborator[:email]}", true, 2
98
- end
99
- else
100
- display "(none)", true, 2
101
- end
102
- display
103
- end
104
-
105
- def pair
106
-
107
- if app_name = app(true)
108
- error ["This project is paired to #{app_name}.", "To unpair run 'pagoda unpair'"]
109
- end
110
-
111
- unless locate_app_root
112
- error ["Unable to find git config in this directory or in any parent directory"]
113
- end
114
-
115
- unless my_repo = extract_git_clone_url
116
- errors = []
117
- errors << "It appears you are using git (fantastic)."
118
- errors << "However we only support git repos hosted with github."
119
- errors << "Please ensure your repo is hosted with github."
120
- error errors
121
- end
122
-
123
- display
124
- display "+> Locating deployed app with matching git repo"
125
-
126
- apps = client.app_list
127
-
128
- matching_apps = []
129
- apps.each do |a|
130
- if a[:git_url] == my_repo
131
- matching_apps.push a
132
- end
133
- end
134
-
135
- if matching_apps.count > 1
136
- if name = app(true) || args.dup.shift
137
- assign_app = nil
138
- matching_apps.each do |a|
139
- assign_app = a if a[:name] == name
140
- end
141
- if assign_app
142
- display "+> Pairing this repo to deployed app - #{assign_app[:name]}"
143
- pair_with_remote(assign_app)
144
- display "+> Repo is now paired to '#{assign_app[:name]}'"
145
- display
146
- else
147
- error "#{name} is not found among your launched app list"
148
- end
149
- else
150
- errors = []
151
- errors << "Multiple matches found"
152
- errors << ""
153
- matching_apps.each do |match|
154
- errors << "-> #{match[:name]}"
155
- end
156
- errors << ""
157
- errors << "You have more then one app that uses this repo."
158
- errors << "Please specify which app you would like to pair to."
159
- errors << ""
160
- errors << "ex: pagoda pair #{matching_apps[0][:name]}"
161
- error errors
162
- end
163
- elsif matching_apps.count == 1
164
- match = matching_apps.first
165
- display "+> Pairing this repo to deployed app - #{match[:name]}"
166
- pair_with_remote match
167
- display "+> Repo is now paired to '#{match[:name]}'"
168
- display
169
- else
170
- error "Current git repo doesn't match any launched app repos"
171
- end
172
- end
173
-
174
- def unpair
175
- app
176
- display
177
- display "+> Unpairing this repo"
178
- remove_app(app)
179
- display "+> Free at last!"
180
- display
181
- end
182
-
183
- def deploy
184
- app
185
- display
186
- branch = parse_branch
187
- commit = parse_commit
188
- if option_value(nil, "--latest")
189
- client.deploy_latest(app)
190
- display "+> deploying to latest commit point on github...", false
191
- loop_transaction
192
- display "+> deployed"
193
- display
194
- else
195
- client.deploy(app, branch, commit)
196
- display "+> deploying current branch and commit...", false
197
- loop_transaction
198
- display "+> deployed"
199
- display
200
- end
201
- end
202
-
203
- def rewind
204
- app
205
- display
206
- transaction = client.rewind(app)
207
- display "+> undo...", false
208
- loop_transaction
209
- display "+> done"
210
- display
211
- end
212
- alias :rollback :rewind
213
- alias :undo :rewind
214
-
215
- def fast_forward
216
- app
217
- display
218
- transaction = client.fast_forward(app)
219
- display "+> redo...", false
220
- loop_transaction
221
- display "+> done"
222
- display
223
- end
224
- alias :fastforward :fast_forward
225
- alias :forward :fast_forward
226
- alias :redo :fast_forward
227
-
228
- protected
229
-
230
- def pair_with_remote(app)
231
- my_app_list = read_apps
232
- current_root = locate_app_root
233
- in_list = false
234
- my_app_list.each do |app_str|
235
- app_arr = app_str.split(" ")
236
- if app[:git_url] == app_arr[1] && app[:name] == app_arr[0] || app_arr[2] == current_root
237
- in_list = true
238
- end
239
- end
240
- unless in_list
241
- add_app app[:name]
242
- end
243
- end
244
-
245
-
246
- end
247
- end