class Nucleus::Adapters::V1::Heroku

The {Heroku} adapter is designed to support the Heroku platform API.

The Nucleus API is fully supported, there are no known issues. @see devcenter.heroku.com/articles/platform-api-reference Heroku Platform API

Public Class Methods

new(endpoint_url, endpoint_app_domain = nil, check_certificates = true) click to toggle source
Calls superclass method
# File lib/nucleus/adapters/v1/heroku/heroku.rb, line 24
def initialize(endpoint_url, endpoint_app_domain = nil, check_certificates = true)
  super(endpoint_url, endpoint_app_domain, check_certificates)
end

Public Instance Methods

handle_422(error_response) click to toggle source
# File lib/nucleus/adapters/v1/heroku/heroku.rb, line 39
def handle_422(error_response)
  return unless error_response.status == 422
  if error_response.body[:id] == 'invalid_params'
    raise Errors::SemanticAdapterRequestError, error_response.body[:message]
  elsif error_response.body[:id] == 'verification_required'
    fail_with(:need_verification, [error_response.body[:message]])
  end
end
handle_error(error_response) click to toggle source
# File lib/nucleus/adapters/v1/heroku/heroku.rb, line 28
def handle_error(error_response)
  handle_422(error_response)
  if error_response.status == 404 && error_response.body[:id] == 'not_found'
    raise Errors::AdapterResourceNotFoundError, error_response.body[:message]
  elsif error_response.status == 503
    raise Errors::PlatformUnavailableError, 'The Heroku API is currently not responding'
  end
  # error still unhandled, will result in a 500, server error
  log.warn "Heroku error still unhandled: #{error_response}"
end

Private Instance Methods

application_instances(application_id) click to toggle source
# File lib/nucleus/adapters/v1/heroku/heroku.rb, line 97
def application_instances(application_id)
  formations = get("/apps/#{application_id}/formation").body
  web_formation = formations.find { |formation| formation[:type] == 'web' }
  return web_formation[:quantity] unless web_formation.nil?
  # if no web formation was detected, there is no instance available
  0
end
dynos(application_id) click to toggle source
# File lib/nucleus/adapters/v1/heroku/heroku.rb, line 105
def dynos(application_id)
  get("/apps/#{application_id}/dynos").body
end
headers() click to toggle source
Calls superclass method
# File lib/nucleus/adapters/v1/heroku/heroku.rb, line 82
def headers
  super.merge(
    'Accept' => 'application/vnd.heroku+json; version=3',
    'Content-Type' => 'application/json'
  )
end
heroku_api() click to toggle source
# File lib/nucleus/adapters/v1/heroku/heroku.rb, line 78
def heroku_api
  ::Heroku::API.new(headers: headers)
end
install_runtimes(application_id, runtimes) click to toggle source
# File lib/nucleus/adapters/v1/heroku/heroku.rb, line 50
def install_runtimes(application_id, runtimes)
  runtime_instructions = runtimes.collect { |buildpack_url| { buildpack: buildpack_url } }
  log.debug "Install runtimes: #{runtime_instructions}"
  buildpack_instructions = { updates: runtime_instructions }
  put("/apps/#{application_id}/buildpack-installations", body: buildpack_instructions)
end
installed_buildpacks(application_id) click to toggle source
# File lib/nucleus/adapters/v1/heroku/heroku.rb, line 89
def installed_buildpacks(application_id)
  buildpacks = get("/apps/#{application_id}/buildpack-installations").body
  return [] if buildpacks.empty?
  buildpacks.collect do |buildpack|
    buildpack[:buildpack][:url]
  end
end
latest_release(application_id, retrieved_dynos = nil) click to toggle source
# File lib/nucleus/adapters/v1/heroku/heroku.rb, line 116
def latest_release(application_id, retrieved_dynos = nil)
  dynos = web_dynos(application_id, retrieved_dynos)
  if dynos.nil? || dynos.empty?
    log.debug 'no dynos for build detection, fallback to latest release version'
    # this approach might be wrong if the app is rolled-back to a previous release
    # However, if no dyno is active, this is the only option to identify the current release
    latest_version = 0
    latest_version_id = nil
    get("/apps/#{application_id}/releases").body.each do |release|
      if release[:version] > latest_version
        latest_version = release[:version]
        latest_version_id = release[:id]
      end
    end
  else
    latest_version = 0
    latest_version_id = nil
    dynos.each do |dyno|
      if dyno[:release][:version] > latest_version
        latest_version = dyno[:release][:version]
        latest_version_id = dyno[:release][:id]
      end
    end
  end

  latest_version_id
end
runtimes_to_install(application) click to toggle source
# File lib/nucleus/adapters/v1/heroku/heroku.rb, line 57
def runtimes_to_install(application)
  return [] unless application[:runtimes]
  runtimes_to_install = []
  application[:runtimes].each do |runtime_identifier|
    # we do not need to install native buildpacks
    # TODO: 2 options for heroku runtime handling
    # a) skip native, fails when native required and not in list
    # b) (current) use native, fails when others (additional) are in the list
    # next if native_runtime?(runtime_identifier)
    runtime_is_url = runtime_identifier =~ /\A#{URI.regexp}\z/
    runtime_url = find_runtime(runtime_identifier)
    runtime_is_valid = runtime_url || runtime_is_url
    fail_with(:invalid_runtime, [runtime_identifier]) unless runtime_is_valid
    # if runtime identifier is valid, we need to install the runtime
    runtimes_to_install.push(runtime_is_url ? runtime_identifier : runtime_url)
  end
  # heroku does not know the 'runtimes' property and would crash if present
  application.delete :runtimes
  runtimes_to_install
end
web_dynos(application_id, retrieved_dynos = nil) click to toggle source
# File lib/nucleus/adapters/v1/heroku/heroku.rb, line 109
def web_dynos(application_id, retrieved_dynos = nil)
  all_dynos = retrieved_dynos ? retrieved_dynos : dynos(application_id)
  all_dynos.find_all do |dyno|
    dyno[:type] == 'web'
  end.compact
end