Checks a cookbook, or your local recipes, for
mix composer.cookbook.lint.
Lint is a set of plain functions: it takes discovered cookbooks, prints
nothing and never raises. Every problem is a Composer.Lint.Diagnostic,
located where it is written (see Composer.Error.anchor/1 and
Composer.Recipe.Locator), in a stable order. Recipes are checked in two
passes: each entry of each recipe on its own (so every bad reference is
reported), then each recipe as a whole (for cycles and conflicting
installs); a problem is reported once, in the recipe that has it.
Errors, for a package cookbook (run/3):
- every step has a summary, an
actionand astability - every step has a test at
test/composer/<cookbook>/steps/<id>_test.exs - every step reference in
requiresresolves - the committed manifest holds the same data as a freshly built one
- the recipe group rules below
- every recipe resolves (with every include followed); this also reports a cookbook alias named like an installed cookbook
- a leftover cookbook-level
templates/directory - a file under
steps/that no step owns: it is not in a step's template directory (steps/_<id>/, besidesteps/<id>.ex) - a step's templates in an unprefixed
steps/<id>/directory - a
.exfile understeps/that is not a compiled step module - a
template/1path that does not exist
Files under steps/ that git ignores are skipped.
Errors, for local (local/2):
- a
steps/ortemplates/directory (local holds recipes only) - any other entry besides
recipes/that composer does not recognize - the recipe group rules below
- every recipe resolves
Recipe group rules:
- a subdirectory under
recipes/(groups are files) - a group file with an invalid name
- a group file that is not a keyword list of recipes
- a duplicate recipe name within a group
- a recipe missing
shortdocorsteps, with an unknown key, or with a value of the wrong type; ashortdocon more than one line - an
if:flag that the recipe does not declare in its ownflags - an invalid, reserved (
core,hex,local), duplicate or atom-valued cookbook alias, or one whose target is not a package cookbook name - a recipe named like a group of the same cookbook
Warnings:
- an empty group
- a cookbook alias that none of the recipe's own references use
- an alias that names different cookbooks in two recipes of one group
- a step and a recipe share an id, which is allowed but confusing
- a file in a step's template directory that its
template/1calls never refer to (skipped for a step whosetemplate/1path is computed at run time)
A file belongs to the step named by the first directory on its path that
starts with _: steps/ash/_postgres/x/y belongs to ash/postgres.
Step path segments never start with _, so a steps/<id>/ directory
only ever holds child steps.
Summary
Functions
Returns the recipes that include recipe ref (or any of a list of
refs), directly or through other includes, as
%{ref: ref, path: group_file}, sorted by ref. The given refs are left
out. Takes the :local option of files/3.
Lints recipe group files: for each of paths, the diagnostics located
in it.
Lints the local config directory dir, resolving references against
cookbooks (which need not include local).
Finds the cookbook a recipe group file belongs to: local when it is
under the local config directory's recipes/ (the :local option),
otherwise the cookbook in cookbooks whose recipes/ holds it.
Lints cookbook, resolving references against cookbooks. root is
the project root, where step tests are looked for.
Types
@type result() :: %{diagnostics: [Composer.Lint.Diagnostic.t()]}
Functions
@spec dependents([Composer.Cookbook.t()], String.t() | [String.t()], keyword()) :: [ %{ref: String.t(), path: Path.t()} ]
Returns the recipes that include recipe ref (or any of a list of
refs), directly or through other includes, as
%{ref: ref, path: group_file}, sorted by ref. The given refs are left
out. Takes the :local option of files/3.
@spec files([Composer.Cookbook.t()], [Path.t()], keyword()) :: %{ required(Path.t()) => [Composer.Lint.Diagnostic.t()] }
Lints recipe group files: for each of paths, the diagnostics located
in it.
Every cookbook's groups are checked, since includes cross files, but
only the recipes in paths are resolved as a whole. Each
{:use, ...} in those files whose target, or anything it includes,
has problems gets one :include_problems diagnostic, with the problems
as related locations.
Files are matched by path, following symbolic links; results are keyed,
and their files given, as in paths.
Options
:local- the local config directory; its recipes are linted as thelocalcookbook, in place of any incookbooks:root- the project root
@spec local(Path.t(), [Composer.Cookbook.t()]) :: result()
Lints the local config directory dir, resolving references against
cookbooks (which need not include local).
@spec owner([Composer.Cookbook.t()], Path.t(), keyword()) :: {:ok, Composer.Cookbook.t()} | {:error, term()}
Finds the cookbook a recipe group file belongs to: local when it is
under the local config directory's recipes/ (the :local option),
otherwise the cookbook in cookbooks whose recipes/ holds it.
@spec run(Composer.Cookbook.t(), [Composer.Cookbook.t()], Path.t()) :: result()
Lints cookbook, resolving references against cookbooks. root is
the project root, where step tests are looked for.