Skip to content

Commit 0cd4d5e

Browse files
validating python and git environment with the lsp
1 parent a716c9b commit 0cd4d5e

File tree

6 files changed

+75
-18
lines changed

6 files changed

+75
-18
lines changed

codeflash/cli_cmds/cli.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from codeflash.code_utils import env_utils
1111
from codeflash.code_utils.code_utils import exit_with_message
1212
from codeflash.code_utils.config_parser import parse_config_file
13+
from codeflash.lsp.helpers import is_LSP_enabled
1314
from codeflash.version import __version__ as version
1415

1516

@@ -211,6 +212,9 @@ def process_pyproject_config(args: Namespace) -> Namespace:
211212
if args.benchmarks_root:
212213
args.benchmarks_root = Path(args.benchmarks_root).resolve()
213214
args.test_project_root = project_root_from_module_root(args.tests_root, pyproject_file_path)
215+
if is_LSP_enabled():
216+
args.all = None
217+
return args
214218
return handle_optimize_all_arg_parsing(args)
215219

216220

codeflash/cli_cmds/cmd_init.py

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,22 @@ def ask_run_end_to_end_test(args: Namespace) -> None:
155155
run_end_to_end_test(args, bubble_sort_path, bubble_sort_test_path)
156156

157157

158+
def is_valid_pyproject_toml(pyproject_toml_path: Path) -> dict[str, Any] | None:
159+
if not pyproject_toml_path.exists():
160+
return None
161+
try:
162+
config, _ = parse_config_file(pyproject_toml_path)
163+
except Exception:
164+
return None
165+
166+
if "module_root" not in config or config["module_root"] is None or not Path(config["module_root"]).is_dir():
167+
return None
168+
if "tests_root" not in config or config["tests_root"] is None or not Path(config["tests_root"]).is_dir():
169+
return None
170+
171+
return config
172+
173+
158174
def should_modify_pyproject_toml() -> tuple[bool, dict[str, Any] | None]:
159175
"""Check if the current directory contains a valid pyproject.toml file with codeflash config.
160176
@@ -163,16 +179,9 @@ def should_modify_pyproject_toml() -> tuple[bool, dict[str, Any] | None]:
163179
from rich.prompt import Confirm
164180

165181
pyproject_toml_path = Path.cwd() / "pyproject.toml"
166-
if not pyproject_toml_path.exists():
167-
return True, None
168-
try:
169-
config, config_file_path = parse_config_file(pyproject_toml_path)
170-
except Exception:
171-
return True, None
172182

173-
if "module_root" not in config or config["module_root"] is None or not Path(config["module_root"]).is_dir():
174-
return True, None
175-
if "tests_root" not in config or config["tests_root"] is None or not Path(config["tests_root"]).is_dir():
183+
config = is_valid_pyproject_toml(pyproject_toml_path)
184+
if config is None:
176185
return True, None
177186

178187
return Confirm.ask(
@@ -442,7 +451,7 @@ def collect_setup_info() -> SetupInfo:
442451
apologize_and_exit()
443452
formatter = formatter_answers["formatter"]
444453

445-
git_remote = ""
454+
git_remote = "origin"
446455
try:
447456
repo = Repo(str(module_root), search_parent_directories=True)
448457
git_remotes = get_git_remotes(repo)
@@ -968,6 +977,11 @@ def install_github_app(git_remote: str) -> None:
968977
except git.InvalidGitRepositoryError:
969978
click.echo("Skipping GitHub app installation because you're not in a git repository.")
970979
return
980+
981+
if git_remote not in get_git_remotes(git_repo):
982+
click.echo(f"Skipping GitHub app installation, remote ({git_remote}) does not exist in this repository.")
983+
return
984+
971985
owner, repo = get_repo_owner_and_name(git_repo, git_remote)
972986

973987
if is_github_app_installed_on_repo(owner, repo, suppress_errors=True):

codeflash/code_utils/git_utils.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,8 @@ def get_last_commit_author_if_pr_exists(repo: Repo | None = None) -> str | None:
201201

202202
def create_worktree_snapshot_commit(worktree_dir: Path, commit_message: str) -> None:
203203
repository = git.Repo(worktree_dir, search_parent_directories=True)
204-
repository.git.commit("-am", commit_message, "--no-verify")
204+
repository.git.add(".")
205+
repository.git.commit("-m", commit_message, "--no-verify")
205206

206207

207208
def create_detached_worktree(module_root: Path) -> Optional[Path]:
@@ -234,7 +235,7 @@ def create_detached_worktree(module_root: Path) -> Optional[Path]:
234235
# Apply the patch inside the worktree
235236
try:
236237
subprocess.run(
237-
["git", "apply", "--ignore-space-change", "--ignore-whitespace", patch_path],
238+
["git", "apply", "--ignore-space-change", "--ignore-whitespace", "--whitespace=nowarn", patch_path],
238239
cwd=worktree_dir,
239240
check=True,
240241
)

codeflash/discovery/functions_to_optimize.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from codeflash.code_utils.git_utils import get_git_diff, get_repo_owner_and_name
2828
from codeflash.code_utils.time_utils import humanize_runtime
2929
from codeflash.discovery.discover_unit_tests import discover_unit_tests
30+
from codeflash.lsp.helpers import is_LSP_enabled
3031
from codeflash.models.models import FunctionParent
3132
from codeflash.telemetry.posthog_cf import ph
3233

@@ -470,6 +471,9 @@ def was_function_previously_optimized(
470471
Tuple of (filtered_functions_dict, remaining_count)
471472
472473
"""
474+
if is_LSP_enabled:
475+
return False
476+
473477
# Check optimization status if repository info is provided
474478
# already_optimized_count = 0
475479
try:

