README.md

# ExQuality

A parallel code quality checker for Elixir projects that runs format, compile, credo, dialyzer, dependency checks, and tests concurrently with actionable feedback.

**Perfect for iterative development**: Use `mix quality --quick` during active coding, then `mix quality` for full verification before committing.

## Features

- **🚀 Fast iteration**: `--quick` mode skips slow checks (dialyzer, coverage) for rapid feedback
- **⚡ Parallel execution**: All checks run concurrently, maximizing CPU utilization
- **🔧 Auto-fix first**: Automatically fixes formatting before running analysis
- **📊 Streaming output**: See results as each stage completes, not after everything finishes
- **🎯 Actionable feedback**: Full tool output with file:line references for easy fixing
- **🤖 Auto-detection**: Automatically enables checks based on installed dependencies
- **⚙️ Configurable**: Customize via `.quality.exs` or CLI flags
- **🧠 LLM-friendly**: Includes `usage-rules.md` for AI coding assistants

## Quick Start

```elixir
# Add to mix.exs
def deps do
  [
    {:ex_quality, "~> 0.1.0", only: :dev, runtime: false}
  ]
end
```

```bash
# Install dependencies
mix deps.get

# Set up quality tools (interactive)
mix quality.init

# Or use defaults without prompts
mix quality.init --skip-prompts
```

This will:
1. Detect which tools are already installed
2. Prompt you to select additional tools (credo, dialyzer, excoveralls recommended)
3. Add dependencies to mix.exs
4. Run `mix deps.get`
5. Set up tool configurations (.credo.exs, coveralls.json, etc.)
6. Create .quality.exs for customization

Then run quality checks:

```bash
# During development - fast feedback
mix quality --quick

# Before committing - full verification
mix quality
```

## Workflow

### Iterative Development (Fast)

When you're actively coding and want quick feedback:

```bash
mix quality --quick
```

**Quick mode skips:**
- ❌ Dialyzer (type checking is slow)
- ❌ Coverage enforcement (tests run, but coverage % not checked)

**Quick mode runs:**
- ✅ Format (auto-fixes)
- ✅ Compilation (dev + test)
- ✅ Credo (static analysis)
- ✅ Dependencies (unused deps + security audit)
- ✅ Tests (must pass)
- ✅ Doctor (if installed)
- ✅ Gettext (if installed)

**Use this when**: Making frequent changes, implementing features, fixing bugs.

### Full Verification (Complete)

Before committing, pushing, or opening a PR:

```bash
mix quality
```

**Full mode runs everything:**
- ✅ Format
- ✅ Compilation
- ✅ Credo
- ✅ Dialyzer (comprehensive type checking)
- ✅ Dependencies (unused deps + security audit)
- ✅ Tests with coverage (enforces threshold)
- ✅ Doctor
- ✅ Gettext

**Use this when**: Ready to commit, opening PRs, in CI/CD.

## Execution Phases

ExQuality runs in three phases:

### Phase 1: Auto-fix
```
✓ Format: Formatted 3 files (0.2s)
```
Automatically fixes code formatting with `mix format`.

### Phase 2: Compilation (Blocking Gate)
```
✓ Compile: dev + test compiled (warnings as errors) (2.1s)
```
Compiles both dev and test environments in parallel. Must pass before analysis.

### Phase 3: Parallel Analysis (Streaming)
```
✓ Doctor: 92% documented (0.4s)              ← prints at 0.4s
✓ Credo: No issues (1.8s)                    ← prints at 1.8s
✓ Tests: 248 passed, 87.3% coverage (5.2s)   ← prints at 5.2s
✓ Dialyzer: No warnings (32.1s)              ← prints at 32.1s
```
All checks run concurrently. Results stream as each completes.

## CLI Options

```bash
# Quick mode for iterative development
mix quality --quick

# Skip specific stages
mix quality --skip-dialyzer
mix quality --skip-credo
mix quality --skip-doctor
mix quality --skip-gettext
mix quality --skip-dependencies

# Combine flags
mix quality --quick --skip-credo
```

## Auto-Detection

ExQuality automatically enables stages based on installed dependencies:

| Stage | Requires | Auto-enabled? |
|-------|----------|---------------|
| Format | (none) | Always |
| Compile | (none) | Always |
| Credo | `:credo` | If installed |
| Dialyzer | `:dialyxir` | If installed |
| Dependencies | (none) / `:mix_audit` | Always (audit if installed) |
| Doctor | `:doctor` | If installed |
| Gettext | `:gettext` | If installed |
| Tests | (none) | Always |
| Coverage | `:excoveralls` | If installed |

**Example**: If you have credo and dialyxir in deps, ExQuality will run both automatically.

## Configuration

Create `.quality.exs` in your project root to customize behavior:

```elixir
[
  # Override auto-detection: force disable dialyzer
  dialyzer: [enabled: false],

  # Credo options
  credo: [
    strict: true,  # Use --strict mode (default: true)
    all: false     # Use --all flag (default: false)
  ],

  # Doctor options
  doctor: [
    summary_only: true  # Show only summary (default: false)
  ],

  # Dependencies options
  dependencies: [
    check_unused: true,  # Check for unused deps (default: true)
    audit: true          # Run security audit if mix_audit installed (default: :auto)
  ]
]
```

