feat: multi-language orchestration loop with per-language config discovery#1918
feat: multi-language orchestration loop with per-language config discovery#1918mashraf-222 wants to merge 7 commits intomainfrom
Conversation
|
Claude finished @mashraf-222's task in 7m 57s —— View job PR Review Summary
Prek Checks
Mypy shows 14 errors across Code ReviewFixed since last review cycle ✅ All three critical bugs from the previous review cycle are addressed:
Previous note corrected: Still open — medium severity
Minor
Duplicate DetectionNo duplicates detected. Test Coverage59 new tests across three test files — all pass. Coverage on the new orchestration path:
The lower numbers reflect untouched legacy paths (init, auth, verify-setup, etc.) that are exercised in other test suites. The new paths added by this PR are well-covered by Missing test noted from previous review (still missing): a test verifying Last updated: 2026-04-01 |
…discovery Adds the ability for codeflash CLI to discover and optimize multiple languages in a single run. When configs for Python, Java, and/or JS/TS are found, the optimizer runs once per language with isolated args. - Add LanguageConfig dataclass and find_all_config_files() for upward walk + monorepo subdirectory scanning (Python/JS/Java) - Extract normalize_toml_config() from inline parse_config_file logic - Add apply_language_config() for per-language arg setup in cli.py - Set language singleton early in process_pyproject_config() - Add orchestration loop in main.py with --file language filtering, per-language error isolation, and summary logging - Use build_config_strategy.parse_java_project_config() (from #1906) - Make get_git_diff tests language-agnostic (no singleton dependency) Intentionally omits auto_configure_language and detect_unconfigured_languages per Linear CF-1075 review. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TypeScript projects discovered via package.json were incorrectly assigned Language.JAVASCRIPT. Now derives language from the config dict returned by parse_package_json_config() and deduplicates both JS and TS together. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract resolve_config_onto_args() from duplicated logic between process_pyproject_config and apply_language_config (~100 lines deduped). This fixes: - Missing benchmark validation in apply_language_config (HIGH) - Missing LSP guard in apply_language_config (MEDIUM) - --all /specific/path silently overridden in orchestration loop (MEDIUM) - Silent except Exception: pass in config discovery (MEDIUM) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
03d890d to
bc6444a
Compare
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
In the multi-language orchestration path, handle_optimize_all_arg_parsing runs before config is loaded, so args.git_remote is unset. This caused repo.remote(name=None) to raise ValueError, crashing every --file/--all run without --no-pr. Default to "origin" when git_remote is not set. Also catch git.NoSuchPathError in check_running_in_git_repo and handle_optimize_all_arg_parsing so non-existent module_root paths return graceful errors instead of uncaught exceptions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@claude review |
|
Claude finished @aseembits93's task in 2m 58s —— View job PR Review
SummarySolid feature work overall — the orchestration loop, config discovery, and test coverage are well-structured. Found several bugs and a few design issues that should be addressed before merging. Bugs1.
bool_keys = {
"override-fixtures": False,
"disable-telemetry": False,
"disable-imports-sorting": False,
"benchmark": False, # ← NEW, wasn't in original
}
2.
trace_optimize = subparsers.add_parser("optimize", help="...", add_help=False)This removes 3.
for lang_config in language_configs:
...
init_sentry(enabled=not pass_args.disable_telemetry, exclude_errors=True) # ← N times
posthog_cf.initialize_posthog(enabled=not pass_args.disable_telemetry) # ← N timesThese are initialization calls that are called once in all other code paths. In the multi-language loop, they're called once per language. Even if idempotent, this is inconsistent and could cause issues if Design Issues4.
if language is not None:
set_current_language(language)
5.
dir_path = start_dir.resolve()
while True:
_check_dir_for_configs(dir_path, configs, seen_languages)
parent = dir_path.parent
if parent == dir_path:
break
dir_path = parentOn developer machines this will routinely scan 6. No first-run experience in the multi-config path
language_configs = find_all_config_files()
if not language_configs:
loaded_args = _handle_config_loading(args) # ← first-run only in this branch
...If 7.
def _parse_java_config_for_dir(dir_path: Path) -> dict[str, Any] | None:
from codeflash.languages.java.build_config_strategy import parse_java_project_config
return parse_java_project_config(dir_path)This wrapper only exists to defer the import, but the same pattern is already used inline elsewhere. It's also the only reason 8.
Test Coverage
Minor
|
Code Review: Bug ReportRan a thorough static analysis and runtime verification of this PR. Found 7 issues (2 critical, 2 medium, 3 low). Bug 1 (Critical): Any
|
- Stop upward config walk at git repo root to prevent picking up configs from parent directories outside the project - Require "codeflash" key in package.json for JS/TS multi-language discovery, matching Python's [tool.codeflash] opt-in model - Remove accidental add_help=False from optimize subparser Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
d21a088 to
ad661a7
Compare
|
Addressed in ad661a7:
Not addressed (pre-existing, not introduced by this PR):
|
…vered project root When running `--file` from a repo containing subdirectories with build files (e.g. codeflash-java-runtime/ with pom.xml), config discovery picks up those subdirs as language configs. This causes a ValueError crash because the target file isn't within the spurious project root. Two fixes: - main.py: filter_configs_for_file() excludes configs whose project root doesn't contain the target file - cli.py: only override project_root for Java when module_root is within config_path (defense-in-depth) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Fixed in b320ef9. Two changes:
Added 3 tests covering the spurious config scenario. E2E validated all 3 reviewer repro commands (Python, Java fixture, JS fixture path). |
Summary
Adds multi-language support to the CLI. A single
codeflashinvocation now discovers and processes all configured languages (Python, Java, JS/TS) sequentially.CF-1075
How it works
Config discovery (
find_all_config_filesinconfig_parser.py):pyproject.toml(Python),package.json(JS/TS),pom.xml/build.gradle(Java)Orchestration loop (
main.py):LanguageConfig, deep-copies args, applies language-specific config, runs optimizerKey behaviors:
--filefilters to the matching language automatically--allre-resolves per language (each gets its ownmodule_root)Files changed
config_parser.pyLanguageConfigdataclass,find_all_config_files(),normalize_toml_config()extractioncli.pyapply_language_config()— maps LanguageConfig onto CLI argsmain.pytest_git_utils.pytest_registry.pytest_multi_config_discovery.pytest_multi_language_orchestration.pyTest plan
pytest tests/test_multi_language_orchestration.py tests/test_multi_config_discovery.py -v)prek run --from-ref origin/mainpasses