codeflash/lsp/beta.py

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from pathlib import Path
77
from typing import TYPE_CHECKING
88

9+
import git
910
from pygls import uris
1011

1112
from codeflash.api.cfapi import get_codeflash_api_key, get_user_id
@@ -88,9 +89,14 @@ def initialize_function_optimization(
8889
) -> dict[str, str]:
8990
file_path = Path(uris.to_fs_path(params.textDocument.uri))
9091
server.show_message_log(f"Initializing optimization for function: {params.functionName} in {file_path}", "Info")
92+
9193
if server.optimizer is None:
92-
_initialize_optimizer_if_valid(server)
94+
_initialize_optimizer_if_api_key_is_valid(server)
95+
9396
server.optimizer.worktree_mode()
97+
# make sure the tests dir is created in the worktree, this can happen if the original tests dir is empty
98+
Path(server.optimizer.args.tests_root).mkdir(parents=True, exist_ok=True)
99+
94100
original_args, _ = server.optimizer.original_args_and_test_cfg
95101

96102
server.optimizer.args.function = params.functionName
@@ -132,7 +138,36 @@ def discover_function_tests(server: CodeflashLanguageServer, params: FunctionOpt
132138
return {"functionName": params.functionName, "status": "success", "discovered_tests": num_discovered_tests}
133139

134140

135-
def _initialize_optimizer_if_valid(server: CodeflashLanguageServer) -> dict[str, str]:
141+
@server.feature("validateProject")
142+
def validate_project(server: CodeflashLanguageServer, _params: FunctionOptimizationParams) -> dict[str, str]:
143+
from codeflash.cli_cmds.cli import process_pyproject_config
144+
from codeflash.cli_cmds.cmd_init import is_valid_pyproject_toml
145+
146+
server.show_message_log("Validating project...", "Info")
147+
config = is_valid_pyproject_toml(server.args.config_file)
148+
if config is None:
149+
server.show_message_log("pyproject.toml is not valid", "Error")
150+
return {
151+
"status": "error",
152+
"message": "pyproject.toml is not valid",
153+
} # keep the error message the same, the extension is matching "pyproject.toml" in the error message to show the codeflash init instructions
154+
155+
new_args = process_pyproject_config(server.args)
156+
server.args = new_args
157+
158+
repo = git.Repo(new_args.module_root, search_parent_directories=True)
159+
if repo.bare:
160+
return {"status": "error", "message": "Repository is in bare state"}
161+
162+
try:
163+
_ = repo.head.commit
164+
except Exception:
165+
return {"status": "error", "message": "Repository has no commits (unborn HEAD)"}
166+
167+
return {"status": "success"}
168+
169+
170+
def _initialize_optimizer_if_api_key_is_valid(server: CodeflashLanguageServer) -> dict[str, str]:
136171
user_id = get_user_id()
137172
if user_id is None:
138173
return {"status": "error", "message": "api key not found or invalid"}
@@ -150,7 +185,7 @@ def _initialize_optimizer_if_valid(server: CodeflashLanguageServer) -> dict[str,
150185
@server.feature("apiKeyExistsAndValid")
151186
def check_api_key(server: CodeflashLanguageServer, _params: any) -> dict[str, str]:
152187
try:
153-
return _initialize_optimizer_if_valid(server)
188+
return _initialize_optimizer_if_api_key_is_valid(server)
154189
except Exception:
155190
return {"status": "error", "message": "something went wrong while validating the api key"}
156191

@@ -170,7 +205,7 @@ def provide_api_key(server: CodeflashLanguageServer, params: ProvideApiKeyParams
170205
get_codeflash_api_key.cache_clear()
171206
get_user_id.cache_clear()
172207

173-
init_result = _initialize_optimizer_if_valid(server)
208+
init_result = _initialize_optimizer_if_api_key_is_valid(server)
174209
if init_result["status"] == "error":
175210
return {"status": "error", "message": "Api key is not valid"}
176211

codeflash/lsp/server.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,12 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: # noqa: ANN401
4949
self.args = None
5050

5151
def prepare_optimizer_arguments(self, config_file: Path) -> None:
52-
from codeflash.cli_cmds.cli import parse_args, process_pyproject_config
52+
from codeflash.cli_cmds.cli import parse_args
5353

5454
args = parse_args()
5555
args.config_file = config_file
5656
args.no_pr = True # LSP server should not create PRs
5757
args.worktree = True
58-
args = process_pyproject_config(args)
5958
self.args = args
6059
# avoid initializing the optimizer during initialization, because it can cause an error if the api key is invalid
6160

0 commit comments

Comments
 (0)