defmodule Mix.Tasks.Arch.Collect do
use Mix.Task
@moduledoc """
Mix task to gather information about the project and store it into the database.
It currently gathers information about:
- Inventory of applications, modules, functions and macros.
- Metrics related to them such as: size and complexity.
- Information about test coverage.
- Internal dependencies between modules.
Usage:
mix arch.collect [options]
The following options are accepted:
* `--no-coverage` avoid running tests and collecting coverage information
* `--include-deps` wildcard glob style to filter dependencies
"""
@shortdoc "Runs data collection tasks on current project"
@impl Mix.Task
def run(argv) do
case validate_args(argv) do
{:ok, _opts, _args} ->
collect(
argv -- ["--no-coverage", "coverage"],
Enum.member?(argv, "--no-coverage")
)
{:error, error} ->
Mix.shell().error("Error: #{error}")
print_help()
{:error, error}
end
end
defp collect(argv, skip_coverage) do
with :ok <- Mix.Task.rerun("arch.collect.static", argv),
:ok <- Mix.Task.rerun("arch.collect.xrefs", argv),
:ok <- Mix.Task.rerun("arch.collect.apps", argv),
:ok <- Mix.Task.rerun("arch.collect.ecto", argv),
:ok <- Mix.Task.rerun("arch.collect.credo_issues", argv),
:ok <- explore_coverage(skip: skip_coverage) do
Mix.shell().info("Data collection completed successfully!")
else
{:error, e} ->
Mix.shell().error("Error: Could not run analysis: #{e}")
end
end
defp explore_coverage(skip: true), do: :ok
defp explore_coverage(skip: false) do
# Coverage needs to be called as a command in order to set the mix testing environment
Mix.Shell.cmd("mix arch.collect.coverage", [env: %{"MIX_ENV" => "test"}], &IO.puts/1)
:ok
end
defp validate_args(argv) do
{opts, args, invalid} =
OptionParser.parse(
argv,
strict: [
coverage: :boolean,
include_deps: :keep
]
)
case invalid do
[] ->
{:ok, opts, args}
_ ->
{:error, :wrong_arguments}
end
end
defp print_help() do
Mix.shell().info("""
Usage: mix arch.collect [opts]
opts: --include-deps 'deps_filter', --no-coverage
Where `deps_filter` is a glob Unix-like pattern, matches dependencies name
--include-deps can be used more than once.
- `*` matches none or many tokens
- `?` matches exactly one token
- `[abc]` matches a set of tokens
- `[a-z]` matches a range of tokens
- `[!...]` matches anything but a set of tokens
""")
end
end