Why
The fastest edit-run loop after a red suite is "run only what just failed". bashunit has rich selection (--filter, --tag, file:line, shard) but no failure memory — after a failing run you must hand-craft a --filter or re-run everything. PHPUnit (--cache-result + --order-by=defects), pytest (--lf), and Jest (--onlyFailures) all ship this.
Proposal
Add --rerun-failed (env: BASHUNIT_RERUN_FAILED):
- Record: every run writes failing tests as
<test_file>:<function_name> lines to a cache file, e.g. .bashunit/last-failed under the working directory (create dir lazily; document adding .bashunit/ to .gitignore in the docs page). Write it on normal exit: sequential failures are known in bashunit::runner::parse_result / state layer; parallel failures are known after aggregation in src/parallel.sh (aggregate_test_results) — hook the common point where _BASHUNIT_TESTS_FAILED is finalized, not each mode separately if possible. A fully green run truncates the cache.
- Replay: with
--rerun-failed, if the cache exists and is non-empty, restrict discovery to the files listed and filter to the recorded function names (reuse the existing per-file function filtering used by file:line selection — see bashunit::helper::find_function_at_line wiring at src/main.sh:327 for how an inline filter is applied). If the cache is missing or empty, print a short notice and run the full suite.
- Flag parsing in
src/main.sh (test subcommand options block), .env.example entry, and --help text.
Edge cases to cover
- Data-provider tests: record the base function name once; replaying runs all its data rows.
- Interpolated/parameterized display names must not leak into the cache — store the raw
fn_name.
- Cache entries pointing at deleted files/functions: skip with a warning, don't crash.
--rerun-failed combined with --filter/--tag: intersect (both filters apply).
- Parallel mode writes the same cache format.
Tests first (TDD)
Acceptance tests in tests/acceptance/ (pattern: existing CLI tests spawning ./bashunit as subprocess): failing run populates cache, --rerun-failed runs only those tests, green run clears cache, empty-cache fallback message. Unit tests for the cache read/write helpers.
Constraints
- Bash 3.0+ (no mapfile, no associative arrays).
- No behavior change when the flag is absent, except writing the cache file. Write it on every run (one write at end of run, cheap) so "fail, then
--rerun-failed" works without pre-planning; document this. If a read-only CWD makes the write fail, ignore silently.
- Update
docs/ and CHANGELOG.md (user-visible feature).
Acceptance criteria
Line references valid at commit 1ae3e82.
Why
The fastest edit-run loop after a red suite is "run only what just failed". bashunit has rich selection (
--filter,--tag,file:line, shard) but no failure memory — after a failing run you must hand-craft a--filteror re-run everything. PHPUnit (--cache-result+--order-by=defects), pytest (--lf), and Jest (--onlyFailures) all ship this.Proposal
Add
--rerun-failed(env:BASHUNIT_RERUN_FAILED):<test_file>:<function_name>lines to a cache file, e.g..bashunit/last-failedunder the working directory (create dir lazily; document adding.bashunit/to.gitignorein the docs page). Write it on normal exit: sequential failures are known inbashunit::runner::parse_result/ state layer; parallel failures are known after aggregation insrc/parallel.sh(aggregate_test_results) — hook the common point where_BASHUNIT_TESTS_FAILEDis finalized, not each mode separately if possible. A fully green run truncates the cache.--rerun-failed, if the cache exists and is non-empty, restrict discovery to the files listed and filter to the recorded function names (reuse the existing per-file function filtering used byfile:lineselection — seebashunit::helper::find_function_at_linewiring atsrc/main.sh:327for how an inline filter is applied). If the cache is missing or empty, print a short notice and run the full suite.src/main.sh(test subcommand options block),.env.exampleentry, and--helptext.Edge cases to cover
fn_name.--rerun-failedcombined with--filter/--tag: intersect (both filters apply).Tests first (TDD)
Acceptance tests in
tests/acceptance/(pattern: existing CLI tests spawning./bashunitas subprocess): failing run populates cache,--rerun-failedruns only those tests, green run clears cache, empty-cache fallback message. Unit tests for the cache read/write helpers.Constraints
--rerun-failed" works without pre-planning; document this. If a read-only CWD makes the write fail, ignore silently.docs/and CHANGELOG.md (user-visible feature).Acceptance criteria
./bashunit tests/and./bashunit --parallel tests/pass.make sa,make lintpass;shfmt -w .produces no diff.--helpdocuments the flag; docs page updated.Line references valid at commit 1ae3e82.