skip to content

How do you make a static analysis plugin actually break the build on violations, and what knobs control that behavior?

level: middleimportance: must knowfreq 50%

answer

  1. check goal not report goal
  2. failOnViolation / failOnError
  3. violationSeverity / threshold
  4. maxAllowedviolations ratchet
  5. spotless:check vs apply

basics

~10 s

Use the *:check goal (not the report goal) and keep its failure flag on: maven-checkstyle-plugin/maven-pmd-plugin use failOnViolation=true, spotbugs uses failOnError=true. Bind it to a phase like verify so mvn verify fails when violations exist.

solid answer

~30 s

Two things must be true: you run the failing goal, and you don't suppress its failure. The check goals (checkstyle:check, pmd:check, spotbugs:check, spotless:check) are the ones that can fail. Then per-plugin flags decide severity: Checkstyle has failOnViolation (true by default) plus violationSeverity to set the threshold (warning vs error); PMD has failOnViolation and failurePriority; SpotBugs has failOnError plus threshold/effort and an optional maxAllowedViolations. Bind the goal to verify (or validate for fast style checks) via an execution so a normal CI build enforces it. A common mistake is leaving failOnViolation=false 'for now' which silently turns the gate into a no-op.

code

bash · 4 lines
bash
# fails on violations because check goals are bound to verify
mvn -B verify
# report-only, never fails (for local inspection)
mvn spotbugs:spotbugs checkstyle:checkstyle

go deeper

for a junior

Run the check goal and keep failOnViolation true.

for a middle

Knows the fail flags and severity thresholds per plugin and how they interact.

for a senior

Tunes threshold/effort and uses maxAllowedViolations to ratchet legacy debt down without a big-bang fix.

for a principal

Designs the org gating policy: which severities block merges, how thresholds evolve, and how exceptions are governed.

## The gate has two switches For a static-analysis gate to actually block a bad build, both must hold: 1. You invoke the **check** goal (the report goal never fails). 2. The plugin's **fail flag** is enabled and the severity **threshold** catches the issue. ## Per-plugin flags - **Checkstyle**: `failOnViolation` (default `true`) and `violationSeverity` (`error` default; lower to `warning` to be stricter). `consoleOutput=true` prints findings. - **PMD**: `failOnViolation` (default `true`), `failurePriority` (1 highest .. 5; only violations at/above the configured priority fail), and `printFailingErrors`. CPD has its own `cpd-check` goal with `failOnViolation`. - **SpotBugs**: `failOnError` (default `true`), `threshold` (Low/Medium/High — how confident a bug must be), `effort` (Min/Default/Max), and `maxAllowedViolations` to ratchet down over time. - **Spotless**: `spotless:check` fails when files aren't formatted; `spotless:apply` rewrites them. There's no severity — it's pass/fail formatting. ## Worked example ```xml <plugin> <groupId>com.github.spotbugs</groupId> <artifactId>spotbugs-maven-plugin</artifactId> <version>4.8.6.6</version> <configuration> <effort>Max</effort> <threshold>Low</threshold> <failOnError>true</failOnError> <plugins> <plugin> <groupId>com.h3xstream.findsecbugs</groupId> <artifactId>findsecbugs-plugin</artifactId> <version>1.13.0</version> </plugin> </plugins> </configuration> <executions> <execution> <id>spotbugs-check</id> <phase>verify</phase> <goals><goal>check</goal></goals> </execution> </executions> </plugin> ``` ## Common no-op mistakes - Running `spotbugs:spotbugs` (report) instead of `spotbugs:check`. - Setting `failOnViolation=false` 'temporarily' so the gate stops failing — now it's decorative. - Severity threshold too high (e.g. PMD failurePriority=1) so most findings are ignored. - Forgetting the `<execution>` so the goal never runs in CI.

  • Your build is green but you know there are SpotBugs warnings — what would you check?
    Whether spotbugs:check is actually bound to a phase, whether failOnError is true, and whether the threshold/effort is high enough to surface those bugs.
  • What's the difference between violationSeverity and a suppression file?
    violationSeverity globally raises/lowers which severities fail; a suppression file selectively excludes specific files/rules while keeping the gate strict elsewhere.

saying these in an interview costs you the question

  • Setting failOnViolation=false and calling the gate 'enabled'
  • Believing the report goal can fail a build
  • Setting PMD failurePriority too low (high number) so nothing fails

context