Current section
Files
Jump to
Current section
Files
lib/mix/tasks/flaky.ex
defmodule Mix.Tasks.Flaky do
@moduledoc """
Detects new tests in git diff (HEAD vs main) and runs them repeatedly to catch flaky tests.
## Usage
mix flaky [options]
## Options
* `--iterations`, `-n` - Number of times to repeat each test (default: 100)
* `--base`, `-b` - Base branch to compare against (default: main)
* `--seed`, `-s` - Specific seed for reproducibility
* `--dry-run` - Show which tests would be run without running them
* `--parallel`, `-p` - Run tests in parallel with N concurrent processes (default: 3)
* `--failed`, `-f` - Re-run only previously failed tests from .flaky/failed_tests.txt
* `--print-full-log`, `-l` - Show full error logs (default: 10 lines)
* `--watch-errors`, `-w` - Tail error log file in real-time
* `--help`, `-h` - Show this help message
## Examples
mix flaky
mix flaky --iterations 50
mix flaky --base develop
mix flaky --seed 12345 --iterations 200
mix flaky --dry-run
mix flaky --parallel 3
mix flaky -p 5
mix flaky --failed
mix flaky --print-full-log
"""
use Mix.Task
@shortdoc "Run new tests repeatedly to detect flaky tests"
@switches [
iterations: :integer,
base: :string,
seed: :integer,
dry_run: :boolean,
parallel: :integer,
failed: :boolean,
print_full_log: :boolean,
watch_errors: :boolean,
help: :boolean
]
@aliases [
n: :iterations,
b: :base,
s: :seed,
p: :parallel,
f: :failed,
l: :print_full_log,
w: :watch_errors,
h: :help
]
@spec run(list(String.t())) :: :ok | no_return()
def run(args) do
{opts, _rest} = OptionParser.parse!(args, strict: @switches, aliases: @aliases)
if Keyword.get(opts, :help, false) do
Mix.shell().info(@moduledoc)
else
run_opts = %{
iterations: Keyword.get(opts, :iterations, 100),
base: Keyword.get(opts, :base, "main"),
seed: Keyword.get(opts, :seed),
dry_run: Keyword.get(opts, :dry_run, false),
parallel: Keyword.get(opts, :parallel),
failed: Keyword.get(opts, :failed, false),
print_full_log: Keyword.get(opts, :print_full_log, false),
watch_errors: Keyword.get(opts, :watch_errors, false)
}
case Flaky.run(run_opts) do
:ok -> :ok
{:error, msg} -> Mix.raise(msg)
end
end
end
end