lib/sr_service.ex

defmodule SrService do
  @moduledoc """
  Documentation for `SrService`.
  """

  def app_module_name(app_name) do
    app_name |> String.split("_") |> Enum.map(fn s -> String.capitalize(s) end) |> Enum.join()
  end

  def write_log_file(app_dir, app_name) do
    contents =
      """
      defmodule #{app_module_name(app_name)}.Log do
        @moduledoc false

        defmacro __using__(params) do
          name = Keyword.fetch!(params, :name)

          quote do
            require Logger

            def error(msg, meta \\\\ []), do: Logger.error(name() <> " :: " <> msg, meta)
            def warn(msg, meta \\\\ []), do: Logger.warn(name() <> " :: " <> msg, meta)
            def info(msg, meta \\\\ []), do: Logger.info(name() <> " :: " <> msg, meta)
            def debug(msg, meta \\\\ []), do: Logger.debug(name() <> " :: " <> msg, meta)

            defp name, do: unquote(name)
          end
        end
      end

      """
      |> Code.format_string!()

    File.write!("#{app_dir}/lib/#{app_name}/log.ex", contents)
  end

  def write_repo_file(app_dir, app_name) do
    contents =
      """
      defmodule #{app_module_name(app_name)}.Repo do
        use Ecto.Repo,
          otp_app: :#{app_name},
          adapter: Ecto.Adapters.Postgres
      end
      """
      |> Code.format_string!()

    File.write!("#{app_dir}/lib/#{app_name}/repo.ex", contents)
  end

  def update_mix_file(app_dir) do
    app_dir
    |> get_mix_file_contents()
    |> update_project()
    |> update_deps_and_aliases()
    |> write_mix_file(app_dir)
  end

  def update_application_file(app_dir, app_name) do
    filename = app_dir <> "/lib/#{app_name}/application.ex"
    match_start = "def start(_type, _args) do"

    replace_start = """
    def start(_type, _args) do
      {:ok, _} = Application.ensure_all_started(:appsignal)
      IO.puts("Application started.")

    """

    match_children = "children = ["

    replace_children = """
    children = [
      #{SrService.app_module_name(app_name)}.Repo,
    """

    contents =
      File.read!(filename)
      |> String.replace(match_start, replace_start)
      |> String.replace(match_children, replace_children)

    File.write!(filename, contents)
  end

  defp get_mix_file_contents(app_dir) do
    File.read!(app_dir <> "/mix.exs")
  end

  defp update_project(contents) do
    match = "deps: deps()"

    replace = """
    deps: deps(),
    aliases: aliases(),
    test_coverage: [tool: ExCoveralls],
    dialyzer: [
      ignore_warnings: "dialyzer.ignore-warnings",
      plt_add_deps: [:app_tree],
      plt_add_apps: [:mix]
    ],
    preferred_cli_env: [
      "coveralls.detail": :test,
      "coveralls.html": :test,
      "coveralls.post": :test,
      "ecto.drop": :test,
      audit: :test,
      coveralls: :test,
      docs: :test,
      run_ci: :test,
      test: :test
    ],
    name: "<MODULE_NAME>",
    docs: [
      # The main page in the docs
      main: "<MODULE_NAME>",
      extras: ["README.md"]
    ]
    """

    contents
    |> String.replace(match, replace)
  end

  defp update_deps_and_aliases(contents) do
    match =
      "defp deps do\n    [\n      # {:dep_from_hexpm, \"~> 0.3.0\"},\n      # {:dep_from_git, git: \"https://github.com/elixir-lang/my_dep.git\", tag: \"0.1.0\"}\n    ]\n  end\n"

    replace = """
    defp deps do
      [
        {:appsignal, "~> 2.0"},
        {:credo, "~> 1.0", [only: [:dev, :test], runtime: false]},
        {:dialyxir, "~> 1.0", only: [:dev], runtime: false},
        {:ecto, "~> 3.9"},
        {:ecto_sql, "~> 3.9"},
        {:ex_doc, "~> 0.27", only: :test, runtime: false},
        {:excoveralls, "~> 0.10", only: :test},
        {:jason, "~> 1.1"},
        {:mix_audit, "~> 2.1", only: [:test, :dev]},
        {:postgrex, ">= 0.0.0"}
      ]
    end

    defp aliases do
      [
        audit: [
          "hex.audit",
          "deps.unlock --check-unused",
          "deps.audit",
          "hex.outdated --within-requirements",
          "format --dry-run --check-formatted",
          "compile --all-warnings --warning-as-errors",
          "credo list --strict",
          "dialyzer"
        ],
        run_ci: [
          "format --dry-run --check-formatted",
          "compile --all-warnings --warning-as-errors",
          "credo list --strict",
          "test --cover"
        ]
      ]
    end
    """

    contents
    |> String.replace(match, replace)
    |> Code.format_string!()
  end

  defp write_mix_file(contents, app_dir) do
    File.write!(app_dir <> "/mix.exs", contents)
  end
end