Packages

Publish Elixir releases created with exrm release manager to Heroku.

Current section

Files

Jump to
exrm_heroku lib exrm plugins heroku.ex
Raw

lib/exrm/plugins/heroku.ex

defmodule ReleaseManager.Plugin.Heroku do
@name "protocol.consolidation"
@shortdoc "Performs protocol consolidation for your release."
use ReleaseManager.Plugin
alias ReleaseManager.Config
alias ReleaseManager.Utils
import ReleaseManager.Utils
@_NAME "{{{PROJECT_NAME}}}"
@_PROCESS_TYPE "{{{PROCESS_TYPE}}}"
def before_release(%{heroku: true} = config) do
config
|> do_before_release_config
|> do_copy_procfile
end
def before_release(_), do: nil
def after_release(%{heroku: true} = config) do
config = config |> do_after_release_config
slug_path = config |> do_unpack_release
config |> do_release_slug(slug_path)
end
def after_release(_), do: nil
def after_cleanup(_), do: nil
def do_before_release_config(config) do
process_type = config |> get_config_item(:process_type, "web")
config |> Map.merge(%{process_type: process_type})
end
def do_after_release_config(config) do
heroku_app = config |> get_config_item(:app, config.name)
slug_command = config |> get_config_item(:slug_command, "slug")
config |> Map.merge(%{heroku_app: heroku_app, slug_command: slug_command})
end
defp do_copy_procfile(config) do
procfile_path = Path.join([File.cwd!, "Procfile"])
unless File.exists?(procfile_path) do
procfile_path = do_generate_procfile(config)
end
# Check if relx.config exist
relx_conf_path = rel_file_dest_path("relx.config")
unless File.exists?(relx_conf_path) do
File.touch(relx_conf_path)
end
# Load relx.config
relx_config = relx_conf_path |> Utils.read_terms
# Add overlay to relx.config which copies Procfile to release
overlays = [overlay: [
{:copy, '#{procfile_path}', 'Procfile'}
]]
updated = Utils.merge(relx_config, overlays)
# Persist relx.config
Utils.write_terms(relx_conf_path, updated)
config
end
defp do_generate_procfile(config) do
debug "Generating Procfile..."
procfile_template = template_path("Procfile")
procfile_path = rel_file_dest_path("Procfile")
contents = File.read!(procfile_template)
|> String.replace(@_NAME, config.name)
|> String.replace(@_PROCESS_TYPE, config.process_type || "web")
File.mkdir_p(rel_file_dest_path)
File.write!(procfile_path, contents)
procfile_path
end
defp do_unpack_release(%{name: name, version: version} = config) do
debug "Unpacking release..."
tmp_dir = create_tmp_dir(config)
tarball = rel_dest_path [name, "#{name}-#{version}.tar.gz"]
:erl_tar.extract(tarball, [{:cwd, tmp_dir}, :compressed])
tmp_dir
end
defp do_release_slug(config, slug_dir) do
heroku_app = config.heroku_app
args = ["-dir", slug_dir, "-app", heroku_app, "-release"]
execute_slug(config.slug_command, args)
end
defp create_tmp_dir(config) do
tmp_dir = System.tmp_dir
release_tmp_dir = Path.join([tmp_dir, config.name])
case File.mkdir(release_tmp_dir) do
:ok ->
release_tmp_dir
{:error, :eexist} ->
File.rm_rf!(release_tmp_dir)
create_tmp_dir(config)
end
end
defp execute_slug(command, args) do
IO.puts "Executing: #{command} #{Enum.join(args, " ")}"
case System.cmd(command, args) do
{:error, :enoent} ->
IO.puts """
slug command wasn't found, please install it and try again.
Check https://github.com/naaman/slug for more info.
"""
{:error, error} ->
IO.puts "Error #{inspect(error)} executing the slug command."
{output, _} ->
IO.puts "Command executed, output: \n#{output}"
output
end
end
defp template_path(filename) do
priv_path = :code.priv_dir('exrm_heroku')
Path.join([priv_path, "rel", "files", filename])
end
defp get_config_item(config, item, default) do
project_config = Mix.Project.config |> Keyword.get(:heroku)
config |> Map.get(item, Keyword.get(project_config, item, default))
end
end