Mutare.Runner.AppGraph (mutare v0.1.2)

Copy Markdown View Source

Read an umbrella's declared inter-app dependency graph out of the sandbox.

Mutare.Project.app_test_scopes/3 narrows a broad (whole-umbrella) mutant run to the mutant's owning app plus its transitive dependents, which needs the forward graph %{app => [sibling apps it depends on]}. This module gets it from Mix: one mix eval in the sandbox (no compile, no deps check) merges Mix.Project.deps_tree/0 from the umbrella root with sibling applications named by each child's application/0. Every child's deps/0 and application/0 are evaluated under MIX_ENV=test exactly as the test runs see them. Consequently, a runtime: false sibling and one named only through :extra_applications or explicit :applications all count as dependencies, while an only: that excludes the test env does not. Why the graph is read this way rather than only off the build: NOTES "Umbrella narrowing must follow the declared graph".

Output contract

The evaluated snippet prints one mutare-dep <app> <dep> <dep>… line per node of the tree and a closing mutare-dep-end line. parse/2 keeps the lines naming an umbrella app, drops deps that aren't umbrella apps (Hex packages), matches names as strings against the known app list (never String.to_atom/1 on subprocess output), and is :error unless every umbrella app was reported and the end marker arrived — a missing node would silently lose that app's edges, so any incompleteness means "unknown graph" and the caller runs the whole umbrella.

Summary

Types

The declared forward graph over umbrella apps: %{app => [apps it depends on]}.

Functions

Decode mix eval output (see the module doc's output contract) into the forward graph over names, the known umbrella apps.

The declared graph of project's umbrella apps, read from the sandbox.

Types

forward()

@type forward() :: %{required(atom()) => [atom()]}

The declared forward graph over umbrella apps: %{app => [apps it depends on]}.

Functions

parse(output, names)

@spec parse(String.t(), [atom()]) :: {:ok, forward()} | :error

Decode mix eval output (see the module doc's output contract) into the forward graph over names, the known umbrella apps.

read(project, sandbox)

@spec read(Mutare.Project.t(), Path.t()) :: {:ok, forward()} | :error

The declared graph of project's umbrella apps, read from the sandbox.

A single (non-umbrella) project is {:ok, %{}} without running anything. For an umbrella, a failed mix eval or an incomplete tree (see parse/2) is :error — logged, since the fallback (every broad run covers the whole umbrella) is safe but slow.