Methods

Class/Module Index [+]

Quicksearch

Heroku::Command::Fork

clone an existing app

Public Instance Methods

index() click to toggle source

fork [NEWNAME]

Fork an existing app -- copy config vars and Heroku Postgres data, and re-provision add-ons to a new app. New app name should not be an existing app. The new app will be created as part of the forking process.

-s, –stack STACK # specify a stack for the new app –region REGION # specify a region

# File lib/heroku/command/fork.rb, line 18
def index
  options[:ignore_no_org] = true

  from = app
  to = shift_argument || "#{from}-#{(rand*1000).to_i}"
  if from == to
    raise Heroku::Command::CommandFailed.new("Cannot fork to the same app.")
  end

  from_info = api.get_app(from).body

  to_info = action("Creating fork #{to}", :org => !!org) do
    params = {
      "name"    => to,
      "region"  => options[:region] || from_info["region"],
      "stack"   => options[:stack] || from_info["stack"],
      "tier"    => from_info["tier"] == "legacy" ? "production" : from_info["tier"]
    }

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

  action("Copying slug") do
    copy_slug(from, to)
  end

  from_config = api.get_config_vars(from).body
  from_addons = api.get_addons(from).body

  from_addons.each do |addon|
    print "Adding #{addon["name"]}... "
    begin
      to_addon = api.post_addon(to, addon["name"]).body
      puts "done"
    rescue Heroku::API::Errors::RequestFailed => ex
      puts "skipped (%s)" % json_decode(ex.response.body)["error"]
    rescue Heroku::API::Errors::NotFound
      puts "skipped (not found)"
    end
    if addon["name"] =~ /^heroku-postgresql:/
      from_var_name = "#{addon["attachment_name"]}_URL"
      from_attachment = to_addon["message"].match(/Attached as (\w+)_URL\n/)[1]
      if from_config[from_var_name] == from_config["DATABASE_URL"]
        from_config["DATABASE_URL"] = api.get_config_vars(to).body["#{from_attachment}_URL"]
      end
      from_config.delete(from_var_name)

      plan = addon["name"].split(":").last
      unless %(dev basic hobby-dev hobby-basic).include? plan
        wait_for_db to, to_addon
      end

      check_for_pgbackups! from
      check_for_pgbackups! to
      migrate_db addon, from, to_addon, to
    end
  end

  to_config = api.get_config_vars(to).body

  action("Copying config vars") do
    diff = from_config.inject({}) do |ax, (key, val)|
      ax[key] = val unless to_config[key]
      ax
    end
    api.put_config_vars to, diff
  end

  puts "Fork complete, view it at #{to_info['web_url']}"
rescue Exception => e
  raise if e.is_a?(Heroku::Command::CommandFailed)

  puts "Failed to fork app #{from} to #{to}."
  message = "WARNING: Potentially Destructive Action\nThis command will destroy #{to} (including all add-ons)."

  if confirm_command(to, message)
    action("Deleting #{to}") do
      begin
        api.delete_app(to)
      rescue Heroku::API::Errors::NotFound
      end
    end
  end
  puts "Original exception below:"
  raise e
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.