feat: zero-config Java projects + smart ReplayHelper for end-to-end optimization#1880
feat: zero-config Java projects + smart ReplayHelper for end-to-end optimization#1880misrasaurabh1 merged 30 commits intomainfrom
Conversation
…iles Java projects no longer need a standalone config file. Codeflash reads config from pom.xml <properties> or gradle.properties, and auto-detects source/test roots from build tool conventions. Changes: - Add parse_java_project_config() to read codeflash.* properties from pom.xml and gradle.properties - Add multi-module Maven scanning: parses each module's pom.xml for <sourceDirectory> and <testSourceDirectory>, picks module with most Java files as source root, identifies test modules by name - Route Java projects through build-file detection in config_parser.py before falling back to pyproject.toml - Detect Java language from pom.xml/build.gradle presence (no config needed) - Fix project_root for multi-module projects (was resolving to sub-module) - Fix JFR parser / separators (JVM uses com/example, normalized to com.example) - Fix graceful timeout (SIGTERM before SIGKILL for JFR dump + shutdown hooks) - Remove isRecording() check from TracingTransformer (was preventing class instrumentation for classes loaded during serialization) - Delete all codeflash.toml files from fixtures and code_to_optimize - Add 33 config detection tests - Update docs for zero-config Java setup Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replay tests call helper.replay() via reflection, not the target function directly. The behavior instrumentation can't wrap indirect calls and produces malformed output (code emitted outside class body) for large replay test files. For replay tests, just rename the class without adding instrumentation — JUnit pass/fail results verify correctness. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Detect test framework from project build config and generate replay tests with appropriate imports (org.junit.Test for JUnit 4, org.junit.jupiter.api.Test for JUnit 5). Fixes compilation failures on projects using JUnit 4 (like aerospike-client-java). Also passes test_framework through run_java_tracer to generate_replay_tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ay tests Use a global counter per method name across all descriptors to generate unique test method names. Previously, overloaded methods (same name, different descriptor) would generate duplicate replay_methodName_N methods, causing compilation errors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…on skip 10 new tests covering: - JUnit 5 replay test generation (imports, class visibility) - JUnit 4 replay test generation (imports, public methods, @afterclass) - Overloaded method handling (no duplicate test method names) - Instrumentation skip for replay tests (behavior + perf mode) - Regular tests still get instrumented normally Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…solution 13 new tests covering: - JFR class name normalization (/ to . conversion) - Package-based sample filtering - Addressable time calculation from JFR samples - Method ranking order and format - Graceful timeout (SIGTERM before SIGKILL) - Multi-module project root detection (Path not str) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The behavior instrumentation was producing malformed output for compact @test lines (annotation + method signature on same line, common in replay tests). The method signature collection loop would skip past the opening brace and consume subsequent methods' content. Fix: detect when the @test annotation line already contains { and treat it as both annotation and method signature, avoiding the separate signature search that was over-consuming lines. Reverted the instrumentation skip for replay tests — they now get properly instrumented for both behavior capture and performance timing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Claude finished @HeshamHM28's task in 4s —— View job PR Review SummaryPrek Checks✅ Mypy reports 19 errors across Code ReviewBinary file committed
|
| File | Coverage |
|---|---|
jfr_parser.py |
71% |
replay_test.py |
76% |
instrumentation.py |
61% |
tracer.py (java) |
33% |
maven_strategy.py |
9% (largely pre-existing) |
tracer.py at 33% is low but most uncovered code is subprocess orchestration (_run_java_with_graceful_timeout, JavaTracer.trace()) that is inherently difficult to unit test. The graceful timeout logic has dedicated tests in TestGracefulTimeout. Acceptable for now.
Last updated: 2026-04-01T20:13Z
ReplayHelper now reads CODEFLASH_MODE env var and produces the same output as the existing test instrumentation: - Behavior mode: captures return value via Kryo serialization, writes to SQLite (test_results table) for correctness comparison, prints start/end timing markers - Performance mode: runs inner loop for JIT warmup, prints timing markers for each iteration matching the expected format - No mode: just invokes the method (trace-only or manual testing) This achieves feature parity with the existing test instrumentation for replay tests, which call functions via reflection and can't be wrapped by text-level instrumentation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ay tests + speedups - Trigger on any codeflash/** or tests/** changes (not just java subset) - Validate replay test files are discovered per-function - Already validates: replay test generation, global discovery count, optimization success, and minimum speedup percentage Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The refactored Java project_root handling moved args.tests_root resolution after the project_root_from_module_root call, which passed a string instead of a Path. Restore the original order: resolve tests_root to Path first, then set test_project_root, then override both for Java multi-module projects. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use Path comparisons instead of forward-slash substring matching - Avoid parse_args() in test (reads stdin on Windows) — use Namespace directly Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use print(flush=True) instead of logging.info for subprocess output so CI logs show progress in real-time instead of buffering until completion. Also set PYTHONUNBUFFERED=1 for the subprocess. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…_write_gradle_properties Co-authored-by: Saurabh Misra <undefined@users.noreply.github.com>
…ions harder - Set jdk.ExecutionSample#period=1ms (default was 10ms) so JFR captures samples from shorter-running programs - Workload.main now runs 1000 rounds with larger inputs so JFR can capture method-level CPU samples (repeatString with O(n²) concat dominates ~75% of samples) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ove priority Replace xml.etree.ElementTree with text-based regex manipulation in _write_maven_properties() and _remove_java_build_config(). ElementTree destroys XML comments, mangles namespace declarations (ns0: prefixes), and reformats whitespace. The new approach reads/writes pom.xml as plain text, only touching codeflash.* property lines. Also extracts duplicated key_map to shared _MAVEN_KEY_MAP constant and aligns remove priority to check pom.xml first (matching write order). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Review & fix: pom.xml formatting preservation (3c63b60)Reviewed the PR changes and identified one genuine issue in the config writer. What was fixed
Additionally:
What was reviewed and left as-isConfirmed the following are intentional design decisions, not bugs:
Validation
|
…os (TODO-37) Java detection in parse_config_file() short-circuited before the existing depth-comparison logic, so a parent pom.xml would override a closer package.json or pyproject.toml. Now all config sources are detected first and the closest one to CWD wins. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…TODO-34, TODO-38) TODO-34: TracingClassVisitor hardcoded line number to 0 because ASM's visitMethod() doesn't provide line info. Added a pre-scan pass in TracingTransformer.instrumentClass() that collects first line numbers via visitLineNumber() before the instrumentation pass. TODO-38: Serialization timeouts/failures silently dropped captures with no visibility. Added AtomicInteger droppedCaptures counter and included it in flush() metadata output. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Changed detect_packages_from_source() from min(2, len) to min(3, len) so com.aerospike.client.util produces prefix com.aerospike.client instead of com.aerospike. This reduces instrumentation to the actual source package instead of the entire organization namespace. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
3 commits addressing the remaining open TODOs from the code review: 1.
|
…orepo subdirectory scanning Adapt find_all_config_files() after rebasing on java-config-redesign (PR #1880): - Java detected via pom.xml/build.gradle instead of codeflash.toml - Add subdirectory scan for monorepo language subprojects (java/, js/ etc.) - Extract _check_dir_for_configs() to eliminate duplicated detection logic - Fix --all flag in multi-language mode (module_root wasn't available during resolution) - Add Java project_root directory override in apply_language_config() - Update all tests to use build-tool detection mocks and directory-based Java paths - Add 5 new monorepo discovery tests (subdir Java, subdir JS, all-three, skip-hidden, root-wins) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Zero-config Java support (auto-detection from build files, codeflash.toml elimination) is handled separately in cf-java-zero-config-strategy. This commit strips those changes, keeping only bug fixes: - JFR parser, ReplayHelper, instrumentation, replay tests - Multi-module test root resolution - JUnit 4/5 test framework detection - add_help=False for optimize subparser Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Ubuntu seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. You have signed the CLA already but the status is still pending? Let us recheck it. |
…candidate keys 2. JFR tool not found — missing JAVA_HOME fallback 3. JaCoCo coverage broken — -DargLine was overwriting JaCoCo's agent flag 4. runtime=0 dropped — if result.runtime: was falsy for zero-nanosecond result
01cb9f8 to
f3eecac
Compare
- Walk up parent directories when looking for mvnw wrapper, fixing multi-module projects where mvnw is in the root but optimizer runs from a submodule - Respect user's --no-pr flag in Java tracer path instead of hardcoding no_pr=True, allowing PR creation from tracer-based optimizations - Add --no-pr to e2e tracer test script Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add mvn/gradle test suite examples, fix replay test description, document current limitations (void methods, mvnw search, --add-opens). Remove unverified claims. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
--no-pr is a top-level codeflash flag, not an optimize subcommand flag. Placing it after optimize caused it to be passed to the JVM as an unrecognized option. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…vior" This reverts commit 85e8a51.
…nction matching Replay test metadata now stores qualified names (e.g. Matrix4f.invertLocal) instead of short names (invertLocal). This prevents mismatches when multiple classes have methods with the same name, ensuring replay tests are correctly mapped to their source functions during optimization. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix(java): use qualified names in replay test metadata for correct function matching
Summary
Eliminates
codeflash.tomlfor Java projects and fixes the complete trace → optimize pipeline to work end-to-end on real Java projects (validated on aerospike-client-java).Zero-config Java support
pom.xml/build.gradle— no config file neededpom.xml<properties>orgradle.properties(codeflash.*keys)<sourceDirectory>/<testSourceDirectory>, picks module with most Java files as source rootcodeflash.tomlfilesSmart ReplayHelper (behavior + performance parity)
ReplayHelper.replay()now readsCODEFLASH_MODEenv var and produces the same output as existing test instrumentationtest_resultstable for correctness comparisonBug fixes
/→.in class names (JVM internal format vs Java package format)isRecording()check that prevented instrumenting classes loaded during serialization (was causing 3 captures instead of 10,000+)org.junit.Testvsorg.junit.jupiter.api.Test), detect from project build config_add_behavior_instrumentationfor compact@Testlines (annotation + signature on same line)add_help=Falseso-hin Java commands isn't intercepted as--helpValidated end-to-end on aerospike-client-java
Crypto.computeDigest)Test plan
🤖 Generated with Claude Code