Class: Heroku::Command::Apps

Inherits:
Base
  • Object
show all
Defined in:
lib/heroku/command/apps.rb

Overview

manage apps (create, destroy)

Instance Attribute Summary

Attributes inherited from Base

#args, #options

Instance Method Summary collapse

Methods inherited from Base

#api, #app, #heroku, #initialize, namespace, #org, #org_api

Methods included from Helpers

#action, #app_owner, #ask, #confirm, #confirm_command, #create_git_remote, #debug, #debugging?, #default_org_host, #deprecate, #display, #display_header, #display_object, #display_row, #display_table, #error, #error_log, #error_log_path, error_with_failure, error_with_failure=, extended, extended_into, #fail, #format_bytes, #format_date, #format_error, #format_with_bang, #get_terminal_environment, #git, #has_git?, #has_git_remote?, #has_http_git_entry_in_netrc, #home_directory, #hprint, #hputs, included, included_into, #json_decode, #json_encode, #launchy, #line_formatter, #longest, #org?, #org_host, #output_with_bang, #quantify, #redisplay, #retry_on_exception, #run_command, #running_on_a_mac?, #running_on_windows?, #set_buffer, #shell, #spinner, #status, #stderr_print, #stderr_puts, #string_distance, #styled_array, #styled_error, #styled_hash, #styled_header, #suggestion, #time_ago, #truncate, #update_git_remote, #warn_if_using_jruby, #with_tty

Constructor Details

This class inherits a constructor from Heroku::Command::Base

Instance Method Details

#createObject

apps:create [NAME]

create a new app

--addons ADDONS        # a comma-delimited list of addons to install

-b, –buildpack BUILDPACK # a buildpack url to use for this app -n, –no-remote # don't create a git remote -r, –remote REMOTE # the git remote to create, default “heroku” -s, –stack STACK # the stack on which to create the app

--region REGION        # specify region for this app to run in

-l, –locked # lock the app

--ssh-git              # Use SSH git protocol

-t, –tier TIER # HIDDEN: the tier for this app

--http-git             # HIDDEN: Use HTTP git protocol

Examples:

$ heroku apps:create Creating floating-dragon-42… done, stack is cedar floating-dragon-42.heroku.com/ | git.heroku.com/floating-dragon-42.git

# specify a stack $ heroku create -s cedar Creating stormy-garden-5052… done, stack is cedar stormy-garden-5052.herokuapp.com/ | git.heroku.com/stormy-garden-5052.git

# specify a name $ heroku apps:create example Creating example… done, stack is cedar example.heroku.com/ | git.heroku.com/example.git

# create a staging app $ heroku apps:create example-staging –remote staging

# create an app in the eu region $ heroku apps:create –region eu


227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/heroku/command/apps.rb', line 227

def create
  name    = shift_argument || options[:app] || ENV['HEROKU_APP']
  validate_arguments!
  options[:ignore_no_org] = true

  params = {
    "name" => name,
    "region" => options[:region],
    "stack" => options[:stack],
    "locked" => options[:locked]
  }

  info = if org
    org_api.post_app(params, org).body
  else
    api.post_app(params).body
  end

  begin
    action("Creating #{info['name']}", :org => !!org) do
      if info['create_status'] == 'creating'
        Timeout::timeout(options[:timeout].to_i) do
          loop do
            break if api.get_app(info['name']).body['create_status'] == 'complete'
            sleep 1
          end
        end
      end
      if options[:region]
        status("region is #{region_from_app(info)}")
      else
        stack = (info['stack'].is_a?(Hash) ? info['stack']["name"] : info['stack'])
        status("stack is #{Heroku::Command::Stack::Codex.out(stack)}")
      end
    end

    (options[:addons] || "").split(",").each do |addon|
      addon.strip!
      action("Adding #{addon} to #{info["name"]}") do
        api.post_addon(info["name"], addon)
      end
    end

    if buildpack = options[:buildpack]
      api.put_app_buildpacks_v3(info['name'], {:updates => [{:buildpack => buildpack}]})
      display "Buildpack set. Next release on #{info['name']} will use #{buildpack}."
    end

    hputs([ info["web_url"], git_url(info['name']) ].join(" | "))
  rescue Timeout::Error
    hputs("Timed Out! Run `heroku status` to check for known platform issues.")
  end

  unless options[:no_remote].is_a? FalseClass
    create_git_remote(options[:remote] || "heroku", git_url(info['name']))
  end
end

#destroyObject

apps:destroy –app APP

permanently destroy an app

Example:

$ heroku apps:destroy -a example –confirm example Destroying example (including all add-ons)… done


358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
# File 'lib/heroku/command/apps.rb', line 358

