MixAffected.Classifier (MixAffected v0.1.0)

Copy Markdown View Source

Sorts a change set into what it means for test selection. Each changed file gets the first rule that applies:

  1. outside the project root - full run, unmapped_file:<absolute path>
  2. matches an ignore glob - dropped
  3. matches a global_invalidation glob - full run, global_invalidation:<glob>:<file>
  4. a test file (test paths + test pattern) - selected directly; a deleted one seeds the tests that used modules it defined
  5. an existing file - a source candidate; affected/2 asks the graph to vouch for it (Graph.dependents/2)
  6. anything else (a deleted non-test file) - full run, unmapped_file:<file>

A global invalidation outranks an unmapped file anywhere in the change set, so the reason names the strongest cause. classify/3 never needs the graph, so an all-docs or tests-only change costs no xref run.

Summary

Functions

The affected files of a classification without a full run: the reverse transitive closure of its sources in graph plus its changed tests, sorted. A source the graph does not compile (an external resource such as a template, or any non-source file) means {:full_run, "unmapped_file:<file>"}. graph may be nil when there are no sources.

Classifies changed (paths relative to the absolute project root, or absolute, in any order, possibly with blanks or duplicates). Every path is canonicalized against root first (lib/./a.ex is lib/a.ex); one outside root is unmapped_file:<absolute path>. exists? answers whether a root-relative path exists in the working tree.

Types

path()

@type path() :: MixAffected.Graph.path()

reason()

@type reason() :: String.t()

t()

@type t() :: %MixAffected.Classifier{
  changed: [path()],
  deleted_tests: [path()],
  full_run: reason() | nil,
  ignored: [path()],
  sources: [path()],
  tests: [path()]
}

Functions

affected(classifier, graph)

@spec affected(t(), MixAffected.Graph.t() | nil) ::
  {:ok, [path()]} | {:full_run, reason()}

The affected files of a classification without a full run: the reverse transitive closure of its sources in graph plus its changed tests, sorted. A source the graph does not compile (an external resource such as a template, or any non-source file) means {:full_run, "unmapped_file:<file>"}. graph may be nil when there are no sources.

classify(changed, config, root, exists?)

@spec classify([String.t()], MixAffected.Config.t(), Path.t(), (path() -> boolean())) ::
  t()

Classifies changed (paths relative to the absolute project root, or absolute, in any order, possibly with blanks or duplicates). Every path is canonicalized against root first (lib/./a.ex is lib/a.ex); one outside root is unmapped_file:<absolute path>. exists? answers whether a root-relative path exists in the working tree.