CheckEscript (AlCheck v0.1.13)

View Source

Runs all code quality checks in parallel.

Usage

check                                # Run all checks
check -v                             # Show version
check --init                         # Create .check.json with defaults
check --help/-h                      # Show this help message
check --fast                         # Run only fast checks (format, compile, credo)
check --only format,test             # Run only format and test
check --only credo                   # Run credo and credo_strict
check --only modified_tests          # Run only modified/new tests vs base branch
check --only modified_test_modules   # Run whole test files modified vs base branch
check --partitions 2                 # Run tests with 2 partitions (default: 3)
check --dir test/dir                 # Run tests only from specific directory
check --dir test/foo,test/bar        # Run tests from multiple directories
check --fix                          # Apply fixes from stored credo output
check --failed                       # Re-run only failed tests from previous run
check --watch                        # Monitor test partition files in real-time
check --test-args '--exclude slow'   # Replace default --warnings-as-errors with custom args
check --verbose                     # Print test output directly instead of partition status
check --coverage                    # Show coverage report (cached if unchanged)
check --repeat 10                   # Run tests with --repeat-until-failure 10 (default: 100)

Available checks

  • format - mix format --check-formatted
  • compile - mix compile --warnings-as-errors
  • compile_test - MIX_ENV=test mix compile --warnings-as-errors
  • dialyzer - mix dialyzer
  • credo - mix credo --all
  • credo_strict - mix credo --strict --only readability --all
  • test - mix test (runs in partitions for parallel execution)

Fast checks

The --fast flag runs only: format, compile, compile_test, credo, credo_strict (skips: dialyzer, test)

Test partitioning

Tests run in parallel partitions (default: 3). Each partition uses its own database. Use --partitions N to customize the number of partitions based on your CPU cores.

Database setup for partitions

Each partition needs its own database to avoid deadlocks and connection limit issues. In config/runtime.exs, use MIX_TEST_PARTITION to create per-partition database URLs:

# config/runtime.exs
partition = System.get_env("MIX_TEST_PARTITION", "")

test_database_url =
  System.get_env("TEST_DATABASE_URL")
  |> URI.parse()
  |> then(fn uri ->
    db_name = String.trim_leading(uri.path || "", "/")
    Map.put(uri, :path, "/#{db_name}#{partition}")
  end)
  |> URI.to_string()

config :my_app, MyApp.Repo, url: test_database_url

This creates databases like my_app_test1, my_app_test2, etc.

Avoiding DB connection limits

With N partitions, your database needs at least N * pool_size connections. Increase max_connections in PostgreSQL if you see connection errors:

# PostgreSQL config (or docker run command)
postgres -c max_connections=400 -c shared_buffers=2GB

Consider reducing pool_size per partition in config/test.exs:

config :my_app, MyApp.Repo, pool_size: 10

With 3 partitions and pool_size 10, you need at least 30 connections.

Scheduler tuning

AlCheck automatically limits BEAM schedulers per partition to avoid CPU contention: schedulers_online / partitions. With 10 cores and 3 partitions, each gets ~3 schedulers.

Failed test workflow

When tests fail, failed test locations are automatically saved to check/failed_tests.txt:

check --only test     # Run tests and save failures
cat .check/failed_tests.txt # View failed tests
check --failed        # Re-run only the failed tests

Auto-fix workflow

Format and credo failures are tracked in .check/ directory for later use with --fix:

check --only format,credo  # Run checks and store failures
check --fix                # Apply fixes from stored failures

The --fix command will:

  • Check if format failed previously (.check/.format_failed marker) and run mix format
  • Apply credo fixes from stored output files (.check/credo.txt, .check/credo_strict.txt)

Configuration file

Create a .check.json in your project root to customize behavior. Override the path via the CHECK_CONFIG environment variable.

{
  "fast": ["format", "compile", "compile_test", "credo"],
  "partitions": 3,
  "max_concurrency": 10,
  "test_args": "--warnings-as-errors",
  "default_repeat": 100,
  "coverage": {"mod": "native", "limit": 80, "html": false},
  "checks": {
    "format": {"name": "Formatting", "run": "mix format --check-formatted"},
    "credo": {"name": "Credo", "run": "mix credo --all"}
  }
}

Name defaults to a capitalized version of the key (e.g. "compile_test" → "Compile Test").

Coverage: {"mod": "native", "limit": 80, "html": false, "baseline_cmd": "git show origin/main:coverage.txt"}. mod selects the tool (native = built-in --cover, coveralls = excoveralls). limit is optional — fails the check if total coverage is below the given percentage. html (default: false) — when true, generates full HTML report; when false, kills early after getting %. baseline_cmd is optional — shell command that outputs baseline coverage % (e.g. from main). When set, shows coverage delta vs baseline after each run. Partition coverage is merged into a single report after all partitions complete.

All fields are optional. CLI flags override config values. When checks is provided, it replaces all built-in checks (test partitions are always added).

Adding custom checks

Add a check to the "checks" section in .check.json:

"checks": {
  "sobelow": {"name": "Security", "run": "mix sobelow --config"},
  "gettext": {"name": "Gettext", "run": "mix gettext.extract --check-up-to-date"}
}

Each check needs a run key with the shell command to execute. The name is optional and defaults to a capitalized version of the key.

Shell commands

The run string is executed via sh -c, so pipes, env vars, and shell features work:

"compile_test": {"run": "MIX_ENV=test mix compile --warnings-as-errors"}

Use {base_branch} placeholder for the auto-detected base branch:

"diff_check": {"run": "git diff {base_branch}... --stat"}

Builtin checks

For checks that need Elixir logic (not just a shell command), use the builtin: prefix:

"modified_tests": {"run": "builtin:modified_tests"}

Available builtins:

  • builtin:modified_tests — runs only changed test lines vs base branch
  • builtin:modified_test_modules — runs whole modified test files vs base branch

Selecting which checks run by default

The "run" key lists which checks execute when running check without flags:

"run": ["format", "compile", "credo", "test"]

Checks not in "run" are still available via --only:

check --only sobelow
check --only modified_tests

Summary

Functions

main(args)

@spec main([String.t()]) :: :ok