Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
6c4950e
feat(mvn)!: Rust module replacing TOML filter, adds test phase support
vdufloth May 17, 2026
cc152cd
fix(mvn): match Surefire 3.x close lines, preserve failure stack trail
vdufloth May 21, 2026
77e28d0
refactor(mvn): drop production duration normalisation
vdufloth May 21, 2026
97dbf98
feat(mvn): filter mvn -q quiet-mode output
vdufloth May 21, 2026
97bd2a7
fix(mvn): preserve compile-error continuation in filter_surefire
vdufloth May 25, 2026
5459c6d
refactor(mvn): extract shared SurefireBlock state machine
vdufloth May 25, 2026
4609102
fix(mvn): keep multi-module Reactor Summary rows
vdufloth May 25, 2026
be6c812
feat(mvn): cap failing-class blocks and Failures summary entries
vdufloth May 25, 2026
92a9218
refactor(mvn): polish — strip_prefix, borrow buffers, CRLF tests
vdufloth May 25, 2026
f58333c
chore(mvn): drop unrelated Cargo.lock churn from PR
vdufloth May 25, 2026
1050cfe
fix(mvn): re-arm failure trail on per-test sublines
vdufloth Jun 6, 2026
be28a51
fix(ci): pin fixture line endings, harden CRLF tests
vdufloth Jun 6, 2026
df76528
fix(mvn): strip post-failure help boilerplate in non-quiet mode
vdufloth Jun 6, 2026
f026cfd
Merge branch 'develop' into feat/mvn-rust-module
vdufloth Jun 7, 2026
3c0ee94
refactor(mvn): bind failure cap to truncate::CAP_WARNINGS, drop confi…
vdufloth Jun 7, 2026
f8bc856
style(mvn): align overflow tail with canonical '… +N more {label}' shape
vdufloth Jun 7, 2026
047f454
Merge pull request #1956 from vdufloth/feat/mvn-rust-module
aeppling Jun 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Fixtures are byte-exact filter inputs; eol conversion must never touch them.
# Without this, Windows runners (core.autocrlf=true) check fixtures out with
# CRLF, and tests that synthesize CRLF input from them produce \r\r\n.
tests/fixtures/** -text
42 changes: 42 additions & 0 deletions src/cmds/jvm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# JVM ecosystem filters

Filters for JVM-based build tools.

| Module | Tool(s) | Modes |
|------------------|--------------------------------------|----------------------------------------------------------------------------------------|
| `gradlew_cmd.rs` | `./gradlew`, `gradlew.bat`, `gradle` | Build / Test / ConnectedTest / Lint / Dependencies — streaming line filter + passthrough |
| `mvn_cmd.rs` | `mvn`, `./mvnw`, `mvnw.cmd` | Test / Compile / Package / Passthrough — buffered single-pass filter per phase |

## Maven (`mvn_cmd.rs`)

Phase routing (`detect_phase`):

| Phase | Goals | Filter |
|-------------|--------------------------------------------------------|-------------------------|
| `Test` | `test`, `integration-test` (Failsafe = Surefire shape) | `filter_surefire` |
| `Compile` | `compile`, `test-compile` | `filter_compile` |
| `Package` | `package`, `install`, `verify`, `deploy` | `filter_package` |
| `Passthrough` | `clean`, `site`, `dependency:*`, `--version`, `--help`, empty, any unrecognised goal | none |

Key behaviours:

- **ANSI strip first** in every filter — real Maven output contains colour escapes.
- **English-footer guard** — if neither `BUILD SUCCESS` nor `BUILD FAILURE` appears as a trimmed line suffix, return the ANSI-stripped raw input unchanged. Protects non-English locales.
- **Verbose bypass** — `-X`, `--debug`, `-e`, `--errors` skip filtering (`run_passthrough`). User asked for detail; respect it.
- **Surefire block collapse** — Surefire emits `[INFO] Running <FQN>` … `[INFO] Tests run: N, Failures: F, Errors: E, …, Time elapsed: T s - in <FQN>`. The filter buffers each block and emits it only when `F > 0` or `E > 0`. Passing blocks (the bulk of healthy-project output) are dropped silently. Failing blocks are emitted with framework stack frames stripped via a deny-list (`at org.junit.`, `at java.util.`, `at sun.reflect.`, etc.).
- **Multi-failure classes (trail re-arm)** — when a single class has several failing tests, Surefire 3.x emits one blank-separated detail block per failing test under a single close line. When a failure trail ends at a blank line, the state machine arms a re-entry: the next per-test subline (`[ERROR] FQN.method -- Time elapsed: … <<< FAILURE!` or `<<< ERROR!`) re-enters the trail with the same keep/drop decision, so every failure message survives (and a capped class drops *all* its blocks). Any other non-blank line disarms the re-entry.
- **`<<< ERROR!` markers** — per-test sublines use `<<< ERROR!` for thrown (non-assertion) exceptions; the close-line regex also tolerates an `ERROR!` marker defensively (Surefire 3.5.5 emits `FAILURE!` even for errors-only classes — failure detection keys off the `Failures`/`Errors` counts, not the marker).
- **Help-boilerplate stripping (all modes)** — the post-failure block Maven emits after `[ERROR] Failed to execute goal` (`See …`, `-> [Help 1]`, `Re-run Maven`, `To see the full stack trace`, `For more information`, help URLs, bare `[ERROR]` dividers) is dropped in quiet *and* non-quiet filters alike (shared `BOILER_PREFIXES`). Deliberately kept as signal: `Failed to execute goal` itself and the multi-module resume hint (`[ERROR] After correcting the problems…` + `[ERROR] mvn <args> -rf :module` — tells the user/agent how to resume the build). Real durations (`Time elapsed: … s`, `Total time: …`) ship untouched — the numbers are diagnostic signal.
- **Wrapper detection** — `./mvnw` (POSIX) and `mvnw.cmd` (Windows) detected via string-literal `Command::new` (semgrep-safe); falls back to `resolved_command("mvn")`.
- **Reactor Summary preservation** — for multi-module builds, the trailing `Reactor Summary for <root>` block with per-module SUCCESS/FAILURE rows is kept (toggled by a `[INFO] Reactor Summary for ` header and cleared on `BUILD SUCCESS` / `BUILD FAILURE`).
- **Failure cap** — both the count of emitted failing test classes and the size of the `[ERROR] Failures:` summary block are bounded by `MAX_MVN_FAILING_CLASSES = CAP_WARNINGS` (the shared test-failure cap class from `src/core/truncate.rs`, same binding as pytest/rspec/rake/runner). Excess emissions are replaced by a single `… +N more failing test classes` / `… +N more failures` tail (canonical `join_with_overflow` shape) to keep large failure sets compact; the raw output stays recoverable via the tee `[full output: …]` hint. Per the core cap policy, a cap of `0` means summary-only: no blocks emitted, the tail still counts every dropped class.

Token-savings tests run inline as part of `cargo test --all` and verify ≥90% savings for `mvn test` and ≥85% for `mvn install` on full synthetic fixtures (gzipped, ~1100 lines each). The `flate2` dependency (already in `Cargo.toml`) decompresses the ~3 KB gzipped fixtures in milliseconds.

### Integrity-check whitelist

`Commands::Mvn` is intentionally omitted from `is_operational_command` in `src/main.rs`, matching the gradle precedent (`Commands::Gradlew` also omitted). The whitelist guards SHA-256 hook-integrity verification; filter modules invoked through an already-verified hook do not need a second check on their own dispatch path. Per the comment above the function, the whitelist is opt-in by design and a forgotten command fails open rather than creating false confidence about what's protected.

## Gradle (`gradlew_cmd.rs`)

See module docs and the gradle PR (`feat/gradlew-android-support`) for rationale. Streaming filter chosen because Gradle output is task-line-based, not block-based — unlike Maven Surefire.
Loading
Loading