MixAffected.Config (MixAffected v0.1.0)

Copy Markdown View Source

The affected: settings of the consuming project, plus the test layout (:test_paths, :test_pattern) Mix itself uses to find test files.

def project do
  [
    app: :my_app,
    affected: [
      # replaces the defaults when given
      global_invalidation: ["config/**", "mix.exs", "mix.lock", "test/test_helper.exs",
                            "priv/repo/migrations/**"],
      # appended to global_invalidation
      extra_global_invalidation: [],
      # changed files that affect no test; default ["*.md", "docs/**/*.md"]
      # (other .md may be runtime data: it falls through as unmapped)
      ignore: ["*.md", "docs/**/*.md"],
      # source glob => test globs to run when a matching file is affected
      mappings: [{"lib/my_app/workers/**", ["test/my_app/workers/**"]}]
    ]
  ]
end

Every glob is matched by MixAffected.Glob against project-root-relative paths, and checked up front by validate_glob/2: a malformed glob, or a pattern naming a directory (one ending in /, or a glob-free pattern that is a directory under the project root; either would match no file), is an error rather than a rule that silently never fires.

Summary

Functions

The default global_invalidation globs.

Reads the config from a project keyword list (Mix.Project.config/0) of the project at root. Unknown affected: keys, malformed values and globs validate_glob/2 rejects are errors, never ignored.

Whether path is a test file: under a test path and matching the test pattern.

Checks a glob from the config or a test's affected_by against the project at root: it must compile (MixAffected.Glob.compile/1), must be in normal form and must not name a directory; any of those would leave a rule that matches no changed file. Changed paths are normalized, so a glob with a ., .. or empty (//) segment never matches; the error gives the normal form, and a glob reaching outside the root is an error of its own. A glob ending in / (or /., /..) names a directory whatever it holds; a pattern with no glob metacharacter names one when it is a directory under root. A leading ./ is allowed, as MixAffected.Glob ignores it.

Types

mapping()

@type mapping() :: {String.t(), [String.t()]}

t()

@type t() :: %MixAffected.Config{
  global_invalidation: [String.t()],
  ignore: [String.t()],
  mappings: [mapping()],
  test_paths: [String.t()],
  test_pattern: String.t()
}

Functions

default_global_invalidation()

@spec default_global_invalidation() :: [String.t()]

The default global_invalidation globs.

from_project(project, root)

@spec from_project(keyword(), Path.t()) :: {:ok, t()} | {:error, String.t()}

Reads the config from a project keyword list (Mix.Project.config/0) of the project at root. Unknown affected: keys, malformed values and globs validate_glob/2 rejects are errors, never ignored.

test_file?(config, path)

@spec test_file?(t(), String.t()) :: boolean()

Whether path is a test file: under a test path and matching the test pattern.

validate_glob(glob, root)

@spec validate_glob(String.t(), Path.t()) :: :ok | {:error, String.t()}

Checks a glob from the config or a test's affected_by against the project at root: it must compile (MixAffected.Glob.compile/1), must be in normal form and must not name a directory; any of those would leave a rule that matches no changed file. Changed paths are normalized, so a glob with a ., .. or empty (//) segment never matches; the error gives the normal form, and a glob reaching outside the root is an error of its own. A glob ending in / (or /., /..) names a directory whatever it holds; a pattern with no glob metacharacter names one when it is a directory under root. A leading ./ is allowed, as MixAffected.Glob ignores it.