Current section
Files
Jump to
Current section
Files
lib/mix/tasks/publish.ex
defmodule Mix.Tasks.Publish do
@shortdoc "Build a docker image, tag it with app name and version, and publish it"
use Mix.Task
def run(_args) do
# NOTE: This function really needs some refactoring once the functionality is deemed to be OK!
cfg = Mix.Project.config
version = calculate_version
app = cfg[:app]
docker_repo = cfg[:docker_repo]
docker_repo != nil or raise ":docker_repo must be set in mix.exs. This is to protect against accidentally publishing in public repos"
tag = "#{docker_repo}/#{app}:#{version}"
cwd = System.cwd
elixir_version = System.version
{_, 0} = System.cmd("rm", ["-rf", "rel/#{app}"], into: IO.stream(:stdio, :line))
# To be sure, but not doing this also seems to break the release config reading
# as the app spec can't be found.
Mix.Task.run("compile")
release_config = Mix.Releases.Config.read!("rel/config.exs")
environments_to_build = release_config.environments |> Map.keys
# Build the deployment tarballs with distillery under Docker
Enum.map(environments_to_build, fn(env) ->
build_args = ["run", "-v", "#{cwd}:#{cwd}", "-e", "MIX_ENV=#{env}", "msaraiva/elixir-dev:#{elixir_version}",
"sh", "-c", "cd #{cwd}; set -ev; mix do deps.get --only=#{env}, release"]
{_, 0} = System.cmd("docker", build_args, into: IO.stream(:stdio, :line))
end)
# Get the tarballs we just built and feed them and some assorted
# stuff to the Dockerfile template.
release_path = "rel/#{app}/releases/"
base_version = String.replace(cfg[:version], "-#{Mix.env}", "")
{:ok, entries} = File.ls(release_path)
release_tars = entries
|> Enum.filter(fn(e) -> String.starts_with?(e, base_version) end)
|> Enum.map(fn(e) -> release_path <> e <> "/#{app}.tar.gz" end)
add_dist_tars = release_tars
|> Enum.map(fn(t) -> "ADD #{t} #{app}" end)
|> Enum.join("\n")
cmd_for_mix_env = "/#{app}/releases/#{base_version}-${MIX_ENV}/#{app}.sh"
docker_file = EEx.eval_file(System.cwd <> "/Dockerfile.deploy.eex", [
add_dist_tars: add_dist_tars,
cmd_for_mix_env: cmd_for_mix_env])
File.write!("Dockerfile", docker_file)
# Build/tag and push the deployment docker file
{_, 0} = System.cmd("docker", ["build", "-t", tag, "."], into: IO.stream(:stdio, :line))
{_, 0} = System.cmd("docker", ["push", tag], into: IO.stream(:stdio, :line))
end
@spec calculate_version :: String.t
def calculate_version do
{rev, 0} = System.cmd("git", ["rev-parse", "--short", "HEAD"])
String.replace_trailing(rev, "\n", "")
end
end