Describe the bug
When a project has neither jmf.globalRules nor a jmf-rules.txt file, the Maven rewrite
and verify goals abort the build:
Failed to execute goal io.github.moranaapps:jacoco-method-filter-maven-plugin:2.2.0:rewrite
(jmf-rewrite) on project X: Configuration problems detected:
- Rules configuration missing at: .../jmf-rules.txt
Solution: execute 'mvn io.github.moranaapps:jacoco-method-filter-maven-plugin:2.2.0:init-rules'
The CLI enforces the same rule — CoverageRewriterCli.checkConfig:
} else if (cfg.globalRules.isEmpty && cfg.localRules.isEmpty) {
failure("At least one of --global-rules or --local-rules must be specified")
}
Expected: no rules configured ⇒ every class passes through unchanged ⇒ a normal, unfiltered
JaCoCo report. Method filtering is an opt-in refinement; its absence should not be a build error.
Why this matters
It blocks wiring the plugin into a shared / parent POM for a group of projects. The moment the
coverage profile runs, every project that has not yet authored a jmf-rules.txt fails its build.
The only escapes are -Djmf.skip=true (turns the whole thing off, per project) or forcing every
project to commit a rules file before it is ready. That defeats the point of a common, centrally
managed coverage setup.
This is a regression AND an internal inconsistency
-
CHANGELOG [1.0.0] (2024-08-24) lists "Quiet-exit mode for builds without a rules file" as
a shipped feature. The 2.0.0 rework (--global-rules / --local-rules, the checkConfig
"at least one" requirement, the new Maven mojos) dropped it.
-
The sbt plugin already does the right thing. JacocoFilterPlugin.jmfRewrite / jmfVerify:
val hasRulesConfig = globalRules.isDefined || localRules.exists(_.exists) || rulesFile.exists
if (!hasRulesConfig) { log.warn(s"[jmf] rules file missing: ...; skipping."); classesIn }
It warns and proceeds on the original classes. Only the Maven plugin + CLI hard-fail.
-
The core engine already supports it. Rules.loadAll(None, None) returns Seq.empty;
CoverageRewriter.run with an empty rule set walks every class, marks 0 methods, and writes a
complete pass-through copy to --out:
[info] Processed N class file(s), marked 0 method(s).
So the "no rules" path is blocked only by two artificial guards (CLI checkConfig +
RewriteMojo/VerifyMojo.checkInputs). The desired behaviour needs no core changes.
Docs currently document it as an error
docs/rules-reference.md → CLI Reference:
| --global-rules <path\|url> | At least one of the two | Global rules file path or URL |
| --local-rules <path> | At least one of the two | Local rules file path |
Steps to reproduce
Minimal Maven project, jacoco-method-filter-maven-plugin:2.2.0 rewrite execution bound in a
profile, no jmf-rules.txt:
mvn -Pcoverage clean verify
→ BUILD FAILURE at jmf:rewrite, exit 1. Reproduced on Maven 3.9.16 / Temurin JDK 1.8.0_504 /
Windows 11 / JMF 2.2.0 (a parent+consumer repro is available on request).
Expected state
rewrite with no rules → BUILD SUCCESS; target/classes-filtered holds an unchanged copy of
every class; a later report produces a normal JaCoCo report.
verify with no rules → BUILD SUCCESS, "0 methods matched".
- CLI
--in … --out … with neither --global-rules nor --local-rules → exit 0, pass-through.
- Maven and sbt behave identically for the no-rules case.
Proposed fix
1. CLI — CoverageRewriterCli.checkConfig
Remove the cfg.globalRules.isEmpty && cfg.localRules.isEmpty → failure(...) branch. With zero
sources, run() already produces a pass-through copy and logs Loaded 0 rule(s).
2. CLI — missing --local-rules file
Rules.loadFromPath throws NoSuchFileException for a non-existent path. Preferred: when a
--local-rules path does not exist, emit
[warn] local rules file not found: <path> — proceeding with 0 local rules and treat it as empty.
(Otherwise wrappers must be careful never to pass the flag for an absent file.)
3. Maven — RewriteMojo / VerifyMojo
- Drop the
hasRulesConfig hard-fail in checkInputs(). When nothing resolves, log
[INFO] No JMF rules configured (no jmf.globalRules, no <basedir>/jmf-rules.txt) — classes pass through unfiltered.
and continue.
- Only pass
--local-rules to the CLI when the file actually exists. (localRules is never null
— it has a default of ${project.basedir}/jmf-rules.txt — so today --local-rules <nonexistent>
is always sent.)
- Net effect:
rewrite still populates target/classes-filtered (pass-through), so the resources
overlay and report downstream are unaffected.
4. Opt-in strictness (optional but recommended)
Add jmf.requireRules (Maven) / --require-rules (CLI), default false, that restores today's
"fail when no rules" behaviour for teams that want it enforced in CI.
5. Docs
docs/rules-reference.md CLI table: --global-rules / --local-rules → Optional. With neither,
all classes pass through unfiltered (no-op).
maven-plugin/README.md: document the pass-through behaviour and jmf.requireRules.
CHANGELOG.md: note restoration of the v1.0.0 "quiet-exit mode for builds without a rules file".
Acceptance criteria
mvn …:rewrite with no jmf.globalRules and no jmf-rules.txt → BUILD SUCCESS;
target/classes-filtered contains an unchanged copy of every .class; a subsequent report
yields a normal JaCoCo report.
mvn …:verify with no rules → BUILD SUCCESS, 0 matched methods.
- CLI
--in … --out … with no rules sources → exit 0, pass-through copy.
- Today's behaviour is still reachable via
jmf.requireRules=true / --require-rules.
- sbt and Maven behave identically for the no-rules case.
- Integration tests cover the no-rules path for CLI, Maven, and sbt.
- Docs and CHANGELOG updated.
Impact / Severity
High — blocks adoption via a shared parent POM, which is the intended model for org-wide
standardisation.
Attachments / Evidence
CoverageRewriterCli.scala checkConfig (the CLI guard)
RewriteMojo.java / VerifyMojo.java checkInputs() (the Maven guard)
JacocoFilterPlugin.scala jmfRewrite / jmfVerify (the sbt path that already warns-and-skips)
CoverageRewriter.scala run() + Rules.loadAll (core already yields a pass-through on empty rules)
CHANGELOG.md [1.0.0] — "Quiet-exit mode for builds without a rules file"
Desktop
- OS: Windows 11
- Maven: 3.9.16
- JDK: Eclipse Temurin 1.8.0_504
- JMF: 2.2.0 (maven plugin + core)
Related / References
Describe the bug
When a project has neither
jmf.globalRulesnor ajmf-rules.txtfile, the Mavenrewriteand
verifygoals abort the build:The CLI enforces the same rule —
CoverageRewriterCli.checkConfig:Expected: no rules configured ⇒ every class passes through unchanged ⇒ a normal, unfiltered
JaCoCo report. Method filtering is an opt-in refinement; its absence should not be a build error.
Why this matters
It blocks wiring the plugin into a shared / parent POM for a group of projects. The moment the
coverage profile runs, every project that has not yet authored a
jmf-rules.txtfails its build.The only escapes are
-Djmf.skip=true(turns the whole thing off, per project) or forcing everyproject to commit a rules file before it is ready. That defeats the point of a common, centrally
managed coverage setup.
This is a regression AND an internal inconsistency
CHANGELOG
[1.0.0](2024-08-24) lists "Quiet-exit mode for builds without a rules file" asa shipped feature. The 2.0.0 rework (
--global-rules/--local-rules, thecheckConfig"at least one" requirement, the new Maven mojos) dropped it.
The sbt plugin already does the right thing.
JacocoFilterPlugin.jmfRewrite/jmfVerify:It warns and proceeds on the original classes. Only the Maven plugin + CLI hard-fail.
The core engine already supports it.
Rules.loadAll(None, None)returnsSeq.empty;CoverageRewriter.runwith an empty rule set walks every class, marks 0 methods, and writes acomplete pass-through copy to
--out:[info] Processed N class file(s), marked 0 method(s).So the "no rules" path is blocked only by two artificial guards (CLI
checkConfig+RewriteMojo/VerifyMojo.checkInputs). The desired behaviour needs no core changes.Docs currently document it as an error
docs/rules-reference.md→ CLI Reference:|
--global-rules <path\|url>| At least one of the two | Global rules file path or URL ||
--local-rules <path>| At least one of the two | Local rules file path |Steps to reproduce
Minimal Maven project,
jacoco-method-filter-maven-plugin:2.2.0rewriteexecution bound in aprofile, no
jmf-rules.txt:→
BUILD FAILUREatjmf:rewrite, exit 1. Reproduced on Maven 3.9.16 / Temurin JDK 1.8.0_504 /Windows 11 / JMF 2.2.0 (a parent+consumer repro is available on request).
Expected state
rewritewith no rules →BUILD SUCCESS;target/classes-filteredholds an unchanged copy ofevery class; a later
reportproduces a normal JaCoCo report.verifywith no rules →BUILD SUCCESS, "0 methods matched".--in … --out …with neither--global-rulesnor--local-rules→ exit 0, pass-through.Proposed fix
1. CLI —
CoverageRewriterCli.checkConfigRemove the
cfg.globalRules.isEmpty && cfg.localRules.isEmpty→failure(...)branch. With zerosources,
run()already produces a pass-through copy and logsLoaded 0 rule(s).2. CLI — missing
--local-rulesfileRules.loadFromPaththrowsNoSuchFileExceptionfor a non-existent path. Preferred: when a--local-rulespath does not exist, emit[warn] local rules file not found: <path> — proceeding with 0 local rulesand treat it as empty.(Otherwise wrappers must be careful never to pass the flag for an absent file.)
3. Maven —
RewriteMojo/VerifyMojohasRulesConfighard-fail incheckInputs(). When nothing resolves, log[INFO] No JMF rules configured (no jmf.globalRules, no <basedir>/jmf-rules.txt) — classes pass through unfiltered.and continue.
--local-rulesto the CLI when the file actually exists. (localRulesis nevernull— it has a default of
${project.basedir}/jmf-rules.txt— so today--local-rules <nonexistent>is always sent.)
rewritestill populatestarget/classes-filtered(pass-through), so the resourcesoverlay and
reportdownstream are unaffected.4. Opt-in strictness (optional but recommended)
Add
jmf.requireRules(Maven) /--require-rules(CLI), defaultfalse, that restores today's"fail when no rules" behaviour for teams that want it enforced in CI.
5. Docs
docs/rules-reference.mdCLI table:--global-rules/--local-rules→ Optional. With neither,all classes pass through unfiltered (no-op).
maven-plugin/README.md: document the pass-through behaviour andjmf.requireRules.CHANGELOG.md: note restoration of the v1.0.0 "quiet-exit mode for builds without a rules file".Acceptance criteria
mvn …:rewritewith nojmf.globalRulesand nojmf-rules.txt→BUILD SUCCESS;target/classes-filteredcontains an unchanged copy of every.class; a subsequentreportyields a normal JaCoCo report.
mvn …:verifywith no rules →BUILD SUCCESS, 0 matched methods.--in … --out …with no rules sources → exit 0, pass-through copy.jmf.requireRules=true/--require-rules.Impact / Severity
High — blocks adoption via a shared parent POM, which is the intended model for org-wide
standardisation.
Attachments / Evidence
CoverageRewriterCli.scalacheckConfig(the CLI guard)RewriteMojo.java/VerifyMojo.javacheckInputs()(the Maven guard)JacocoFilterPlugin.scalajmfRewrite/jmfVerify(the sbt path that already warns-and-skips)CoverageRewriter.scalarun()+Rules.loadAll(core already yields a pass-through on empty rules)CHANGELOG.md[1.0.0]— "Quiet-exit mode for builds without a rules file"Desktop
Related / References