def destroy
  @app = shift_argument || options[:app] || options[:confirm]
  validate_arguments!

  unless @app
    error("Usage: heroku apps:destroy --app APP\nMust specify APP to destroy.")
  end

  api.get_app(@app) # fail fast if no access or doesn't exist

  message = "WARNING: Potentially Destructive Action\nThis command will destroy #{@app} (including all add-ons)."
  if confirm_command(@app, message)
    action("Destroying #{@app} (including all add-ons)") do
      api.delete_app(@app)
      if remotes = git_remotes(Dir.pwd)
        remotes.each do |remote_name, remote_app|
          next if @app != remote_app
          git "remote rm #{remote_name}"
        end
      end
    end
  end
end

#downgradeObject

apps:downgrade TIER –app APP

HIDDEN: downgrade an app's pricing tier


475
476
477
478
479
480
481
482
483
# File 'lib/heroku/command/apps.rb', line 475

def downgrade
  tier = shift_argument
  error("Usage: heroku apps:downgrade TIER\nMust specify TIER to downgrade.") if tier.nil? || tier.empty?
  validate_arguments!

  action("Upgrading #{app} to #{tier}") do
    api.put_app(app, "tier" => tier)
  end
end

#indexObject

apps

list your apps

-o, –org ORG # the org to list the apps for -A, –all # list all apps in the org. Not just joined apps -p, –personal # list apps in personal account when a default org is set

Example:

$ heroku apps

My Apps

example example2

Collaborated Apps

theirapp [email protected]


26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/heroku/command/apps.rb', line 26

def index
  validate_arguments!
  options[:ignore_no_org] = true

  apps = if org
    org_api.get_apps(org).body
  else
    api.get_apps.body.select { |app| options[:all] ? true : !org?(app["owner_email"]) }
  end

  unless apps.empty?
    if org
      joined, unjoined = apps.partition { |app| app['joined'] == true }

      styled_header("Apps joined in organization #{org}")
      unless joined.empty?
        styled_array(joined.map {|app| regionized_app_name(app) + (app['locked'] ? ' (locked)' : '') })
      else
        display("You haven't joined any apps.")
        display("Use --all to see unjoined apps.") unless options[:all]
        display
      end

      if options[:all]
        styled_header("Apps available to join in organization #{org}")
        unless unjoined.empty?
          styled_array(unjoined.map {|app| regionized_app_name(app) + (app['locked'] ? ' (locked)' : '') })
        else
          display("There are no apps to join.")
          display
        end
      end
    else
      my_apps, collaborated_apps = apps.partition { |app| app["owner_email"] == Heroku::Auth.user }

      unless my_apps.empty?
        styled_header("My Apps")
        styled_array(my_apps.map { |app| regionized_app_name(app) })
      end

      unless collaborated_apps.empty?
        styled_header("Collaborated Apps")
        styled_array(collaborated_apps.map { |app| [regionized_app_name(app), app_owner(app["owner_email"])] })
      end
    end
  else
    org ? display("There are no apps in organization #{org}.") : display("You have no apps.")
  end
end

#infoObject

apps:info

show detailed app information

-s, –shell # output more shell friendly key/value pairs

Examples:

$ heroku apps:info

example

Git URL: git.heroku.com/example.git Repo Size: 5M …

$ heroku apps:info –shell git_url=git.heroku.com/example.git repo_size=5000000 …


97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/heroku/command/apps.rb', line 97

def info
  validate_arguments!
  requires_preauth
  app_data = api.get_app(app).body

  unless options[:shell]
    styled_header(app_data["name"])
  end

  addons_data = api.get_addons(app).body.map {|addon| addon['name']}.sort
  collaborators_data = api.get_collaborators(app).body.map {|collaborator| collaborator["email"]}.sort
  collaborators_data.reject! {|email| email == app_data["owner_email"]}

  if org? app_data['owner_email']
    app_data['owner'] = app_owner(app_data['owner_email'])
    app_data.delete("owner_email")
  end

  if options[:shell]
    app_data['git_url'] = git_url(app_data['name'])
    if app_data['domain_name']
      app_data['domain_name'] = app_data['domain_name']['domain']
    end
    unless addons_data.empty?
      app_data['addons'] = addons_data.join(',')
    end
    unless collaborators_data.empty?
      app_data['collaborators'] = collaborators_data.join(',')
    end
    app_data.keys.sort_by { |a| a.to_s }.each do |key|
      hputs("#{key}=#{app_data[key]}")
    end
  else
    data = {}

    unless addons_data.empty?
      data["Addons"] = addons_data
    end

    if app_data["archived_at"]
      data["Archived At"] = format_date(app_data["archived_at"])
    end

    data["Collaborators"] = collaborators_data

    if app_data["create_status"] && app_data["create_status"] != "complete"
      data["Create Status"] = app_data["create_status"]
    end

    if app_data["cron_finished_at"]
      data["Cron Finished At"] = format_date(app_data["cron_finished_at"])
    end

    if app_data["cron_next_run"]
      data["Cron Next Run"] = format_date(app_data["cron_next_run"])
    end

    if app_data["database_size"]
      data["Database Size"] = format_bytes(app_data["database_size"])
    end

    data["Git URL"] = git_url(app_data['name'])

    if app_data["database_tables"]
      data["Database Size"].gsub!('(empty)', '0K') + " in #{quantify("table", app_data["database_tables"])}"
    end

    if app_data["dyno_hours"].is_a?(Hash)
      data["Dyno Hours"] = app_data["dyno_hours"].keys.map do |type|
        "%s - %0.2f dyno-hours" % [ type.to_s.capitalize, app_data["dyno_hours"][type] ]
      end
    end

    data["Owner Email"] = app_data["owner_email"] if app_data["owner_email"]
    data["Owner"] = app_data["owner"] if app_data["owner"]
    data["Region"] = app_data["region"] if app_data["region"]
    data["Repo Size"] = format_bytes(app_data["repo_size"]) if app_data["repo_size"]
    data["Slug Size"] = format_bytes(app_data["slug_size"]) if app_data["slug_size"]
    data["Cache Size"] = format_bytes(app_data["cache_size"]) if app_data["cache_size"]

    data["Stack"] = Heroku::Command::Stack::Codex.out(app_data["stack"])
    if data["Stack"] != "cedar-10"
      data.merge!("Dynos" => app_data["dynos"], "Workers" => app_data["workers"])
    end

    data["Web URL"] = app_data["web_url"]

    styled_hash(data)
  end
