mix quality (ExQuality v0.13.0)

View Source

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-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

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.

Summary

Functions

Runs the quality check task.

Functions

run(args)

Runs the quality check task.