Skip to content

Commit 6f7a68c

Browse files
committed
Support mix xref graph at umbrella roots, closes #12629
1 parent 0936fb4 commit 6f7a68c

File tree

2 files changed

+68
-14
lines changed

2 files changed

+68
-14
lines changed

lib/mix/lib/mix/tasks/xref.ex

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@ defmodule Mix.Tasks.Xref do
3838
$ mix xref trace lib/my_app/router.ex --label compile
3939
4040
If you have an umbrella application, we also recommend using the
41-
`--include-siblings` flag to see the dependencies on other
42-
umbrella applications.
41+
`--include-siblings` flag to see the dependencies from sibling
42+
applications. The `trace` command is not currently supported at the
43+
umbrella root.
4344
4445
### Example
4546
@@ -222,6 +223,12 @@ defmodule Mix.Tasks.Xref do
222223
lib/a.ex
223224
└── lib/b.ex (compile)
224225
226+
If you have an umbrella application, we also recommend using the
227+
`--include-siblings` flag to see the dependencies from sibling
228+
applications. When invoked at the umbrella root, the `graph`
229+
command will list all files from all umbrella children, without
230+
any namespacing.
231+
225232
### Dependency types
226233
227234
Elixir tracks three types of dependencies between modules: compile,
@@ -289,22 +296,18 @@ defmodule Mix.Tasks.Xref do
289296

290297
@impl true
291298
def run(args) do
292-
if Mix.Project.umbrella?() do
293-
Mix.raise(
294-
"mix xref is not supported in the umbrella root. Please run it inside the umbrella applications instead"
295-
)
296-
end
297-
298299
Mix.Task.run("compile", args)
299300
Mix.Task.reenable("xref")
300301

301302
{opts, args} = OptionParser.parse!(args, strict: @switches)
302303

303304
case args do
304305
["callers", module] ->
306+
no_umbrella!("callers")
305307
handle_callers(module, opts)
306308

307309
["trace", file] ->
310+
no_umbrella!("trace")
308311
handle_trace(file, opts)
309312

310313
["graph"] ->
@@ -327,6 +330,14 @@ defmodule Mix.Tasks.Xref do
327330
end
328331
end
329332

333+
defp no_umbrella!(task) do
334+
if Mix.Project.umbrella?() do
335+
Mix.raise(
336+
"mix xref #{task} is not supported in the umbrella root. Please run it inside the umbrella applications instead"
337+
)
338+
end
339+
end
340+
330341
@doc """
331342
Returns a list of information of all the runtime function calls in the project.
332343
@@ -1058,12 +1069,18 @@ defmodule Mix.Tasks.Xref do
10581069

10591070
defp manifests(opts) do
10601071
siblings =
1061-
if opts[:include_siblings] do
1062-
for %{scm: Mix.SCM.Path, opts: opts} <- Mix.Dep.cached(),
1063-
opts[:in_umbrella],
1064-
do: Path.join([opts[:build], ".mix", @manifest])
1065-
else
1066-
[]
1072+
cond do
1073+
Mix.Project.umbrella?() ->
1074+
for %{opts: opts} <- Mix.Dep.Umbrella.cached(),
1075+
do: Path.join([opts[:build], ".mix", @manifest])
1076+
1077+
opts[:include_siblings] ->
1078+
for %{scm: Mix.SCM.Path, opts: opts} <- Mix.Dep.cached(),
1079+
opts[:in_umbrella],
1080+
do: Path.join([opts[:build], ".mix", @manifest])
1081+
1082+
true ->
1083+
[]
10671084
end
10681085

10691086
[Path.join(Mix.Project.manifest_path(), @manifest) | siblings]

lib/mix/test/mix/tasks/xref_test.exs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,43 @@ defmodule Mix.Tasks.XrefTest do
915915
end)
916916
end
917917

918+
test "generates reports from the umbrella root" do
919+
Mix.Project.pop()
920+
921+
in_fixture("umbrella_dep/deps/umbrella", fn ->
922+
Mix.Project.in_project(:umbrella, ".", fn _ ->
923+
File.write!("apps/bar/lib/bar.ex", """
924+
defmodule Bar do
925+
def bar do
926+
Foo.foo()
927+
end
928+
end
929+
""")
930+
931+
Mix.Task.run("compile")
932+
Mix.shell().flush()
933+
934+
Mix.Tasks.Xref.run(["graph", "--format", "stats", "--include-siblings"])
935+
936+
assert receive_until_no_messages([]) == """
937+
Tracked files: 2 (nodes)
938+
Compile dependencies: 0 (edges)
939+
Exports dependencies: 0 (edges)
940+
Runtime dependencies: 1 (edges)
941+
Cycles: 0
942+
943+
Top 2 files with most outgoing dependencies:
944+
* lib/bar.ex (1)
945+
* lib/foo.ex (0)
946+
947+
Top 2 files with most incoming dependencies:
948+
* lib/foo.ex (1)
949+
* lib/bar.ex (0)
950+
"""
951+
end)
952+
end)
953+
end
954+
918955
test "generates reports considering siblings inside umbrellas" do
919956
Mix.Project.pop()
920957

0 commit comments

Comments
 (0)