Skip to content

feat(cli): --rerun-failed to replay only the last failing tests #776

Description

@Chemaclass

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

  1. 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.
  2. 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.
  3. 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

  • ./bashunit tests/ and ./bashunit --parallel tests/ pass.
  • make sa, make lint pass; shfmt -w . produces no diff.
  • --help documents the flag; docs page updated.

Line references valid at commit 1ae3e82.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions