fix: add --configure-on-demand to all Gradle commands

Gradle evaluates all project configurations during the configuration
phase, even when only one module is targeted. Multi-module projects with
diverse toolchain requirements (e.g., OpenRewrite's rewrite-gradle needs
JDK 8) fail when an unrelated module's toolchain isn't available.

Adds --configure-on-demand to all 8 Gradle command construction sites
so Gradle only configures projects needed for the requested task.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Mohamed Ashraf 2026-04-10 21:46:42 +00:00
parent 5ee642e35e
commit a7371b55ca
2 changed files with 92 additions and 8 deletions

View file

@ -533,7 +533,15 @@ class GradleStrategy(BuildToolStrategy):
logger.error("Gradle not found — cannot pre-install multi-module dependencies")
return False
cmd = [gradle, f":{test_module}:testClasses", "-x", "test", "--build-cache", "--no-daemon"]
cmd = [
gradle,
f":{test_module}:testClasses",
"-x",
"test",
"--build-cache",
"--no-daemon",
"--configure-on-demand",
]
cmd.extend(["--init-script", _get_skip_validation_init_script()])
logger.info("Pre-installing multi-module dependencies: %s (module: %s)", build_root, test_module)
@ -568,9 +576,9 @@ class GradleStrategy(BuildToolStrategy):
return subprocess.CompletedProcess(args=["gradle"], returncode=-1, stdout="", stderr="Gradle not found")
if test_module:
cmd = [gradle, f":{test_module}:testClasses", "--no-daemon"]
cmd = [gradle, f":{test_module}:testClasses", "--no-daemon", "--configure-on-demand"]
else:
cmd = [gradle, "testClasses", "--no-daemon"]
cmd = [gradle, "testClasses", "--no-daemon", "--configure-on-demand"]
cmd.extend(["--init-script", _get_skip_validation_init_script()])
logger.debug("Compiling tests: %s in %s", " ".join(cmd), build_root)
@ -592,9 +600,9 @@ class GradleStrategy(BuildToolStrategy):
return subprocess.CompletedProcess(args=["gradle"], returncode=-1, stdout="", stderr="Gradle not found")
if test_module:
cmd = [gradle, f":{test_module}:classes", "--no-daemon"]
cmd = [gradle, f":{test_module}:classes", "--no-daemon", "--configure-on-demand"]
else:
cmd = [gradle, "classes", "--no-daemon"]
cmd = [gradle, "classes", "--no-daemon", "--configure-on-demand"]
cmd.extend(["--init-script", _get_skip_validation_init_script()])
logger.debug("Compiling source only: %s in %s", " ".join(cmd), build_root)
@ -638,7 +646,7 @@ class GradleStrategy(BuildToolStrategy):
else:
task = "codeflashPrintClasspath"
cmd = [gradle, "--init-script", init_script_path, task, "-q", "--no-daemon"]
cmd = [gradle, "--init-script", init_script_path, task, "-q", "--no-daemon", "--configure-on-demand"]
logger.debug("Getting classpath: %s", " ".join(cmd))
@ -789,7 +797,7 @@ class GradleStrategy(BuildToolStrategy):
with os.fdopen(init_fd, "w", encoding="utf-8") as f:
f.write(init_script_content)
cmd = [gradle, task, "--no-daemon", "--rerun", "--init-script", init_path]
cmd = [gradle, task, "--no-daemon", "--rerun", "--configure-on-demand", "--init-script", init_path]
cmd.extend(["--init-script", _get_skip_validation_init_script()])
for class_filter in test_filter.split(","):
@ -1044,7 +1052,7 @@ class GradleStrategy(BuildToolStrategy):
raise ValueError(msg)
gradle = self.find_executable(project_root) or "gradle"
cmd = [gradle, "test", "--no-daemon"]
cmd = [gradle, "test", "--no-daemon", "--configure-on-demand"]
if test_classes:
for cls in test_classes:
cmd.extend(["--tests", cls])

View file

@ -0,0 +1,76 @@
from __future__ import annotations
from typing import TYPE_CHECKING
from unittest.mock import MagicMock, patch
from codeflash.languages.java.gradle_strategy import GradleStrategy
if TYPE_CHECKING:
from pathlib import Path
COD_FLAG = "--configure-on-demand"
MOCK_TARGET = "codeflash.languages.java.test_runner._run_cmd_kill_pg_on_timeout"
class TestConfigureOnDemand:
def test_compile_tests_includes_configure_on_demand(self, tmp_path: Path) -> None:
strategy = GradleStrategy()
with patch.object(strategy, "find_executable", return_value="gradlew"), patch(MOCK_TARGET) as mock_run:
mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
strategy.compile_tests(tmp_path, {}, test_module=None)
cmd = mock_run.call_args[0][0]
assert COD_FLAG in cmd
def test_compile_tests_multimodule_includes_configure_on_demand(self, tmp_path: Path) -> None:
strategy = GradleStrategy()
with patch.object(strategy, "find_executable", return_value="gradlew"), patch(MOCK_TARGET) as mock_run:
mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
strategy.compile_tests(tmp_path, {}, test_module="core")
cmd = mock_run.call_args[0][0]
assert COD_FLAG in cmd
assert ":core:testClasses" in cmd
def test_compile_source_only_includes_configure_on_demand(self, tmp_path: Path) -> None:
strategy = GradleStrategy()
with patch.object(strategy, "find_executable", return_value="gradlew"), patch(MOCK_TARGET) as mock_run:
mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
strategy.compile_source_only(tmp_path, {}, test_module=None)
cmd = mock_run.call_args[0][0]
assert COD_FLAG in cmd
def test_get_test_run_command_includes_configure_on_demand(self, tmp_path: Path) -> None:
strategy = GradleStrategy()
with patch.object(strategy, "find_executable", return_value="gradlew"):
cmd = strategy.get_test_run_command(tmp_path)
assert COD_FLAG in cmd
def test_install_multi_module_deps_includes_configure_on_demand(self, tmp_path: Path) -> None:
strategy = GradleStrategy()
with (
patch.object(strategy, "find_executable", return_value="gradlew"),
patch(MOCK_TARGET) as mock_run,
patch("codeflash.languages.java.gradle_strategy._multimodule_deps_installed", set()),
):
mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
strategy.install_multi_module_deps(tmp_path, test_module="core", env={})
cmd = mock_run.call_args[0][0]
assert COD_FLAG in cmd
assert ":core:testClasses" in cmd
def test_run_tests_via_build_tool_includes_configure_on_demand(self, tmp_path: Path) -> None:
strategy = GradleStrategy()
reports_dir = tmp_path / "build" / "test-results" / "test"
reports_dir.mkdir(parents=True, exist_ok=True)
with patch.object(strategy, "find_executable", return_value="gradlew"), patch(MOCK_TARGET) as mock_run:
mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
strategy.run_tests_via_build_tool(
build_root=tmp_path,
test_paths=["com.example.TestFoo"],
env={},
timeout=60,
mode="behavior",
test_module=None,
)
cmd = mock_run.call_args[0][0]
assert COD_FLAG in cmd