PageRenderTime 36ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/heroku/command/apps.rb

https://github.com/kch/heroku
Ruby | 320 lines | 207 code | 40 blank | 73 comment | 36 complexity | 8b55b4dc6ab8b829674d5894c9ca8304 MD5 | raw file
  1. require "heroku/command/base"
  2. # manage apps (create, destroy)
  3. #
  4. class Heroku::Command::Apps < Heroku::Command::Base
  5. # apps
  6. #
  7. # list your apps
  8. #
  9. #Example:
  10. #
  11. # $ heroku apps
  12. # === My Apps
  13. # myapp1
  14. # myapp2
  15. #
  16. # === Collaborated Apps
  17. # theirapp1 other@owner.name
  18. #
  19. def index
  20. validate_arguments!
  21. apps = api.get_apps.body
  22. unless apps.empty?
  23. my_apps, collaborated_apps = apps.partition do |app|
  24. app["owner_email"] == Heroku::Auth.user
  25. end
  26. unless my_apps.empty?
  27. styled_header("My Apps")
  28. styled_array(my_apps.map { |app| app["name"] })
  29. end
  30. unless collaborated_apps.empty?
  31. styled_header("Collaborated Apps")
  32. styled_array(collaborated_apps.map { |app| [app["name"], app["owner_email"]] })
  33. end
  34. else
  35. display("You have no apps.")
  36. end
  37. end
  38. alias_command "list", "apps"
  39. # apps:info
  40. #
  41. # show detailed app information
  42. #
  43. # -s, --shell # output more shell friendly key/value pairs
  44. #
  45. #Examples:
  46. #
  47. # $ heroku apps:info
  48. # === myapp
  49. # Git URL: git@heroku.com:myapp.git
  50. # Repo Size: 5M
  51. # ...
  52. #
  53. # $ heroku apps:info --shell
  54. # git_url=git@heroku.com:myapp.git
  55. # repo_size=5000000
  56. # ...
  57. #
  58. def info
  59. validate_arguments!
  60. app_data = api.get_app(app).body
  61. unless options[:shell]
  62. styled_header(app_data["name"])
  63. end
  64. addons_data = api.get_addons(app).body.map {|addon| addon['name']}.sort
  65. collaborators_data = api.get_collaborators(app).body.map {|collaborator| collaborator["email"]}.sort
  66. collaborators_data.reject! {|email| email == app_data["owner_email"]}
  67. if options[:shell]
  68. if app_data['domain_name']
  69. app_data['domain_name'] = app_data['domain_name']['domain']
  70. end
  71. unless addons_data.empty?
  72. app_data['addons'] = addons_data.join(',')
  73. end
  74. unless collaborators_data.empty?
  75. app_data['collaborators'] = collaborators_data.join(',')
  76. end
  77. app_data.keys.sort_by { |a| a.to_s }.each do |key|
  78. hputs("#{key}=#{app_data[key]}")
  79. end
  80. else
  81. data = {}
  82. unless addons_data.empty?
  83. data["Addons"] = addons_data
  84. end
  85. data["Collaborators"] = collaborators_data
  86. if app_data["create_status"] && app_data["create_status"] != "complete"
  87. data["Create Status"] = app_data["create_status"]
  88. end
  89. if app_data["cron_finished_at"]
  90. data["Cron Finished At"] = format_date(app_data["cron_finished_at"])
  91. end
  92. if app_data["cron_next_run"]
  93. data["Cron Next Run"] = format_date(app_data["cron_next_run"])
  94. end
  95. if app_data["database_size"]
  96. data["Database Size"] = format_bytes(app_data["database_size"])
  97. end
  98. data["Git URL"] = app_data["git_url"]
  99. if app_data["database_tables"]
  100. data["Database Size"].gsub!('(empty)', '0K') + " in #{quantify("table", app_data["database_tables"])}"
  101. end
  102. if app_data["dyno_hours"].is_a?(Hash)
  103. data["Dyno Hours"] = app_data["dyno_hours"].keys.map do |type|
  104. "%s - %0.2f dyno-hours" % [ type.to_s.capitalize, app_data["dyno_hours"][type] ]
  105. end
  106. end
  107. data["Owner Email"] = app_data["owner_email"]
  108. if app_data["region"]
  109. data["Region"] = app_data["region"]
  110. end
  111. if app_data["repo_size"]
  112. data["Repo Size"] = format_bytes(app_data["repo_size"])
  113. end
  114. if app_data["slug_size"]
  115. data["Slug Size"] = format_bytes(app_data["slug_size"])
  116. end
  117. data["Stack"] = app_data["stack"]
  118. if data["Stack"] != "cedar"
  119. data.merge!("Dynos" => app_data["dynos"], "Workers" => app_data["workers"])
  120. end
  121. data["Web URL"] = app_data["web_url"]
  122. styled_hash(data)
  123. end
  124. end
  125. alias_command "info", "apps:info"
  126. # apps:create [NAME]
  127. #
  128. # create a new app
  129. #
  130. # --addons ADDONS # a comma-delimited list of addons to install
  131. # -b, --buildpack BUILDPACK # a buildpack url to use for this app
  132. # -n, --no-remote # don't create a git remote
  133. # -r, --remote REMOTE # the git remote to create, default "heroku"
  134. # -s, --stack STACK # the stack on which to create the app
  135. #
  136. #Examples:
  137. #
  138. # $ heroku apps:create
  139. # Creating floating-dragon-42... done, stack is cedar
  140. # http://floating-dragon-42.heroku.com/ | git@heroku.com:floating-dragon-42.git
  141. #
  142. # $ heroku apps:create -s bamboo
  143. # Creating floating-dragon-42... done, stack is bamboo-mri-1.9.2
  144. # http://floating-dragon-42.herokuapp.com/ | git@heroku.com:floating-dragon-42.git
  145. #
  146. # # specify a name
  147. # $ heroku apps:create myapp
  148. # Creating myapp... done, stack is cedar
  149. # http://myapp.heroku.com/ | git@heroku.com:myapp.git
  150. #
  151. # # create a staging app
  152. # $ heroku apps:create myapp-staging --remote staging
  153. #
  154. def create
  155. name = shift_argument || options[:app] || ENV['HEROKU_APP']
  156. region = options.delete(:region) # don't validate this arg
  157. validate_arguments!
  158. info = api.post_app({
  159. "name" => name,
  160. "region" => region,
  161. "stack" => options[:stack]
  162. }).body
  163. begin
  164. action("Creating #{info['name']}") do
  165. if info['create_status'] == 'creating'
  166. Timeout::timeout(options[:timeout].to_i) do
  167. loop do
  168. break if api.get_app(info['name']).body['create_status'] == 'complete'
  169. sleep 1
  170. end
  171. end
  172. end
  173. status("stack is #{info['stack']}")
  174. end
  175. (options[:addons] || "").split(",").each do |addon|
  176. addon.strip!
  177. action("Adding #{addon} to #{info["name"]}") do
  178. api.post_addon(info["name"], addon)
  179. end
  180. end
  181. if buildpack = options[:buildpack]
  182. api.put_config_vars(info["name"], "BUILDPACK_URL" => buildpack)
  183. display("BUILDPACK_URL=#{buildpack}")
  184. end
  185. hputs([ info["web_url"], info["git_url"] ].join(" | "))
  186. rescue Timeout::Error
  187. hputs("Timed Out! Run `heroku status` to check for known platform issues.")
  188. end
  189. unless options[:no_remote].is_a? FalseClass
  190. create_git_remote(options[:remote] || "heroku", info["git_url"])
  191. end
  192. end
  193. alias_command "create", "apps:create"
  194. # apps:rename NEWNAME
  195. #
  196. # rename the app
  197. #
  198. #Example:
  199. #
  200. # $ heroku apps:rename myapp-newname
  201. # http://myapp-newname.herokuapp.com/ | git@heroku.com:myapp-newname.git
  202. # Git remote heroku updated
  203. #
  204. def rename
  205. newname = shift_argument
  206. if newname.nil? || newname.empty?
  207. error("Usage: heroku apps:rename NEWNAME\nMust specify NEWNAME to rename.")
  208. end
  209. validate_arguments!
  210. action("Renaming #{app} to #{newname}") do
  211. api.put_app(app, "name" => newname)
  212. end
  213. app_data = api.get_app(newname).body
  214. hputs([ app_data["web_url"], app_data["git_url"] ].join(" | "))
  215. if remotes = git_remotes(Dir.pwd)
  216. remotes.each do |remote_name, remote_app|
  217. next if remote_app != app
  218. git "remote rm #{remote_name}"
  219. git "remote add #{remote_name} #{app_data["git_url"]}"
  220. hputs("Git remote #{remote_name} updated")
  221. end
  222. else
  223. hputs("Don't forget to update your Git remotes on any local checkouts.")
  224. end
  225. end
  226. alias_command "rename", "apps:rename"
  227. # apps:open
  228. #
  229. # open the app in a web browser
  230. #
  231. #Example:
  232. #
  233. # $ heroku apps:open
  234. # Opening myapp... done
  235. #
  236. def open
  237. validate_arguments!
  238. app_data = api.get_app(app).body
  239. launchy("Opening #{app}", app_data['web_url'])
  240. end
  241. alias_command "open", "apps:open"
  242. # apps:destroy
  243. #
  244. # permanently destroy an app
  245. #
  246. #Example:
  247. #
  248. # $ heroku apps:destroy -a myapp --confirm myapp
  249. # Destroying myapp (including all add-ons)... done
  250. #
  251. def destroy
  252. @app = shift_argument || options[:app] || options[:confirm]
  253. validate_arguments!
  254. unless @app
  255. error("Usage: heroku apps:destroy --app APP\nMust specify APP to destroy.")
  256. end
  257. api.get_app(@app) # fail fast if no access or doesn't exist
  258. message = "WARNING: Potentially Destructive Action\nThis command will destroy #{@app} (including all add-ons)."
  259. if confirm_command(@app, message)
  260. action("Destroying #{@app} (including all add-ons)") do
  261. api.delete_app(@app)
  262. if remotes = git_remotes(Dir.pwd)
  263. remotes.each do |remote_name, remote_app|
  264. next if @app != remote_app
  265. git "remote rm #{remote_name}"
  266. end
  267. end
  268. end
  269. end
  270. end
  271. alias_command "destroy", "apps:destroy"
  272. alias_command "apps:delete", "apps:destroy"
  273. end