defmodule Mix.Tasks.SrService.New do
@moduledoc """
Used to generate a new service for use in the SalesRabbit ecosystem.
"""
use Mix.Task
@app_name_replace_text "<APP_NAME>"
@module_name_replace_text "<MODULE_NAME>"
@impl true
def run(args) do
case OptionParser.parse(args, switches: []) do
{opts, [name], _} ->
name = String.downcase(name)
Mix.shell().info("Generating '#{name}' with options #{inspect(opts)}")
generate(name, opts)
_ ->
Mix.raise(
"You need to pass in a name and valid options! (example: mix sr_service new_app --db)"
)
end
end
defp generate(app_name, []) do
{:ok, app_dir} = create_base_app(app_name)
:ok = copy_base_files(app_dir, app_name)
SrService.write_log_file(app_dir, app_name)
SrService.update_application_file(app_dir, app_name)
SrService.update_mix_file(app_dir)
SrService.write_repo_file(app_dir, app_name)
replace_app_name(app_dir, app_name)
format_files(app_dir)
install_deps(app_dir)
print_mix_info()
end
defp create_base_app(name) do
pwd = File.cwd!()
app_dir = "#{pwd}/#{name}"
:ok = Mix.Task.run("new", ["#{app_dir}", "--sup"])
{:ok, app_dir}
end
defp copy_base_files(app_dir, app_name) do
File.cp!("#{template_dir()}/template.README.md", "#{app_dir}/README.md",
on_conflict: fn _, _ -> true end
)
File.cp!("#{template_dir()}/template.service.ex", "#{app_dir}/lib/#{app_name}.ex",
on_conflict: fn _, _ -> true end
)
File.cp!(
"#{template_dir()}/template.service_test.exs",
"#{app_dir}/test/#{app_name}_test.exs",
on_conflict: fn _, _ -> true end
)
File.cp!("#{template_dir()}/template.tool-versions", "#{app_dir}/.tool-versions",
on_conflict: fn _, _ -> true end
)
File.cp!("#{template_dir()}/template.gitignore", "#{app_dir}/.gitignore",
on_conflict: fn _, _ -> true end
)
File.cp!("#{template_dir()}/template.coveralls.json", "#{app_dir}/coveralls.json",
on_conflict: fn _, _ -> true end
)
File.cp!("#{template_dir()}/template.Dockerfile", "#{app_dir}/Dockerfile",
on_conflict: fn _, _ -> true end
)
File.cp!("#{template_dir()}/template.credo.exs", "#{app_dir}/.credo.exs",
on_conflict: fn _, _ -> true end
)
File.cp!("#{template_dir()}/template.gitlab-ci.yml", "#{app_dir}/.gitlab-ci.yml",
on_conflict: fn _, _ -> true end
)
File.mkdir_p!("#{app_dir}/lib/mix/tasks/")
File.mkdir_p!("#{app_dir}/sdk")
File.touch("#{app_dir}/sdk/.gitkeep")
File.cp!("#{template_dir()}/template.build_sdk.ex", "#{app_dir}/lib/mix/tasks/build_sdk.ex",
on_conflict: fn _, _ -> true end
)
# CONFIG FILES
File.mkdir!("#{app_dir}/config")
File.cp!("#{template_dir()}/template.config.exs", "#{app_dir}/config/config.exs",
on_conflict: fn _, _ -> true end
)
File.cp!("#{template_dir()}/template.runtime.exs", "#{app_dir}/config/runtime.exs",
on_conflict: fn _, _ -> true end
)
File.cp!("#{template_dir()}/template.env", "#{app_dir}/config/.env",
on_conflict: fn _, _ -> true end
)
# RELEASE FILES
File.mkdir!("#{app_dir}/rel")
File.cp!("#{template_dir()}/template.env.sh.eex", "#{app_dir}/rel/env.sh.eex",
on_conflict: fn _, _ -> true end
)
:ok
end
defp template_dir do
"#{:code.priv_dir(:sr_service)}"
end
defp replace_app_name(app_dir, app_name) do
files =
~w(#{app_dir}/lib/#{app_name}.ex #{app_dir}/test/#{app_name}_test.exs #{app_dir}/.gitlab-ci.yml #{app_dir}/Dockerfile #{app_dir}/README.md #{app_dir}/mix.exs #{app_dir}/config/runtime.exs #{app_dir}/coveralls.json)
Enum.each(files, fn filename ->
contents =
File.read!(filename)
|> String.replace(@app_name_replace_text, app_name)
|> String.replace(@module_name_replace_text, SrService.app_module_name(app_name))
File.write!(filename, contents)
end)
end
defp format_files(app_dir) do
Mix.Task.run("format", ["#{app_dir}/**/*.{ex,exs}"])
end
defp install_deps(app_dir) do
File.cd!(app_dir)
System.cmd("mix", ["deps.get"], env: [{"DATABASE_URL", "nothing"}])
end
defp print_mix_info do
Mix.shell().info("""
To Start your new app run:
$ iex -S mix
Some Followup items may include:
- Setting up your project in Gitlab
- Working with the infrastructure team to get your new app deployed
""")
end
end