mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-13 12:15:10 +00:00
Fix dangling registered project poisoning project lookup/activation
A registered project whose root directory was deleted (e.g. a removed git worktree) would raise FileNotFoundError from RegisteredProject.matches_root_path (via Path.samefile). Because get_registered_project iterates matches_root_path over every registered project, one dangling entry aborted activation of all other, valid projects until an MCP server restart. matches_root_path now treats a non-existent directory as a non-match instead of letting the filesystem error propagate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
bd322fcb5e
commit
4160732c7d
3 files changed
+52
-2
No files matched your search
@@ -20,6 +20,8 @@ Status of the `main` branch. Changes prior to the next official version change w
|
||||
- Improve quoting/escaping of arguments in shell executions on Windows (via `oslex` dependency)
|
||||
- Add tool parameter alias support, adding `name_path` as an alias for `name_path_pattern` in `find_symbol` tools
|
||||
- Make tool call errors surface explicitly as errors at the MCP protocol level
|
||||
- Fix: a registered project whose root directory was deleted while Serena was already running could break
|
||||
`activate_project`/project lookup, raising `FileNotFoundError` in `RegisteredProject.matches_root_path`
|
||||
|
||||
* Language Servers:
|
||||
- `typescript_vts`: Add `initialization_options` setting in `ls_specific_settings.typescript_vts`.
|
||||
|
||||
@@ -705,9 +705,14 @@ class RegisteredProject(ToStringMixin):
|
||||
Check if the given path matches the project root path.
|
||||
|
||||
:param path: the path to check
|
||||
:return: True if the path matches the project root, False otherwise
|
||||
:return: True if the path matches the project root, False otherwise (including the case
|
||||
where this project's root directory no longer exists, e.g. a removed git worktree)
|
||||
"""
|
||||
return self.project_root.samefile(Path(path).resolve())
|
||||
try:
|
||||
return self.project_root.samefile(Path(path).resolve())
|
||||
except OSError:
|
||||
# typically raised if the path does not exist (e.g., a removed git worktree)
|
||||
return False
|
||||
|
||||
def get_project_instance(self, serena_config: "SerenaConfig") -> "Project":
|
||||
"""
|
||||
|
||||
@@ -569,6 +569,49 @@ class TestSerenaConfigFromConfigFileRobustness:
|
||||
)
|
||||
|
||||
|
||||
class TestGetRegisteredProjectWithDanglingProject:
|
||||
"""A registered project whose root directory was deleted (e.g. a removed git
|
||||
worktree) must not break lookup/activation of other, valid projects.
|
||||
|
||||
Reproduces the bug where ``get_registered_project`` iterates over every
|
||||
registered project and ``RegisteredProject.matches_root_path`` raises
|
||||
``FileNotFoundError`` for the dangling project, aborting the whole lookup.
|
||||
"""
|
||||
|
||||
def setup_method(self):
|
||||
self.test_dir = Path(tempfile.mkdtemp())
|
||||
|
||||
def teardown_method(self):
|
||||
shutil.rmtree(self.test_dir, ignore_errors=True)
|
||||
|
||||
def _make_project_dir(self, name: str) -> Path:
|
||||
project_dir = self.test_dir / name
|
||||
(project_dir / SERENA_MANAGED_DIR_NAME).mkdir(parents=True)
|
||||
(project_dir / SERENA_MANAGED_DIR_NAME / "project.yml").write_text(f'project_name: "{name}"\nlanguages: ["python"]\n')
|
||||
return project_dir
|
||||
|
||||
def test_dangling_project_does_not_break_lookup_of_valid_project(self):
|
||||
config = create_default_serena_config()
|
||||
dangling_dir = self._make_project_dir("dangling_project")
|
||||
valid_dir = self._make_project_dir("valid_project")
|
||||
|
||||
# Register the dangling project FIRST so the path-matching loop hits the
|
||||
# deleted directory before reaching the valid project.
|
||||
config.projects = [
|
||||
RegisteredProject.from_project_root(dangling_dir, serena_config=config),
|
||||
RegisteredProject.from_project_root(valid_dir, serena_config=config),
|
||||
]
|
||||
|
||||
# Delete the dangling project's directory out from under Serena.
|
||||
shutil.rmtree(dangling_dir)
|
||||
|
||||
# Looking up the valid project by path must succeed, not raise
|
||||
# FileNotFoundError on the deleted dangling project's path.
|
||||
result = config.get_registered_project(str(valid_dir))
|
||||
assert result is not None
|
||||
assert result.project_name == "valid_project"
|
||||
|
||||
|
||||
class TestMemoriesManagerCustomPath:
|
||||
"""Tests for MemoriesManager with a custom serena data folder."""
|
||||
|
||||
|
||||
Reference in new issue
Block a user