Add support for project.local.yml

This commit is contained in:
Dominik Jain committed 2026-03-05 21:55:21 +01:00
1 parent 58efe413e3
commit 75cf842180
4 files changed
+18 -11

No files matched your search

+5
View File
@@ -59,6 +59,11 @@ The file allows you to configure ...
For detailed information on the parameters and possible settings, see the
[template file](https://github.com/oraios/serena/blob/main/src/serena/resources/project.template.yml).
**Local Overrides**. The project.yml file is intended to be versioned together with the project.
You can specify local overrides for the settings in a `project.local.yml` file in the same directory
(which, by default, is ignored by git).
Any keys defined therein will override the respective key in `project.yml`.
(indexing)=
### Indexing
+9 -8
View File
@@ -213,7 +213,8 @@ class ProjectConfig(SharedConfig):
initial_prompt: str = ""
encoding: str = DEFAULT_SOURCE_FILE_ENCODING
SERENA_DEFAULT_PROJECT_FILE = "project.yml"
SERENA_PROJECT_FILE = "project.yml"
SERENA_LOCAL_PROJECT_FILE = "project.local.yml"
FIELDS_WITHOUT_DEFAULTS = {"project_name", "languages"}
YAML_COMMENT_NORMALISATION = YamlCommentNormalisation.LEADING
"""
@@ -296,7 +297,7 @@ class ProjectConfig(SharedConfig):
log.info("Using languages: %s", languages_to_use)
else:
languages_to_use = [lang.value for lang in languages]
config_with_comments, _ = cls._load_yaml(PROJECT_TEMPLATE_FILE)
config_with_comments, _ = cls._load_yaml_dict(PROJECT_TEMPLATE_FILE)
config_with_comments["project_name"] = project_name
config_with_comments["languages"] = languages_to_use
if save_to_disk:
@@ -312,10 +313,10 @@ class ProjectConfig(SharedConfig):
This is suitable as a fallback when no ``SerenaConfig`` is available to resolve
a potentially customised location.
"""
return os.path.join(str(project_root), SERENA_MANAGED_DIR_NAME, cls.SERENA_DEFAULT_PROJECT_FILE)
return os.path.join(str(project_root), SERENA_MANAGED_DIR_NAME, cls.SERENA_PROJECT_FILE)
@classmethod
def _load_yaml(
def _load_yaml_dict(
cls, yml_path: str, comment_normalisation: YamlCommentNormalisation = YamlCommentNormalisation.NONE
) -> tuple[CommentedMap, bool]:
"""
@@ -429,7 +430,7 @@ class ProjectConfig(SharedConfig):
raise FileNotFoundError(f"Project configuration file not found: {yaml_path}")
# load the configuration dictionary
yaml_data, was_complete = cls._load_yaml(str(yaml_path))
yaml_data, was_complete = cls._load_yaml_dict(str(yaml_path))
if "project_name" not in yaml_data:
yaml_data["project_name"] = project_folder_name
@@ -453,11 +454,11 @@ class ProjectConfig(SharedConfig):
log.info("Saving updated project configuration to %s", config_path)
# load original commented map and update it with current values
config_with_comments, _ = self._load_yaml(config_path, self.YAML_COMMENT_NORMALISATION)
config_with_comments, _ = self._load_yaml_dict(config_path, self.YAML_COMMENT_NORMALISATION)
config_with_comments.update(self._to_yaml_dict())
# transfer missing comments from the template file
template_config, _ = self._load_yaml(PROJECT_TEMPLATE_FILE, self.YAML_COMMENT_NORMALISATION)
template_config, _ = self._load_yaml_dict(PROJECT_TEMPLATE_FILE, self.YAML_COMMENT_NORMALISATION)
transfer_missing_yaml_comments(template_config, config_with_comments, self.YAML_COMMENT_NORMALISATION)
save_yaml(config_path, config_with_comments)
@@ -981,7 +982,7 @@ class SerenaConfig(SharedConfig):
:return: the resolved absolute path to the project's project.yml file
"""
serena_folder = self.get_project_serena_folder(project_root)
return os.path.join(serena_folder, ProjectConfig.SERENA_DEFAULT_PROJECT_FILE)
return os.path.join(serena_folder, ProjectConfig.SERENA_PROJECT_FILE)
def propagate_settings(self) -> None:
"""
+1
View File
@@ -219,6 +219,7 @@ class Project(ToStringMixin):
log.info(f"Creating .gitignore file in {serena_data_gitignore_path}")
with open(serena_data_gitignore_path, "w", encoding="utf-8") as f:
f.write(f"/{SolidLanguageServer.CACHE_FOLDER_NAME}\n")
f.write(f"/{ProjectConfig.SERENA_LOCAL_PROJECT_FILE}\n")
# prepare ignore spec asynchronously, ensuring immediate project activation.
self.__ignored_patterns: list[str]
+3 -3
View File
@@ -135,7 +135,7 @@ class TestProjectConfigAutogenerate:
class TestProjectConfig:
def test_template_is_complete(self):
_, is_complete = ProjectConfig._load_yaml(PROJECT_TEMPLATE_FILE)
_, is_complete = ProjectConfig._load_yaml_dict(PROJECT_TEMPLATE_FILE)
assert is_complete, "Project template YAML is incomplete; all fields must be present (with descriptions)."
@@ -177,7 +177,7 @@ class TestProjectConfigLanguageBackend:
def test_language_backend_parsed_from_dict(self):
"""Test that _from_dict parses language_backend correctly."""
template_path = PROJECT_TEMPLATE_FILE
data, _ = ProjectConfig._load_yaml(template_path)
data, _ = ProjectConfig._load_yaml_dict(template_path)
data["project_name"] = "test"
data["languages"] = ["python"]
data["language_backend"] = "JetBrains"
@@ -187,7 +187,7 @@ class TestProjectConfigLanguageBackend:
def test_language_backend_none_when_missing_from_dict(self):
"""Test that _from_dict handles missing language_backend gracefully."""
template_path = PROJECT_TEMPLATE_FILE
data, _ = ProjectConfig._load_yaml(template_path)
data, _ = ProjectConfig._load_yaml_dict(template_path)
data["project_name"] = "test"
data["languages"] = ["python"]
data.pop("language_backend", None)