# `mix quality`
[🔗](https://github.com/riddler/ex_quality/blob/v0.15.0/lib/mix/tasks/quality.ex#L1)

Runs code quality checks in parallel with actionable feedback.

Automatically fixes formatting issues, then runs all analysis stages
in parallel with streaming output.

## Execution Phases

1. **Auto-fix** - Runs `mix format` to fix formatting
2. **Compile** - Compiles dev + test environments in parallel
3. **Analysis** - Runs enabled checks in parallel (credo, dialyzer, doctor, tests)

`--until-first-failure` replaces all three with one sequential pass, cheapest
stage first, stopping at the first failure. See "An inner loop" below.

## Usage

    mix quality

## Options

- `--quick` - Quick mode for development: skips dialyzer and coverage enforcement
- `--skip-dialyzer` - Skip Dialyzer type checking
- `--skip-credo` - Skip Credo static analysis
- `--skip-doctor` - Skip Doctor documentation checks
- `--skip-docs` - Skip the Docs (ExDoc warnings) stage
- `--skip-doc-links` - Skip the Doc links (relative link rules) stage
- `--skip-gettext` - Skip Gettext translation checks
- `--skip-sobelow` - Skip Sobelow security analysis
- `--skip-dependencies` - Skip dependency checks (unused deps and security audit)
- `--skip KEY` - Skip any stage by key, built-in or custom; repeatable
- `--profile NAME` - Run a named bundle of options from `.quality.exs`
- `--test-scope all|changed|GLOB` - How much of the suite to run
- `--until-first-failure` - Stop at the first failing stage, cheapest first
- `--verbose` - Show full output even on success
- `--format json` - Write a JSON report to stdout, human output to stderr
- `--report PATH` - Write a JSON report to PATH, human output to stdout
  (`--report -` writes it to stdout, as `--format json` does)

## Passing Test Options

You can pass extra arguments to `mix test` or `mix coveralls` using `--`:

    mix quality -- --only integration
    mix quality --quick -- --include slow --seed 0

Arguments after `--` are passed directly to the test command.

Alternatively, configure test args in `.quality.exs`:

    test: [
      args: ["--only", "integration"]
    ]

CLI args (after `--`) override config file args (no merge).

## Auto-Detection

Stages are automatically enabled based on installed dependencies:

- `:credo` → enables Credo stage
- `:dialyxir` → enables Dialyzer stage
- `:doctor` → enables Doctor stage
- `:gettext` → enables Gettext translation checks
- `:sobelow` → enables Sobelow security analysis
- `:mix_audit` → enables security audit in Dependencies stage
- `:excoveralls` → uses `mix coveralls` instead of `mix test`

The Docs stage (ExDoc warnings) is the exception: it is opt-in, via
`docs: [enabled: :auto]` in `.quality.exs`, because nearly every published
package has `:ex_doc` and enabling on detection would move existing gates.
See `ExQuality.Stages.Docs`. The Doc links stage is opt-in the same way,
via `doc_links: [enabled: :auto]`; see `ExQuality.Stages.DocLinks`.

## Quick Mode

Use `--quick` during active development when you haven't finished all
implementation tasks (like writing tests). Quick mode:

- Skips Dialyzer (slow)
- Runs `mix test` instead of `mix coveralls` (tests must pass, but
  coverage threshold is not enforced)

This lets you iterate quickly while still catching obvious issues.

## An inner loop, as opposed to a gate

A full run is a good thing to require before a push and a bad thing to run
between edits, and every switch above narrows *which checks run* when the
expensive question is *how much code they run over*. On a large suite the tests
are most of the wall clock, and `--quick` does not touch them: it removes
dialyzer and the coverage threshold and still runs every test.

    mix quality --test-scope changed        # only the tests covering your edits
    mix quality --profile loop             # a named bundle, see below
    mix quality --until-first-failure      # stop at the first thing to fix

`--test-scope changed` maps the files you have changed, committed or not, to
the test files covering them. A scope that resolves to no test files runs the
whole suite instead, because a green run of nothing is the one result that
would be worse than a slow one. Coverage is reported as skipped on a scoped
run, never as a number over a subset. See `ExQuality.Scope`.

A profile gives that fast path a name, so a project's docs and its agent
instructions can point at one word instead of a switch list:

    profiles: [
      loop: [stages: [:format, :compile, :credo], test: [scope: :changed]],
      gate: []
    ]

A run with no `--profile` behaves exactly as it did before profiles existed.
See `ExQuality.Config` for how a profile merges, and what an unknown name does.

## Configuration

Create `.quality.exs` in your project root to customize behavior
or override auto-detection. See `Config` for options.

## Custom Stages

A project's own check - a house rule, a schema linter, a shell script gate -
runs as a stage of the run rather than beside it, declared under `custom:` in
`.quality.exs`. It gets the same parallelism, timing, printer and JSON report
as a built-in stage, which is what lets a caller route its findings. See
`ExQuality.Custom`.

## Example Output

    Running quality checks...

    ✓ Format: No changes needed (0.1s)
    ✓ Compile: dev + test compiled (warnings as errors) (1.8s)

    Running analysis stages in parallel...

    ○ Doctor: skipped (:doctor not installed)
    ✓ Credo: No issues (1.2s)
    ✓ Tests: 248 passed, 0 failed, 87.3% coverage (5.2s)
    ✓ Dialyzer: No warnings (32.1s)

    ✓ All quality checks passed!

## Skipped Stages

A stage that is disabled, or whose tool is not installed, prints a line
saying so with the reason. A run never leaves out a stage silently: a
missing stage would otherwise read as a stage that passed.

## Machine-Readable Output

The exit code says the run failed, not what failed. A caller that wants to
route on the result asks for a report instead of scraping the console:

    mix quality --format json           # report on stdout, human on stderr
    mix quality --report .quality.json  # human on stdout, report to a file
    mix quality --report -              # the same as --format json

`--report PATH` is usually the most useful, because it leaves the human
stream intact, and it can be given alongside `--format json`.

The root of the report carries `profile`, `scope` and `base_ref`, because
`status` alone does not say what a run is evidence for: a green run over three
test files and a green full run are different claims. See `ExQuality.Report`
for the shape.

## Dialyzer PLT

A run that has to build the Dialyzer PLT says so while it happens
(`⋯ Dialyzer: building PLT (this is a one-time cost)`) and reports it in the
stage summary, because a multi-minute wait behind a single line of output
otherwise reads as a hang. `mix quality.plt` builds it outside a run, which
is what a container image or a CI job should cache.

# `run`

Runs the quality check task.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