### Configuration Precedence

Configuration is merged in this order (later wins):

1. **Defaults** - Sensible built-in defaults
2. **Auto-detection** - Based on installed deps
3. **`.quality.exs`** - Project-specific config
4. **CLI flags** - Runtime overrides (highest priority)

**Example**: If `.quality.exs` disables dialyzer, but you run `mix quality` (no flags), dialyzer stays disabled. However, the auto-detection still marks it as "available" internally.

### Coverage Threshold

Coverage threshold is **NOT** configured in ExQuality. It reads from your existing excoveralls configuration:

- `coveralls.json` → `minimum_coverage` or `coverage_threshold`
- `mix.exs` → `test_coverage: [minimum_coverage: 80.0]`

This ensures a **single source of truth** for coverage requirements.

## Actionable Output

When checks fail, ExQuality shows the complete tool output with file:line references:

```bash
✗ Credo: 5 issue(s) (1 refactoring, 2 readability, 2 design) (0.4s)

────────────────────────────────────────────────────────────
Credo - FAILED
────────────────────────────────────────────────────────────
┃ [D] ↘ Nested modules could be aliased at the top of the invoking module.
┃       lib/mix/tasks/quality.ex:96:22 #(Mix.Tasks.Quality.run)
┃
┃ [R] ↗ Predicate function names should not start with 'is'...
┃       lib/ex_quality/stages/dialyzer.ex:92:8 #(ExQuality.Stages.Dialyzer.is_debug_info_error?)
```

**Why this matters:**
- Humans can click file:line in their editor
- LLMs can see exactly what needs fixing
- No need to run individual tools to get details

## Recommended Dependencies

For the best experience, add these to your `mix.exs`:

```elixir
def deps do
  [
    # Recommended quality tools
    {:credo, "~> 1.7", only: [:dev, :test], runtime: false},
    {:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false},
    {:excoveralls, "~> 0.18", only: :test},
    {:doctor, "~> 0.21", only: :dev, runtime: false},
    {:mix_audit, "~> 2.1", only: [:dev, :test], runtime: false},

    # If you use translations
    {:gettext, "~> 0.24"},

    # Quality checker
    {:ex_quality, "~> 0.1.0", only: :dev, runtime: false}
  ]
end
```

## Integration

### In CI/CD

Run full quality checks in your CI pipeline:

```yaml
# GitHub Actions
- name: Run quality checks
  run: mix quality
```

**Note**: Dialyzer requires a PLT (Persistent Lookup Table). You may want to cache it:

```yaml
- name: Restore PLT cache
  uses: actions/cache@v3
  with:
    path: priv/plts
    key: ${{ runner.os }}-plt-${{ hashFiles('**/mix.lock') }}
```

### Pre-commit Hook

Add to `.git/hooks/pre-commit`:

```bash
#!/bin/sh
mix quality --quick
```

This gives you fast feedback before committing.

### In Your Development Workflow

**During feature development:**
```bash
# Make changes
vim lib/my_app/feature.ex

# Quick check (fast)
mix quality --quick

# Fix issues, repeat
```

**Before committing:**
```bash
# Full verification
mix quality

# If it passes, commit
git add .
git commit -m "Add feature"
```

## Comparison with Alternatives

| Feature | ExQuality | ex_check | al_check |
|---------|-----------|----------|----------|
| Parallel execution | ✅ | ✅ | ✅ |
| Streaming output | ✅ | ❌ | ❌ |
| Auto-fix first | ✅ | ✅ | ✅ |
| Auto-detect tools | ✅ | ✅ | ❌ |
| Quick mode | ✅ | ❌ | ✅ |
| LLM-friendly | ✅ | ❌ | ❌ |
| Config file | .quality.exs | .check.exs | alcheck.toml |
| Actionable output | ✅ Full tool output | ✅ | ✅ |

**ExQuality's differentiators:**
1. **Quick mode** - Fast iteration during development
2. **Streaming output** - See results as each check completes
3. **Auto-fix first** - Format code before analysis
4. **LLM integration** - Includes `usage-rules.md` for AI assistants

## Troubleshooting

### "Dialyzer is too slow"

Use quick mode during development:
```bash
mix quality --quick
```

Or disable it permanently in `.quality.exs`:
```elixir
[dialyzer: [enabled: false]]
```

### "Credo is too strict"

Adjust strictness in `.quality.exs`:
```elixir
[credo: [strict: false]]
```

Or create `.credo.exs` to configure credo directly.

### "I don't have doctor/gettext"

ExQuality auto-detects and skips them. No configuration needed.

### "Tests are failing"

ExQuality shows the full test output with file:line references. Look for the failure details in the output.

## Philosophy

**ExQuality is designed for rapid, iterative development with confidence.**

1. **Fast feedback loop**: `--quick` gives you sub-second feedback on most changes
2. **Comprehensive verification**: Full mode ensures everything is correct
3. **Actionable output**: See exactly what needs fixing, with file:line references
4. **Zero configuration**: Works out of the box with sensible defaults
5. **Progressive enhancement**: Add tools as you need them

## License

MIT

## Contributing

Issues and pull requests welcome at [https://github.com/riddler/ex_quality](https://github.com/riddler/ex_quality)