mirror of
https://github.com/codeflash-ai/codeflash.git
synced 2026-05-04 18:25:17 +00:00
refactor: replace find_gradle_executable and find_maven_executable with find_executable method in Maven and Gradle strategies
This commit is contained in:
parent
30fa5cef0d
commit
1ec829daff
11 changed files with 81 additions and 120 deletions
|
|
@ -11,8 +11,6 @@ from codeflash.languages.java.build_tools import (
|
||||||
JavaProjectInfo,
|
JavaProjectInfo,
|
||||||
MavenTestResult,
|
MavenTestResult,
|
||||||
detect_build_tool,
|
detect_build_tool,
|
||||||
find_gradle_executable,
|
|
||||||
find_maven_executable,
|
|
||||||
find_source_root,
|
find_source_root,
|
||||||
find_test_root,
|
find_test_root,
|
||||||
get_project_info,
|
get_project_info,
|
||||||
|
|
@ -145,10 +143,8 @@ __all__ = [
|
||||||
"extract_code_context",
|
"extract_code_context",
|
||||||
"extract_function_source",
|
"extract_function_source",
|
||||||
"extract_read_only_context",
|
"extract_read_only_context",
|
||||||
"find_gradle_executable",
|
|
||||||
"find_helper_files",
|
"find_helper_files",
|
||||||
"find_helper_functions",
|
"find_helper_functions",
|
||||||
"find_maven_executable",
|
|
||||||
"find_source_root",
|
"find_source_root",
|
||||||
"find_test_root",
|
"find_test_root",
|
||||||
"find_tests_for_function",
|
"find_tests_for_function",
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,11 @@ class BuildToolStrategy(ABC):
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def find_executable(self, build_root: Path) -> str | None:
|
||||||
|
"""Find the build tool executable, searching up parent directories if needed."""
|
||||||
|
...
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def ensure_runtime(self, build_root: Path, test_module: str | None) -> bool:
|
def ensure_runtime(self, build_root: Path, test_module: str | None) -> bool:
|
||||||
"""Install codeflash-runtime JAR and register it as a project dependency."""
|
"""Install codeflash-runtime JAR and register it as a project dependency."""
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,10 @@ This module provides functionality to detect and work with Java build tools
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import shutil
|
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from pathlib import Path
|
from pathlib import Path # noqa: TC003 — used at runtime
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -289,72 +288,6 @@ def _get_gradle_project_info(project_root: Path) -> JavaProjectInfo | None:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def find_maven_executable(project_root: Path | None = None) -> str | None:
|
|
||||||
"""Find the Maven executable.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Path to mvn executable, or None if not found.
|
|
||||||
|
|
||||||
"""
|
|
||||||
# Check for Maven wrapper in project root first
|
|
||||||
if project_root is not None:
|
|
||||||
mvnw_path = project_root / "mvnw"
|
|
||||||
if mvnw_path.exists():
|
|
||||||
return str(mvnw_path)
|
|
||||||
mvnw_cmd_path = project_root / "mvnw.cmd"
|
|
||||||
if mvnw_cmd_path.exists():
|
|
||||||
return str(mvnw_cmd_path)
|
|
||||||
|
|
||||||
# Check for Maven wrapper in current directory
|
|
||||||
if Path("mvnw").exists():
|
|
||||||
return "./mvnw"
|
|
||||||
if Path("mvnw.cmd").exists():
|
|
||||||
return "mvnw.cmd"
|
|
||||||
|
|
||||||
# Check system Maven
|
|
||||||
mvn_path = shutil.which("mvn")
|
|
||||||
if mvn_path:
|
|
||||||
return mvn_path
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def find_gradle_executable(project_root: Path | None = None) -> str | None:
|
|
||||||
"""Find the Gradle executable.
|
|
||||||
|
|
||||||
Checks for Gradle wrapper in the project root and current directory,
|
|
||||||
then falls back to system Gradle.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
project_root: Optional project root directory to search for Gradle wrapper.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Path to gradle executable, or None if not found.
|
|
||||||
|
|
||||||
"""
|
|
||||||
# Check for Gradle wrapper in project root first
|
|
||||||
if project_root is not None:
|
|
||||||
gradlew_path = project_root / "gradlew"
|
|
||||||
if gradlew_path.exists():
|
|
||||||
return str(gradlew_path)
|
|
||||||
gradlew_bat_path = project_root / "gradlew.bat"
|
|
||||||
if gradlew_bat_path.exists():
|
|
||||||
return str(gradlew_bat_path)
|
|
||||||
|
|
||||||
# Check for Gradle wrapper in current directory
|
|
||||||
if Path("gradlew").exists():
|
|
||||||
return "./gradlew"
|
|
||||||
if Path("gradlew.bat").exists():
|
|
||||||
return "gradlew.bat"
|
|
||||||
|
|
||||||
# Check system Gradle
|
|
||||||
gradle_path = shutil.which("gradle")
|
|
||||||
if gradle_path:
|
|
||||||
return gradle_path
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_surefire_reports(surefire_dir: Path) -> tuple[int, int, int, int]:
|
def _parse_surefire_reports(surefire_dir: Path) -> tuple[int, int, int, int]:
|
||||||
"""Parse Surefire XML reports to get test counts.
|
"""Parse Surefire XML reports to get test counts.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from codeflash.languages.java.build_tool_strategy import BuildToolStrategy
|
from codeflash.languages.java.build_tool_strategy import BuildToolStrategy
|
||||||
from codeflash.languages.java.build_tools import find_gradle_executable
|
|
||||||
|
|
||||||
_BUILD = "build"
|
_BUILD = "build"
|
||||||
|
|
||||||
|
|
@ -128,6 +127,24 @@ class GradleStrategy(BuildToolStrategy):
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
return "Gradle"
|
return "Gradle"
|
||||||
|
|
||||||
|
def find_executable(self, build_root: Path) -> str | None:
|
||||||
|
# Walk up from build_root to find gradlew — for multi-module projects
|
||||||
|
# the wrapper lives at the repo root, which may be a parent of build_root.
|
||||||
|
current = build_root.resolve()
|
||||||
|
while True:
|
||||||
|
gradlew_path = current / "gradlew"
|
||||||
|
if gradlew_path.exists():
|
||||||
|
return str(gradlew_path)
|
||||||
|
gradlew_bat_path = current / "gradlew.bat"
|
||||||
|
if gradlew_bat_path.exists():
|
||||||
|
return str(gradlew_bat_path)
|
||||||
|
parent = current.parent
|
||||||
|
if parent == current:
|
||||||
|
break
|
||||||
|
current = parent
|
||||||
|
# Fall back to system Gradle
|
||||||
|
return shutil.which("gradle")
|
||||||
|
|
||||||
def ensure_runtime(self, build_root: Path, test_module: str | None) -> bool:
|
def ensure_runtime(self, build_root: Path, test_module: str | None) -> bool:
|
||||||
runtime_jar = self.find_runtime_jar()
|
runtime_jar = self.find_runtime_jar()
|
||||||
if runtime_jar is None:
|
if runtime_jar is None:
|
||||||
|
|
@ -169,7 +186,7 @@ class GradleStrategy(BuildToolStrategy):
|
||||||
logger.debug("Multi-module deps already installed for %s:%s, skipping", build_root, test_module)
|
logger.debug("Multi-module deps already installed for %s:%s, skipping", build_root, test_module)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
gradle = find_gradle_executable(build_root)
|
gradle = self.find_executable(build_root)
|
||||||
if not gradle:
|
if not gradle:
|
||||||
logger.error("Gradle not found — cannot pre-install multi-module dependencies")
|
logger.error("Gradle not found — cannot pre-install multi-module dependencies")
|
||||||
return False
|
return False
|
||||||
|
|
@ -202,7 +219,7 @@ class GradleStrategy(BuildToolStrategy):
|
||||||
) -> subprocess.CompletedProcess[str]:
|
) -> subprocess.CompletedProcess[str]:
|
||||||
from codeflash.languages.java.test_runner import _run_cmd_kill_pg_on_timeout
|
from codeflash.languages.java.test_runner import _run_cmd_kill_pg_on_timeout
|
||||||
|
|
||||||
gradle = find_gradle_executable(build_root)
|
gradle = self.find_executable(build_root)
|
||||||
if not gradle:
|
if not gradle:
|
||||||
logger.error("Gradle not found")
|
logger.error("Gradle not found")
|
||||||
return subprocess.CompletedProcess(args=["gradle"], returncode=-1, stdout="", stderr="Gradle not found")
|
return subprocess.CompletedProcess(args=["gradle"], returncode=-1, stdout="", stderr="Gradle not found")
|
||||||
|
|
@ -238,7 +255,7 @@ class GradleStrategy(BuildToolStrategy):
|
||||||
) -> str | None:
|
) -> str | None:
|
||||||
from codeflash.languages.java.test_runner import _find_junit_console_standalone, _run_cmd_kill_pg_on_timeout
|
from codeflash.languages.java.test_runner import _find_junit_console_standalone, _run_cmd_kill_pg_on_timeout
|
||||||
|
|
||||||
gradle = find_gradle_executable(build_root)
|
gradle = self.find_executable(build_root)
|
||||||
if not gradle:
|
if not gradle:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
@ -339,7 +356,7 @@ class GradleStrategy(BuildToolStrategy):
|
||||||
) -> subprocess.CompletedProcess[str]:
|
) -> subprocess.CompletedProcess[str]:
|
||||||
from codeflash.languages.java.test_runner import _build_test_filter, _run_cmd_kill_pg_on_timeout
|
from codeflash.languages.java.test_runner import _build_test_filter, _run_cmd_kill_pg_on_timeout
|
||||||
|
|
||||||
gradle = find_gradle_executable(build_root)
|
gradle = self.find_executable(build_root)
|
||||||
if not gradle:
|
if not gradle:
|
||||||
logger.error("Gradle not found")
|
logger.error("Gradle not found")
|
||||||
return subprocess.CompletedProcess(args=["gradle"], returncode=-1, stdout="", stderr="Gradle not found")
|
return subprocess.CompletedProcess(args=["gradle"], returncode=-1, stdout="", stderr="Gradle not found")
|
||||||
|
|
@ -610,7 +627,7 @@ class GradleStrategy(BuildToolStrategy):
|
||||||
msg = f"Invalid test class name: '{test_class}'. Test names must follow Java identifier rules."
|
msg = f"Invalid test class name: '{test_class}'. Test names must follow Java identifier rules."
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
gradle = find_gradle_executable(project_root) or "gradle"
|
gradle = self.find_executable(project_root) or "gradle"
|
||||||
cmd = [gradle, "test", "--no-daemon"]
|
cmd = [gradle, "test", "--no-daemon"]
|
||||||
if test_classes:
|
if test_classes:
|
||||||
for cls in test_classes:
|
for cls in test_classes:
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,13 @@ from __future__ import annotations
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from codeflash.languages.java.build_tool_strategy import BuildToolStrategy
|
from codeflash.languages.java.build_tool_strategy import BuildToolStrategy
|
||||||
from codeflash.languages.java.build_tools import find_maven_executable
|
|
||||||
|
|
||||||
_TARGET = "target"
|
_TARGET = "target"
|
||||||
|
|
||||||
|
|
@ -55,8 +55,9 @@ def _safe_parse_xml(file_path: Path) -> ET.ElementTree:
|
||||||
return ET.ElementTree(root)
|
return ET.ElementTree(root)
|
||||||
|
|
||||||
|
|
||||||
def install_codeflash_runtime(project_root: Path, runtime_jar_path: Path) -> bool:
|
def install_codeflash_runtime(project_root: Path, runtime_jar_path: Path, mvn: str | None = None) -> bool:
|
||||||
mvn = find_maven_executable()
|
if not mvn:
|
||||||
|
mvn = shutil.which("mvn")
|
||||||
if not mvn:
|
if not mvn:
|
||||||
logger.error("Maven not found")
|
logger.error("Maven not found")
|
||||||
return False
|
return False
|
||||||
|
|
@ -314,6 +315,19 @@ class MavenStrategy(BuildToolStrategy):
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
return "Maven"
|
return "Maven"
|
||||||
|
|
||||||
|
def find_executable(self, build_root: Path) -> str | None:
|
||||||
|
mvnw_path = build_root / "mvnw"
|
||||||
|
if mvnw_path.exists():
|
||||||
|
return str(mvnw_path)
|
||||||
|
mvnw_cmd_path = build_root / "mvnw.cmd"
|
||||||
|
if mvnw_cmd_path.exists():
|
||||||
|
return str(mvnw_cmd_path)
|
||||||
|
if Path("mvnw").exists():
|
||||||
|
return "./mvnw"
|
||||||
|
if Path("mvnw.cmd").exists():
|
||||||
|
return "mvnw.cmd"
|
||||||
|
return shutil.which("mvn")
|
||||||
|
|
||||||
def find_runtime_jar(self) -> Path | None:
|
def find_runtime_jar(self) -> Path | None:
|
||||||
if self._M2_JAR.exists():
|
if self._M2_JAR.exists():
|
||||||
return self._M2_JAR
|
return self._M2_JAR
|
||||||
|
|
@ -327,7 +341,7 @@ class MavenStrategy(BuildToolStrategy):
|
||||||
|
|
||||||
if not self._M2_JAR.exists():
|
if not self._M2_JAR.exists():
|
||||||
logger.info("Installing codeflash-runtime JAR to local Maven repository")
|
logger.info("Installing codeflash-runtime JAR to local Maven repository")
|
||||||
if not install_codeflash_runtime(build_root, runtime_jar):
|
if not install_codeflash_runtime(build_root, runtime_jar, mvn=self.find_executable(build_root)):
|
||||||
logger.error("Failed to install codeflash-runtime to local Maven repository")
|
logger.error("Failed to install codeflash-runtime to local Maven repository")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
@ -357,7 +371,7 @@ class MavenStrategy(BuildToolStrategy):
|
||||||
logger.debug("Multi-module deps already installed for %s:%s, skipping", build_root, test_module)
|
logger.debug("Multi-module deps already installed for %s:%s, skipping", build_root, test_module)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
mvn = find_maven_executable()
|
mvn = self.find_executable(build_root)
|
||||||
if not mvn:
|
if not mvn:
|
||||||
logger.error("Maven not found — cannot pre-install multi-module dependencies")
|
logger.error("Maven not found — cannot pre-install multi-module dependencies")
|
||||||
return False
|
return False
|
||||||
|
|
@ -391,7 +405,7 @@ class MavenStrategy(BuildToolStrategy):
|
||||||
) -> subprocess.CompletedProcess[str]:
|
) -> subprocess.CompletedProcess[str]:
|
||||||
from codeflash.languages.java.test_runner import _run_cmd_kill_pg_on_timeout
|
from codeflash.languages.java.test_runner import _run_cmd_kill_pg_on_timeout
|
||||||
|
|
||||||
mvn = find_maven_executable()
|
mvn = self.find_executable(build_root)
|
||||||
if not mvn:
|
if not mvn:
|
||||||
logger.error("Maven not found")
|
logger.error("Maven not found")
|
||||||
return subprocess.CompletedProcess(args=["mvn"], returncode=-1, stdout="", stderr="Maven not found")
|
return subprocess.CompletedProcess(args=["mvn"], returncode=-1, stdout="", stderr="Maven not found")
|
||||||
|
|
@ -428,7 +442,7 @@ class MavenStrategy(BuildToolStrategy):
|
||||||
) -> str | None:
|
) -> str | None:
|
||||||
from codeflash.languages.java.test_runner import _find_junit_console_standalone, _run_cmd_kill_pg_on_timeout
|
from codeflash.languages.java.test_runner import _find_junit_console_standalone, _run_cmd_kill_pg_on_timeout
|
||||||
|
|
||||||
mvn = find_maven_executable()
|
mvn = self.find_executable(build_root)
|
||||||
if not mvn:
|
if not mvn:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
@ -517,7 +531,7 @@ class MavenStrategy(BuildToolStrategy):
|
||||||
_validate_test_filter,
|
_validate_test_filter,
|
||||||
)
|
)
|
||||||
|
|
||||||
mvn = find_maven_executable()
|
mvn = self.find_executable(build_root)
|
||||||
if not mvn:
|
if not mvn:
|
||||||
logger.error("Maven not found")
|
logger.error("Maven not found")
|
||||||
return subprocess.CompletedProcess(args=["mvn"], returncode=-1, stdout="", stderr="Maven not found")
|
return subprocess.CompletedProcess(args=["mvn"], returncode=-1, stdout="", stderr="Maven not found")
|
||||||
|
|
@ -749,7 +763,7 @@ class MavenStrategy(BuildToolStrategy):
|
||||||
msg = f"Invalid test class name: '{test_class}'. Test names must follow Java identifier rules."
|
msg = f"Invalid test class name: '{test_class}'. Test names must follow Java identifier rules."
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
mvn = find_maven_executable(project_root) or "mvn"
|
mvn = self.find_executable(project_root) or "mvn"
|
||||||
cmd = [mvn, "test", "-B"]
|
cmd = [mvn, "test", "-B"]
|
||||||
if test_classes:
|
if test_classes:
|
||||||
cmd.append(f"-Dtest={','.join(test_classes)}")
|
cmd.append(f"-Dtest={','.join(test_classes)}")
|
||||||
|
|
|
||||||
|
|
@ -767,11 +767,9 @@ def _find_junit_console_standalone() -> Path | None:
|
||||||
This JAR contains ConsoleLauncher which is required for direct JVM test execution
|
This JAR contains ConsoleLauncher which is required for direct JVM test execution
|
||||||
with JUnit 5.
|
with JUnit 5.
|
||||||
"""
|
"""
|
||||||
from codeflash.languages.java.build_tools import find_maven_executable
|
|
||||||
|
|
||||||
m2_base = Path.home() / ".m2" / "repository" / "org" / "junit" / "platform" / "junit-platform-console-standalone"
|
m2_base = Path.home() / ".m2" / "repository" / "org" / "junit" / "platform" / "junit-platform-console-standalone"
|
||||||
if not m2_base.exists():
|
if not m2_base.exists():
|
||||||
mvn = find_maven_executable()
|
mvn = shutil.which("mvn")
|
||||||
if mvn:
|
if mvn:
|
||||||
logger.debug("Console standalone not found in cache, downloading via Maven")
|
logger.debug("Console standalone not found in cache, downloading via Maven")
|
||||||
with contextlib.suppress(subprocess.TimeoutExpired, Exception):
|
with contextlib.suppress(subprocess.TimeoutExpired, Exception):
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ def test_skipped_for_single_module(strategy):
|
||||||
assert len(_multimodule_deps_installed) == 0
|
assert len(_multimodule_deps_installed) == 0
|
||||||
|
|
||||||
|
|
||||||
@patch("codeflash.languages.java.maven_strategy.find_maven_executable", return_value="mvn")
|
@patch.object(MavenStrategy, "find_executable", return_value="mvn")
|
||||||
@patch("codeflash.languages.java.test_runner._run_cmd_kill_pg_on_timeout")
|
@patch("codeflash.languages.java.test_runner._run_cmd_kill_pg_on_timeout")
|
||||||
def test_runs_install_command_with_correct_args(mock_run, mock_mvn, strategy):
|
def test_runs_install_command_with_correct_args(mock_run, mock_mvn, strategy):
|
||||||
"""Should run mvn install -DskipTests -pl <module> -am with validation skip flags."""
|
"""Should run mvn install -DskipTests -pl <module> -am with validation skip flags."""
|
||||||
|
|
@ -53,7 +53,7 @@ def test_runs_install_command_with_correct_args(mock_run, mock_mvn, strategy):
|
||||||
assert mock_run.call_args[1]["cwd"] == root
|
assert mock_run.call_args[1]["cwd"] == root
|
||||||
|
|
||||||
|
|
||||||
@patch("codeflash.languages.java.maven_strategy.find_maven_executable", return_value="mvn")
|
@patch.object(MavenStrategy, "find_executable", return_value="mvn")
|
||||||
@patch("codeflash.languages.java.test_runner._run_cmd_kill_pg_on_timeout")
|
@patch("codeflash.languages.java.test_runner._run_cmd_kill_pg_on_timeout")
|
||||||
def test_caches_and_does_not_rerun(mock_run, mock_mvn, strategy):
|
def test_caches_and_does_not_rerun(mock_run, mock_mvn, strategy):
|
||||||
"""Second call with same (root, module) should be cached — no Maven invocation."""
|
"""Second call with same (root, module) should be cached — no Maven invocation."""
|
||||||
|
|
@ -68,7 +68,7 @@ def test_caches_and_does_not_rerun(mock_run, mock_mvn, strategy):
|
||||||
assert mock_run.call_count == 1
|
assert mock_run.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
@patch("codeflash.languages.java.maven_strategy.find_maven_executable", return_value="mvn")
|
@patch.object(MavenStrategy, "find_executable", return_value="mvn")
|
||||||
@patch("codeflash.languages.java.test_runner._run_cmd_kill_pg_on_timeout")
|
@patch("codeflash.languages.java.test_runner._run_cmd_kill_pg_on_timeout")
|
||||||
def test_different_modules_not_cached(mock_run, mock_mvn, strategy):
|
def test_different_modules_not_cached(mock_run, mock_mvn, strategy):
|
||||||
"""Different test modules should each trigger their own install."""
|
"""Different test modules should each trigger their own install."""
|
||||||
|
|
@ -80,7 +80,7 @@ def test_different_modules_not_cached(mock_run, mock_mvn, strategy):
|
||||||
assert mock_run.call_count == 2
|
assert mock_run.call_count == 2
|
||||||
|
|
||||||
|
|
||||||
@patch("codeflash.languages.java.maven_strategy.find_maven_executable", return_value="mvn")
|
@patch.object(MavenStrategy, "find_executable", return_value="mvn")
|
||||||
@patch("codeflash.languages.java.test_runner._run_cmd_kill_pg_on_timeout")
|
@patch("codeflash.languages.java.test_runner._run_cmd_kill_pg_on_timeout")
|
||||||
def test_returns_false_on_maven_failure(mock_run, mock_mvn, strategy):
|
def test_returns_false_on_maven_failure(mock_run, mock_mvn, strategy):
|
||||||
"""Non-zero exit code should return False and NOT cache."""
|
"""Non-zero exit code should return False and NOT cache."""
|
||||||
|
|
@ -92,7 +92,7 @@ def test_returns_false_on_maven_failure(mock_run, mock_mvn, strategy):
|
||||||
assert len(_multimodule_deps_installed) == 0
|
assert len(_multimodule_deps_installed) == 0
|
||||||
|
|
||||||
|
|
||||||
@patch("codeflash.languages.java.maven_strategy.find_maven_executable", return_value=None)
|
@patch.object(MavenStrategy, "find_executable", return_value=None)
|
||||||
def test_returns_false_when_maven_not_found(mock_mvn, strategy):
|
def test_returns_false_when_maven_not_found(mock_mvn, strategy):
|
||||||
"""Should return False if Maven executable is not found."""
|
"""Should return False if Maven executable is not found."""
|
||||||
result = strategy.install_multi_module_deps(Path("/fake"), "module", {})
|
result = strategy.install_multi_module_deps(Path("/fake"), "module", {})
|
||||||
|
|
|
||||||
|
|
@ -69,9 +69,7 @@ def test_run_tests_via_build_tool_raises_on_empty_filter():
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
with patch("codeflash.languages.java.maven_strategy.find_maven_executable") as mock_maven:
|
with patch.object(MavenStrategy, "find_executable", return_value="mvn"):
|
||||||
mock_maven.return_value = "mvn"
|
|
||||||
|
|
||||||
with pytest.raises(ValueError, match="Test filter is EMPTY"):
|
with pytest.raises(ValueError, match="Test filter is EMPTY"):
|
||||||
strategy.run_tests_via_build_tool(
|
strategy.run_tests_via_build_tool(
|
||||||
project_root,
|
project_root,
|
||||||
|
|
@ -101,10 +99,9 @@ def test_run_tests_via_build_tool_succeeds_with_valid_filter():
|
||||||
)
|
)
|
||||||
|
|
||||||
with (
|
with (
|
||||||
patch("codeflash.languages.java.maven_strategy.find_maven_executable") as mock_maven,
|
patch.object(MavenStrategy, "find_executable", return_value="mvn"),
|
||||||
patch("codeflash.languages.java.test_runner._run_cmd_kill_pg_on_timeout") as mock_run,
|
patch("codeflash.languages.java.test_runner._run_cmd_kill_pg_on_timeout") as mock_run,
|
||||||
):
|
):
|
||||||
mock_maven.return_value = "mvn"
|
|
||||||
mock_run.return_value = subprocess.CompletedProcess(
|
mock_run.return_value = subprocess.CompletedProcess(
|
||||||
args=[], returncode=0, stdout="Tests run: 1, Failures: 0, Errors: 0, Skipped: 0", stderr=""
|
args=[], returncode=0, stdout="Tests run: 1, Failures: 0, Errors: 0, Skipped: 0", stderr=""
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,11 @@ from pathlib import Path
|
||||||
from codeflash.languages.java.build_tools import (
|
from codeflash.languages.java.build_tools import (
|
||||||
BuildTool,
|
BuildTool,
|
||||||
detect_build_tool,
|
detect_build_tool,
|
||||||
find_maven_executable,
|
|
||||||
find_source_root,
|
find_source_root,
|
||||||
find_test_root,
|
find_test_root,
|
||||||
get_project_info,
|
get_project_info,
|
||||||
)
|
)
|
||||||
from codeflash.languages.java.maven_strategy import add_codeflash_dependency
|
from codeflash.languages.java.maven_strategy import MavenStrategy, add_codeflash_dependency
|
||||||
from codeflash.languages.java.test_runner import _extract_modules_from_pom_content
|
from codeflash.languages.java.test_runner import _extract_modules_from_pom_content
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -175,8 +174,8 @@ class TestMavenExecutable:
|
||||||
|
|
||||||
def test_find_maven_executable_system(self):
|
def test_find_maven_executable_system(self):
|
||||||
"""Test finding system Maven."""
|
"""Test finding system Maven."""
|
||||||
# This test may pass or fail depending on whether Maven is installed
|
strategy = MavenStrategy()
|
||||||
mvn = find_maven_executable()
|
mvn = strategy.find_executable(Path("."))
|
||||||
# We can't assert it exists, just that the function doesn't crash
|
# We can't assert it exists, just that the function doesn't crash
|
||||||
if mvn:
|
if mvn:
|
||||||
assert "mvn" in mvn.lower() or "maven" in mvn.lower()
|
assert "mvn" in mvn.lower() or "maven" in mvn.lower()
|
||||||
|
|
@ -188,10 +187,8 @@ class TestMavenExecutable:
|
||||||
mvnw_path.write_text("#!/bin/bash\necho 'Maven Wrapper'")
|
mvnw_path.write_text("#!/bin/bash\necho 'Maven Wrapper'")
|
||||||
mvnw_path.chmod(0o755)
|
mvnw_path.chmod(0o755)
|
||||||
|
|
||||||
# Change to tmp_path
|
strategy = MavenStrategy()
|
||||||
monkeypatch.chdir(tmp_path)
|
mvn = strategy.find_executable(tmp_path)
|
||||||
|
|
||||||
mvn = find_maven_executable()
|
|
||||||
# Should find the wrapper
|
# Should find the wrapper
|
||||||
assert mvn is not None
|
assert mvn is not None
|
||||||
|
|
||||||
|
|
@ -377,24 +374,27 @@ class TestMavenProfiles:
|
||||||
|
|
||||||
|
|
||||||
class TestMavenExecutableWithProjectRoot:
|
class TestMavenExecutableWithProjectRoot:
|
||||||
"""Tests for find_maven_executable with project_root parameter."""
|
"""Tests for MavenStrategy.find_executable with project_root parameter."""
|
||||||
|
|
||||||
def test_find_wrapper_in_project_root(self, tmp_path):
|
def test_find_wrapper_in_project_root(self, tmp_path):
|
||||||
mvnw_path = tmp_path / "mvnw"
|
mvnw_path = tmp_path / "mvnw"
|
||||||
mvnw_path.write_text("#!/bin/bash\necho Maven Wrapper")
|
mvnw_path.write_text("#!/bin/bash\necho Maven Wrapper")
|
||||||
mvnw_path.chmod(0o755)
|
mvnw_path.chmod(0o755)
|
||||||
|
|
||||||
result = find_maven_executable(project_root=tmp_path)
|
strategy = MavenStrategy()
|
||||||
|
result = strategy.find_executable(tmp_path)
|
||||||
assert result is not None
|
assert result is not None
|
||||||
assert str(tmp_path / "mvnw") in result
|
assert str(tmp_path / "mvnw") in result
|
||||||
|
|
||||||
def test_fallback_to_cwd_when_no_project_root(self):
|
def test_fallback_to_cwd(self, tmp_path):
|
||||||
result = find_maven_executable()
|
strategy = MavenStrategy()
|
||||||
# Should not crash even without project_root
|
result = strategy.find_executable(tmp_path)
|
||||||
|
# Should not crash even with a dir that has no wrapper
|
||||||
|
|
||||||
def test_project_root_none_uses_cwd(self):
|
def test_with_nonexistent_wrapper(self, tmp_path):
|
||||||
result = find_maven_executable(project_root=None)
|
strategy = MavenStrategy()
|
||||||
# Should not crash
|
result = strategy.find_executable(tmp_path)
|
||||||
|
# Should not crash, may return system mvn or None
|
||||||
|
|
||||||
|
|
||||||
class TestCustomSourceDirectoryDetection:
|
class TestCustomSourceDirectoryDetection:
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ os.environ["CODEFLASH_API_KEY"] = "cf-test-key"
|
||||||
from codeflash.discovery.functions_to_optimize import FunctionToOptimize
|
from codeflash.discovery.functions_to_optimize import FunctionToOptimize
|
||||||
from codeflash.languages.base import Language
|
from codeflash.languages.base import Language
|
||||||
from codeflash.languages.current import set_current_language
|
from codeflash.languages.current import set_current_language
|
||||||
from codeflash.languages.java.build_tools import find_maven_executable
|
from codeflash.languages.java.maven_strategy import MavenStrategy
|
||||||
from codeflash.languages.java.discovery import discover_functions_from_source
|
from codeflash.languages.java.discovery import discover_functions_from_source
|
||||||
from codeflash.languages.java.instrumentation import (
|
from codeflash.languages.java.instrumentation import (
|
||||||
_add_behavior_instrumentation,
|
_add_behavior_instrumentation,
|
||||||
|
|
@ -1968,7 +1968,7 @@ public class AccentTest {
|
||||||
|
|
||||||
# Skip all E2E tests if Maven is not available
|
# Skip all E2E tests if Maven is not available
|
||||||
requires_maven = pytest.mark.skipif(
|
requires_maven = pytest.mark.skipif(
|
||||||
find_maven_executable() is None, reason="Maven not found - skipping execution tests"
|
MavenStrategy().find_executable(Path(".")) is None, reason="Maven not found - skipping execution tests"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,9 +90,10 @@ POM_CONTENT = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
|
||||||
def skip_if_maven_not_available():
|
def skip_if_maven_not_available():
|
||||||
from codeflash.languages.java.build_tools import find_maven_executable
|
from codeflash.languages.java.maven_strategy import MavenStrategy
|
||||||
|
|
||||||
|
if not MavenStrategy().find_executable(Path(".")):
|
||||||
|
|
||||||
if not find_maven_executable():
|
|
||||||
pytest.skip("Maven not available")
|
pytest.skip("Maven not available")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue