From d609766eebff0789f0bb9d679ea1a1ec3a1277fd Mon Sep 17 00:00:00 2001 From: miroslavpojer Date: Tue, 1 Sep 2026 15:38:17 +0200 Subject: [PATCH 1/3] Add support to two input process method. --- CHANGELOG.md | 10 ++++++++++ build.sbt | 5 +++++ .../scala/morana/coverage/JacocoFilterPlugin.scala | 8 ++++++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4021358..eb4e300 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,16 @@ This project uses [Semantic Versioning](https://semver.org/). ## [Unreleased] +### Fixed + +- **sbt plugin restored to sbt 1.x compatibility.** v2.4.0 used the 3-arg + `Command.process` overload (added in sbt 1.10.0), so `jacocoCleanAll` / + `jacocoReportAll` failed on sbt 1.9.x with + `java.lang.NoSuchMethodError: sbt.Command$.process(...)`. Switched back to the + 2-arg overload and pinned `pluginCrossBuild / sbtVersion` to `1.9.0` so the + plugin can no longer compile against newer-than-1.9 sbt APIs. + ([#76](https://github.com/MoranaApps/jacoco-method-filter/issues/76)) + ## [2.4.0] — 2026-09-01 ### Changed diff --git a/build.sbt b/build.sbt index 994c631..fc6152f 100644 --- a/build.sbt +++ b/build.sbt @@ -88,6 +88,11 @@ lazy val sbtPlugin = (project in file("sbt-plugin")) // sbt plugins are built with Scala 2.12 for sbt 1.x scalaVersion := "2.12.21", crossScalaVersions := Seq("2.12.21"), + // Compile against the oldest supported sbt so the plugin cannot accidentally + // depend on APIs newer than sbt 1.9 (e.g. the 3-arg Command.process added in + // sbt 1.10.0, which broke JMF on sbt 1.9.x with NoSuchMethodError). The dev + // build itself still runs on the sbt.version in project/build.properties. + pluginCrossBuild / sbtVersion := "1.9.0", // Prevent publishing the legacy (non-suffixed) Maven artifacts like // `jacoco-method-filter-sbt-.jar` which Sonatype Central cannot associate // with the sbt-plugin coordinates `jacoco-method-filter-sbt_2.12_1.0`. diff --git a/sbt-plugin/src/main/scala/morana/coverage/JacocoFilterPlugin.scala b/sbt-plugin/src/main/scala/morana/coverage/JacocoFilterPlugin.scala index ee0bf8a..2f5a982 100644 --- a/sbt-plugin/src/main/scala/morana/coverage/JacocoFilterPlugin.scala +++ b/sbt-plugin/src/main/scala/morana/coverage/JacocoFilterPlugin.scala @@ -53,7 +53,10 @@ object JacocoFilterPlugin extends AutoPlugin { state } else { targets.foldLeft(state) { (st, ref) => - Command.process(s"${ref.project}/jacocoClean", st, msg => sys.error(msg)) + // 2-arg overload: works across all sbt 1.x. sbt already fails the build + // on a command/parse error, so the 3-arg onParseError callback (added in + // sbt 1.10.0) is not needed and would break sbt < 1.10 with NoSuchMethodError. + Command.process(s"${ref.project}/jacocoClean", st) } } } @@ -71,7 +74,8 @@ object JacocoFilterPlugin extends AutoPlugin { state } else { targets.foldLeft(state) { (st, ref) => - Command.process(s"${ref.project}/jacocoReport", st, msg => sys.error(msg)) + // 2-arg overload: see note in jacocoCleanAllCmd. + Command.process(s"${ref.project}/jacocoReport", st) } } } From cdef9684dc8538a2d5bb63af30bdf2ef5826cbd0 Mon Sep 17 00:00:00 2001 From: miroslavpojer Date: Tue, 1 Sep 2026 15:54:32 +0200 Subject: [PATCH 2/3] added new test --- integration-tests/README.md | 5 ++ integration-tests/fixtures/sbt-19x/build.sbt | 19 +++++++ .../fixtures/sbt-19x/jmf-rules.txt | 9 +++ .../fixtures/sbt-19x/project/build.properties | 1 + .../fixtures/sbt-19x/project/plugins.sbt | 3 + .../src/main/scala/example/Calculator.scala | 14 +++++ .../test/scala/example/CalculatorTest.scala | 29 ++++++++++ integration-tests/test-sbt-19x.sh | 55 +++++++++++++++++++ 8 files changed, 135 insertions(+) create mode 100644 integration-tests/fixtures/sbt-19x/build.sbt create mode 100644 integration-tests/fixtures/sbt-19x/jmf-rules.txt create mode 100644 integration-tests/fixtures/sbt-19x/project/build.properties create mode 100644 integration-tests/fixtures/sbt-19x/project/plugins.sbt create mode 100644 integration-tests/fixtures/sbt-19x/src/main/scala/example/Calculator.scala create mode 100644 integration-tests/fixtures/sbt-19x/src/test/scala/example/CalculatorTest.scala create mode 100644 integration-tests/test-sbt-19x.sh diff --git a/integration-tests/README.md b/integration-tests/README.md index de9f441..1eb6723 100644 --- a/integration-tests/README.md +++ b/integration-tests/README.md @@ -40,6 +40,8 @@ bash integration-tests/test-sbt-init-rules.sh | `test-cli-verify.sh` | CLI `--verify` mode shows methods that would be filtered | | `test-cli-verify-unmatched.sh` | CLI `--verify` UNMATCHED RULES report and `--error-on-unmatched` flag | | `test-sbt-basic.sh` | `examples/sbt-basic` passes tests without filtering, then with filtering + report generation | +| `test-sbt-scala211.sh` | Plugin works on a Scala 2.11 cross-build project (no `NoSuchMethodError`) | +| `test-sbt-19x.sh` | Plugin loads and `jacocoReportAll` runs on sbt 1.9.x — regression guard for the 3-arg `Command.process` (issue #76) | | `test-sbt-report-custom.sh` | sbt plugin with custom report settings (formats, title, encoding) verifies only specified formats are generated | | `test-maven-basic.sh` | `examples/maven-basic` (Java) passes tests without and with `-Pcode-coverage` | | `test-maven-report-custom.sh` | Maven plugin with custom report settings (formats, title, encoding) verifies only specified formats are generated | @@ -61,6 +63,9 @@ that has the plugin already enabled, then overlay the source and rules files from the example. This avoids fragile `sed` edits and ensures dependency resolution works cleanly in CI. +`fixtures/sbt-scala211/` and `fixtures/sbt-19x/` are self-contained variants +(own source + rules) that pin a specific Scala or sbt version. + ## CI Integration The `integration` job in `.github/workflows/ci.yml` runs `./integration-tests/run-all.sh`, diff --git a/integration-tests/fixtures/sbt-19x/build.sbt b/integration-tests/fixtures/sbt-19x/build.sbt new file mode 100644 index 0000000..03937f1 --- /dev/null +++ b/integration-tests/fixtures/sbt-19x/build.sbt @@ -0,0 +1,19 @@ +// CI fixture: minimal single-module project pinned to sbt 1.9.x. +// Guards against regressions that use sbt APIs newer than 1.9 (e.g. the 3-arg +// Command.process overload added in sbt 1.10.0, see issue #76). +lazy val root = (project in file("")) + .enablePlugins(JacocoFilterPlugin) + .settings( + name := "sbt-19x-test", + organization := "io.github.moranaapps", + scalaVersion := "2.12.21", + version := "0.1.0-SNAPSHOT", + + libraryDependencies ++= Seq( + "org.scalatest" %% "scalatest" % "3.2.18" % Test + ) + ) + +addCommandAlias("jacoco", "; jacocoOn; clean; test; jacocoReportAll; jacocoOff") +addCommandAlias("jacocoOff", "; set every jacocoPluginEnabled := false") +addCommandAlias("jacocoOn", "; set every jacocoPluginEnabled := true") diff --git a/integration-tests/fixtures/sbt-19x/jmf-rules.txt b/integration-tests/fixtures/sbt-19x/jmf-rules.txt new file mode 100644 index 0000000..5492f62 --- /dev/null +++ b/integration-tests/fixtures/sbt-19x/jmf-rules.txt @@ -0,0 +1,9 @@ +# Test rules for the sbt 1.9.x integration test +# Exclude synthetic / bridge methods +*#* synthetic +*#* bridge + +# Exclude compiler-generated methods +*#$anonfun$* +*#lambda$* +*#$default$* diff --git a/integration-tests/fixtures/sbt-19x/project/build.properties b/integration-tests/fixtures/sbt-19x/project/build.properties new file mode 100644 index 0000000..04267b1 --- /dev/null +++ b/integration-tests/fixtures/sbt-19x/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.9.9 diff --git a/integration-tests/fixtures/sbt-19x/project/plugins.sbt b/integration-tests/fixtures/sbt-19x/project/plugins.sbt new file mode 100644 index 0000000..530fe1a --- /dev/null +++ b/integration-tests/fixtures/sbt-19x/project/plugins.sbt @@ -0,0 +1,3 @@ +// CI fixture: verifies the plugin loads and runs on sbt 1.9.x (the 3-arg +// Command.process overload used up to v2.4.0 only exists in sbt >= 1.10.0). +addSbtPlugin("io.github.moranaapps" % "jacoco-method-filter-sbt" % "2.4.0") diff --git a/integration-tests/fixtures/sbt-19x/src/main/scala/example/Calculator.scala b/integration-tests/fixtures/sbt-19x/src/main/scala/example/Calculator.scala new file mode 100644 index 0000000..d047b13 --- /dev/null +++ b/integration-tests/fixtures/sbt-19x/src/main/scala/example/Calculator.scala @@ -0,0 +1,14 @@ +package example + +class Calculator { + def add(a: Int, b: Int): Int = a + b + + def subtract(a: Int, b: Int): Int = a - b + + def multiply(a: Int, b: Int): Int = a * b + + def divide(a: Int, b: Int): Int = { + require(b != 0, "Cannot divide by zero") + a / b + } +} diff --git a/integration-tests/fixtures/sbt-19x/src/test/scala/example/CalculatorTest.scala b/integration-tests/fixtures/sbt-19x/src/test/scala/example/CalculatorTest.scala new file mode 100644 index 0000000..0d576b0 --- /dev/null +++ b/integration-tests/fixtures/sbt-19x/src/test/scala/example/CalculatorTest.scala @@ -0,0 +1,29 @@ +package example + +import org.scalatest.funsuite.AnyFunSuite + +class CalculatorTest extends AnyFunSuite { + val calc = new Calculator + + test("addition") { + assert(calc.add(2, 3) === 5) + } + + test("subtraction") { + assert(calc.subtract(5, 3) === 2) + } + + test("multiplication") { + assert(calc.multiply(3, 4) === 12) + } + + test("division") { + assert(calc.divide(12, 3) === 4) + } + + test("division by zero throws exception") { + intercept[IllegalArgumentException] { + calc.divide(5, 0) + } + } +} diff --git a/integration-tests/test-sbt-19x.sh b/integration-tests/test-sbt-19x.sh new file mode 100644 index 0000000..001e6e5 --- /dev/null +++ b/integration-tests/test-sbt-19x.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# --------------------------------------------------------------------------- +# Test: sbt 1.9.x compatibility (regression guard for issue #76) +# +# v2.4.0 of the plugin used the 3-arg `Command.process(String, State, onParseError)` +# overload, which only exists in sbt >= 1.10.0. On sbt 1.9.x, `jacocoReportAll` +# (and `jacocoCleanAll`) failed with: +# java.lang.NoSuchMethodError: sbt.Command$.process(...) +# +# This test pins a project to sbt 1.9.9 and runs the full jacoco flow; the +# `jacocoReportAll` step is what invokes `Command.process`, so a regression to a +# newer-than-1.9 sbt API makes `run_cmd` fail here. +# +# Prerequisite: sbt plugin published locally. +# --------------------------------------------------------------------------- +source "$(dirname "$0")/helpers.sh" + +TEST_NAME="sbt-19x-compat" +info "Running: $TEST_NAME" + +# Self-contained fixture (own src + rules), pinned to sbt.version=1.9.9. +cp -R "$REPO_ROOT/integration-tests/fixtures/sbt-19x" "$WORK_DIR/project" +cd "$WORK_DIR/project" + +# ── 1. Confirm the launcher really uses sbt 1.9.x ────────────────────────── +SBT_VERSION_OUT="$(sbt -Dsbt.supershell=false --no-colors sbtVersion 2>&1 | tail -n 5)" +echo "$SBT_VERSION_OUT" +echo "$SBT_VERSION_OUT" | grep -Eq '1\.9\.[0-9]+' \ + || fail "$TEST_NAME — expected sbt 1.9.x, got:\n$SBT_VERSION_OUT" + +pass "$TEST_NAME — running on sbt 1.9.x" + +# ── 2. Plain test (no filtering) ────────────────────────────────────────── +run_cmd "$TEST_NAME — sbt clean test (no filtering)" sbt clean test + +pass "$TEST_NAME — tests pass without filtering" + +# ── 3. Full jacoco flow (jacocoReportAll invokes Command.process) ───────── +# The critical step: it must NOT fail with NoSuchMethodError on sbt 1.9.x. +run_cmd "$TEST_NAME — sbt jacoco (with filtering on sbt 1.9.x)" sbt jacoco + +REPORT_DIR="target/scala-2.12/jacoco-report" +assert_dir_not_empty "$REPORT_DIR" \ + "$TEST_NAME — JaCoCo report directory exists and is not empty" + +assert_file_exists "$REPORT_DIR/index.html" \ + "$TEST_NAME — HTML report generated" + +assert_file_exists "$REPORT_DIR/jacoco.xml" \ + "$TEST_NAME — XML report generated" + +assert_file_exists "$REPORT_DIR/jacoco.csv" \ + "$TEST_NAME — CSV report generated" + +pass "$TEST_NAME — coverage with filtering on sbt 1.9.x" From 2309a80ca9ef8fb23246611534d7f8a65f4404fd Mon Sep 17 00:00:00 2001 From: miroslavpojer Date: Tue, 1 Sep 2026 16:12:59 +0200 Subject: [PATCH 3/3] Fix bug in test. --- integration-tests/helpers.sh | 7 ++++++- integration-tests/test-sbt-19x.sh | 22 +++++++++++----------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/integration-tests/helpers.sh b/integration-tests/helpers.sh index 2e1991b..1c6f797 100755 --- a/integration-tests/helpers.sh +++ b/integration-tests/helpers.sh @@ -23,10 +23,14 @@ pass() { echo -e "${GREEN}PASS${NC}: $1"; } fail() { echo -e "${RED}FAIL${NC}: $1"; exit 1; } info() { echo -e "${YELLOW}INFO${NC}: $1"; } +# Path of the log file written by the most recent run_cmd call. +LAST_CMD_LOG="" + # --------------------------------------------------------------------------- # run_cmd