lib/mix/task/monorepo.compile.ex

defmodule Mix.Tasks.Monorepo.Compile do
  @moduledoc """
  Detects the changes in a monorepo and attempts to compile them all.

      $ mix monorepo.compile [repo path]

  Only dependencies of the root project will be compile using this method,
  the root project will not be comiled as it's not a dependency.
  """

  @shortdoc "Compile all apps in a monorepo with changes."

  use Mix.Task

  @impl true
  def run([]), do: run([File.cwd!()])

  def run([path]) do
    Mix.Project.get!()

    repo = ExMonorepo.parse_repofile(List.first(ExMonorepo.repofiles(path)))
    changes = Mix.Tasks.Monorepo.Changes.scan_for_changes(repo)

    sum =
      for {_app, files} <- changes, reduce: 0 do
        acc -> acc + length(files)
      end

    deps = Mix.Dep.load_and_cache()

    IO.puts("compiling #{sum} files in #{length(changes)} applications")

    stale_deps = for %{app: app} = dep <- deps, Keyword.has_key?(changes, app), do: dep

    Mix.Tasks.Deps.Compile.compile(stale_deps)
  end
end