From 0fe0e79355bde3586781c029f11d8e51c07d27ac Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Nov 2025 06:45:34 +0000 Subject: [PATCH] Remove LocalGitConfigSource in favor of RemoteGitConfigSource with file URL support Co-authored-by: chrisburr <5220533+chrisburr@users.noreply.github.com> --- .../src/diracx/core/config/__init__.py | 2 - diracx-core/src/diracx/core/config/sources.py | 50 +++++-------------- diracx-core/tests/test_config_source.py | 30 +++++++++++ 3 files changed, 42 insertions(+), 40 deletions(-) diff --git a/diracx-core/src/diracx/core/config/__init__.py b/diracx-core/src/diracx/core/config/__init__.py index 37ff457ca..b07dc57d7 100644 --- a/diracx-core/src/diracx/core/config/__init__.py +++ b/diracx-core/src/diracx/core/config/__init__.py @@ -6,7 +6,6 @@ from .sources import ( ConfigSource, ConfigSourceUrl, - LocalGitConfigSource, RemoteGitConfigSource, is_running_in_async_context, ) @@ -15,7 +14,6 @@ "Config", "ConfigSource", "ConfigSourceUrl", - "LocalGitConfigSource", "RemoteGitConfigSource", "is_running_in_async_context", ) diff --git a/diracx-core/src/diracx/core/config/sources.py b/diracx-core/src/diracx/core/config/sources.py index 1cf9cc622..e8c55b415 100644 --- a/diracx-core/src/diracx/core/config/sources.py +++ b/diracx-core/src/diracx/core/config/sources.py @@ -67,7 +67,7 @@ class ConfigSource(metaclass=ABCMeta): # Keep a mapping between the scheme and the class __registry: dict[str, type["ConfigSource"]] = {} - scheme: str + scheme: str | list[str] def __init__(self, *, backend_url: ConfigSourceUrl) -> None: # Revision cache is used to store the latest revision and its @@ -102,9 +102,11 @@ def read_raw(self, hexsha: str, modified: datetime) -> Config: def __init_subclass__(cls) -> None: """Keep a record of .""" - if cls.scheme in cls.__registry: - raise TypeError(f"{cls.scheme=} is already define") - cls.__registry[cls.scheme] = cls + schemes = cls.scheme if isinstance(cls.scheme, list) else [cls.scheme] + for scheme in schemes: + if scheme in cls.__registry: + raise TypeError(f"{scheme=} is already defined") + cls.__registry[scheme] = cls @classmethod def create(cls): @@ -233,42 +235,14 @@ def get_git_branch_from_url(self, backend_url: ConfigSourceUrl) -> str: return dict(backend_url.query_params()).get("branch", DEFAULT_GIT_BRANCH) -class LocalGitConfigSource(BaseGitConfigSource): - """The configuration is stored on a local git repository - When running on multiple servers, the filesystem must be shared. - """ - - scheme = "git+file" - - def __init__(self, *, backend_url: ConfigSourceUrl) -> None: - super().__init__(backend_url=backend_url) - if not backend_url.path: - raise ValueError("Empty path for LocalGitConfigSource") - - self.repo_location = Path(backend_url.path) - # Check if it's a valid git repository - try: - sh.git( - "rev-parse", - "--git-dir", - _cwd=self.repo_location, - _tty_out=False, - _async=False, - ) - except sh.ErrorReturnCode as e: - raise ValueError( - f"{self.repo_location} is not a valid git repository" - ) from e - sh.git.checkout(self.git_branch, _cwd=self.repo_location, _async=False) - - def __hash__(self): - return hash(self.repo_location) - - class RemoteGitConfigSource(BaseGitConfigSource): - """Use a remote directory as a config source.""" + """Use a remote or local git repository as a config source. + + Supports both remote URLs (git+https://) and local file URLs (git+file://). + The repository is cloned to a temporary directory. + """ - scheme = "git+https" + scheme = ["git+https", "git+file"] def __init__(self, *, backend_url: ConfigSourceUrl) -> None: super().__init__(backend_url=backend_url) diff --git a/diracx-core/tests/test_config_source.py b/diracx-core/tests/test_config_source.py index d448b0dfd..75656ed1d 100644 --- a/diracx-core/tests/test_config_source.py +++ b/diracx-core/tests/test_config_source.py @@ -36,3 +36,33 @@ def test_remote_git_config_source(monkeypatch, repo_url): assert isinstance(modified, datetime.datetime) result = remote_conf.read_raw(hexsha, modified) assert isinstance(result, Config) + + +def test_file_url_config_source(tmp_path): + """Test that file URLs work with RemoteGitConfigSource.""" + from git import Repo + + # Create a test git repository + repo = Repo.init(tmp_path, initial_branch="master") + cs_file = tmp_path / "default.yml" + example_cs = Config.model_validate( + { + "DIRAC": {}, + "Registry": {}, + "Operations": {}, + } + ) + cs_file.write_text(example_cs.model_dump_json()) + repo.index.add([cs_file]) + repo.index.commit("Initial commit") + + # Test with git+file:// URL + file_url = f"git+file://{tmp_path}" + config_source = ConfigSource.create_from_url(backend_url=file_url) + assert isinstance(config_source, RemoteGitConfigSource) + + hexsha, modified = config_source.latest_revision() + assert isinstance(hexsha, str) + assert isinstance(modified, datetime.datetime) + result = config_source.read_raw(hexsha, modified) + assert isinstance(result, Config)