end

#joinObject

apps:join –app APP

add yourself to an organization app

-a, –app APP # the app


390
391
392
393
394
395
396
397
398
# File 'lib/heroku/command/apps.rb', line 390

def join
  begin
    action("Joining application #{app}") do
      org_api.join_app(app)
    end
  rescue Heroku::API::Errors::NotFound
    error("Application does not exist or does not belong to an org that you have access to.")
  end
end

#leaveObject

apps:leave –app APP

remove yourself from an organization app

-a, –app APP # the app


407
408
409
410
411
412
413
414
415
416
417
# File 'lib/heroku/command/apps.rb', line 407

def leave
  begin
    action("Leaving application #{app}") do
      if org_from_app = extract_org_from_app
        org_api.leave_app(app)
      else
        api.delete_collaborator(app, Heroku::Auth.user)
      end
    end
  end
end

#lockObject

apps:lock –app APP

lock an organization app to restrict access


425
426
427
428
429
430
431
432
433
434
# File 'lib/heroku/command/apps.rb', line 425

def lock
  begin
    action("Locking #{app}") {
      org_api.lock_app(app)
    }
    display("Organization members must be invited this app.")
  rescue Excon::Errors::NotFound
    error("#{app} was not found")
  end
end

#openObject

apps:open –app APP

open the app in a web browser

Example:

$ heroku apps:open Opening example… done


337
338
339
340
341
342
343
344
345
# File 'lib/heroku/command/apps.rb', line 337

def open
  path = shift_argument
  validate_arguments!

  app_data = api.get_app(app).body

  url = [app_data['web_url'], path].join
  launchy("Opening #{app}", url)
end

#renameObject

apps:rename NEWNAME –app APP

rename the app

--ssh-git              # Use SSH git protocol
--http-git             # HIDDEN: Use HTTP git protocol

Example:

$ heroku apps:rename example-newname example-newname.herokuapp.com/ | git.heroku.com/example-newname.git Git remote heroku updated


300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/heroku/command/apps.rb', line 300

def rename
  newname = shift_argument
  if newname.nil? || newname.empty?
    error("Usage: heroku apps:rename NEWNAME\nMust specify NEWNAME to rename.")
  end
  validate_arguments!

  action("Renaming #{app} to #{newname}") do
    api.put_app(app, "name" => newname)
  end

  app_data = api.get_app(newname).body
  hputs([ app_data["web_url"], git_url(newname) ].join(" | "))

  if remotes = git_remotes(Dir.pwd)
    remotes.each do |remote_name, remote_app|
      next if remote_app != app
      git "remote rm #{remote_name}"
      git "remote add #{remote_name} #{git_url(newname)}"
      hputs("Git remote #{remote_name} updated")
    end
  else
    hputs("Don't forget to update your Git remotes on any local checkouts.")
  end
end

#unlockObject

apps:unlock –app APP

unlock an organization app so that any org member can join it


442
443
444
445
446
447
448
449
450
451
# File 'lib/heroku/command/apps.rb', line 442

def unlock
  begin
    action("Unlocking #{app}") {
      org_api.unlock_app(app)
    }
    display("All organization members can join this app.")
  rescue Excon::Errors::NotFound
    error("#{app} was not found")
  end
end

#upgradeObject

apps:upgrade TIER –app APP

HIDDEN: upgrade an app's pricing tier


459
460
461
462
463
464
465
466
467
# File 'lib/heroku/command/apps.rb', line 459

def upgrade
  tier = shift_argument
  error("Usage: heroku apps:upgrade TIER\nMust specify TIER to upgrade.") if tier.nil? || tier.empty?
  validate_arguments!

  action("Upgrading #{app} to #{tier}") do
    api.put_app(app, "tier" => tier)
  end
end