semantics

This commit is contained in:
2026-05-12 20:06:16 +03:00
parent 9ea177558b
commit fe8978f716
461 changed files with 31360 additions and 25040 deletions

View File

@@ -1,12 +1,10 @@
# [DEF:GitServiceBase:Module]
# @COMPLEXITY: 3
# @LAYER: Infra
# @SEMANTICS: git, service, repository, version_control, initialization
# @PURPOSE: Core GitService base class — initialization, path resolution, repo lifecycle (init/delete/get), and identity configuration.
# @RELATION: INHERITED_BY -> [GitService]
# @RELATION: DEPENDS_ON -> [SessionLocal]
# @RELATION: DEPENDS_ON -> [AppConfigRecord]
# @RELATION: DEPENDS_ON -> [GitRepository]
# #region GitServiceBase [C:3] [TYPE Module] [SEMANTICS git, service, repository, version_control, initialization]
# @BRIEF Core GitService base class — initialization, path resolution, repo lifecycle (init/delete/get), and identity configuration.
# @LAYER Infra
# @RELATION INHERITED_BY -> [GitService]
# @RELATION DEPENDS_ON -> [SessionLocal]
# @RELATION DEPENDS_ON -> [AppConfigRecord]
# @RELATION DEPENDS_ON -> [GitRepository]
import os
import re
@@ -25,12 +23,11 @@ from src.models.config import AppConfigRecord
from src.core.database import SessionLocal
# [DEF:GitServiceBase:Class]
# @COMPLEXITY: 3
# @PURPOSE: Base class for GitService providing initialization, path resolution, repository lifecycle, and identity.
# #region GitServiceBase [C:3] [TYPE Class]
# @BRIEF Base class for GitService providing initialization, path resolution, repository lifecycle, and identity.
class GitServiceBase:
# [DEF:GitService_init:Function]
# @PURPOSE: Initializes the GitService with a base path for repositories.
# #region GitService_init [TYPE Function]
# @BRIEF Initializes the GitService with a base path for repositories.
# @PARAM: base_path (str) - Root directory for all Git clones.
# @PRE: base_path is a valid string path.
# @POST: GitService is initialized; base_path directory exists.
@@ -41,12 +38,12 @@ class GitServiceBase:
self._uses_default_base_path = base_path == "git_repos"
self.base_path = self._resolve_base_path(base_path)
self._ensure_base_path_exists()
# [/DEF:GitService_init:Function]
# #endregion GitService_init
# [DEF:_ensure_base_path_exists:Function]
# @PURPOSE: Ensure the repositories root directory exists and is a directory.
# @PRE: self.base_path is resolved to filesystem path.
# @POST: self.base_path exists as directory or raises ValueError.
# #region _ensure_base_path_exists [TYPE Function]
# @BRIEF Ensure the repositories root directory exists and is a directory.
# @PRE self.base_path is resolved to filesystem path.
# @POST self.base_path exists as directory or raises ValueError.
def _ensure_base_path_exists(self) -> None:
base = Path(self.base_path)
if base.exists() and not base.is_dir():
@@ -56,13 +53,13 @@ class GitServiceBase:
except (PermissionError, OSError) as e:
log.explore("Cannot create Git repositories base path", payload={"base_path": self.base_path}, error=str(e))
raise ValueError(f"Cannot create Git repositories base path: {self.base_path}. {e}")
# [/DEF:_ensure_base_path_exists:Function]
# #endregion _ensure_base_path_exists
# [DEF:_resolve_base_path:Function]
# @PURPOSE: Resolve base repository directory from explicit argument or global storage settings.
# @PRE: base_path is a string path.
# @POST: Returns absolute path for Git repositories root.
# @RETURN: str
# #region _resolve_base_path [TYPE Function]
# @BRIEF Resolve base repository directory from explicit argument or global storage settings.
# @PRE base_path is a string path.
# @POST Returns absolute path for Git repositories root.
# @RETURN str
def _resolve_base_path(self, base_path: str) -> str:
backend_root = Path(__file__).parents[3]
fallback_path = str((backend_root / base_path).resolve())
@@ -91,23 +88,23 @@ class GitServiceBase:
except Exception as e:
log.explore("Falling back to default base path", error=str(e))
return fallback_path
# [/DEF:_resolve_base_path:Function]
# #endregion _resolve_base_path
# [DEF:_normalize_repo_key:Function]
# @PURPOSE: Convert user/dashboard-provided key to safe filesystem directory name.
# @PRE: repo_key can be None/empty.
# @POST: Returns normalized non-empty key.
# @RETURN: str
# #region _normalize_repo_key [TYPE Function]
# @BRIEF Convert user/dashboard-provided key to safe filesystem directory name.
# @PRE repo_key can be None/empty.
# @POST Returns normalized non-empty key.
# @RETURN str
def _normalize_repo_key(self, repo_key: Optional[str]) -> str:
raw_key = str(repo_key or "").strip().lower()
normalized = re.sub(r"[^a-z0-9._-]+", "-", raw_key).strip("._-")
return normalized or "dashboard"
# [/DEF:_normalize_repo_key:Function]
# #endregion _normalize_repo_key
# [DEF:_update_repo_local_path:Function]
# @PURPOSE: Persist repository local_path in GitRepository table when record exists.
# @PRE: dashboard_id is valid integer.
# @POST: local_path is updated for existing record.
# #region _update_repo_local_path [TYPE Function]
# @BRIEF Persist repository local_path in GitRepository table when record exists.
# @PRE dashboard_id is valid integer.
# @POST local_path is updated for existing record.
def _update_repo_local_path(self, dashboard_id: int, local_path: str) -> None:
try:
session = SessionLocal()
@@ -124,13 +121,13 @@ class GitServiceBase:
session.close()
except Exception as e:
log.explore("Failed to update repo local path", error=str(e))
# [/DEF:_update_repo_local_path:Function]
# #endregion _update_repo_local_path
# [DEF:_migrate_repo_directory:Function]
# @PURPOSE: Move legacy repository directory to target path and sync DB metadata.
# @PRE: source_path exists.
# @POST: Repository content available at target_path.
# @RETURN: str
# #region _migrate_repo_directory [TYPE Function]
# @BRIEF Move legacy repository directory to target path and sync DB metadata.
# @PRE source_path exists.
# @POST Repository content available at target_path.
# @RETURN str
def _migrate_repo_directory(self, dashboard_id: int, source_path: str, target_path: str) -> str:
source_abs = os.path.abspath(source_path)
target_abs = os.path.abspath(target_path)
@@ -147,10 +144,10 @@ class GitServiceBase:
self._update_repo_local_path(dashboard_id, target_abs)
log.reflect(f"Repository migrated for dashboard {dashboard_id}: {source_abs} -> {target_abs}")
return target_abs
# [/DEF:_migrate_repo_directory:Function]
# #endregion _migrate_repo_directory
# [DEF:_get_repo_path:Function]
# @PURPOSE: Resolves the local filesystem path for a dashboard's repository.
# #region _get_repo_path [TYPE Function]
# @BRIEF Resolves the local filesystem path for a dashboard's repository.
# @PARAM: dashboard_id (int)
# @PARAM: repo_key (Optional[str]) - Slug-like key used when DB local_path is absent.
# @PRE: dashboard_id is an integer.
@@ -193,10 +190,10 @@ class GitServiceBase:
if os.path.exists(target_path):
self._update_repo_local_path(dashboard_id, target_path)
return target_path
# [/DEF:_get_repo_path:Function]
# #endregion _get_repo_path
# [DEF:init_repo:Function]
# @PURPOSE: Initialize or clone a repository for a dashboard.
# #region init_repo [TYPE Function]
# @BRIEF Initialize or clone a repository for a dashboard.
# @PARAM: dashboard_id (int), remote_url (str), pat (str), repo_key (Optional[str]).
# @PRE: dashboard_id is int, remote_url is valid Git URL, pat is provided.
# @POST: Repository is cloned or opened at the local path.
@@ -232,12 +229,12 @@ class GitServiceBase:
repo = Repo.clone_from(auth_url, repo_path)
self._ensure_gitflow_branches(repo, dashboard_id)
return repo
# [/DEF:init_repo:Function]
# #endregion init_repo
# [DEF:delete_repo:Function]
# @PURPOSE: Remove local repository and DB binding for a dashboard.
# @PRE: dashboard_id is a valid integer.
# @POST: Local path is deleted when present and GitRepository row is removed.
# #region delete_repo [TYPE Function]
# @BRIEF Remove local repository and DB binding for a dashboard.
# @PRE dashboard_id is a valid integer.
# @POST Local path is deleted when present and GitRepository row is removed.
def delete_repo(self, dashboard_id: int) -> None:
with belief_scope("GitService.delete_repo"):
repo_path = self._get_repo_path(dashboard_id)
@@ -274,13 +271,13 @@ class GitServiceBase:
raise HTTPException(status_code=500, detail=f"Failed to delete repository: {str(e)}")
finally:
session.close()
# [/DEF:delete_repo:Function]
# #endregion delete_repo
# [DEF:get_repo:Function]
# @PURPOSE: Get Repo object for a dashboard.
# @PRE: Repository must exist on disk for the given dashboard_id.
# @POST: Returns a GitPython Repo instance for the dashboard.
# @RETURN: Repo
# #region get_repo [TYPE Function]
# @BRIEF Get Repo object for a dashboard.
# @PRE Repository must exist on disk for the given dashboard_id.
# @POST Returns a GitPython Repo instance for the dashboard.
# @RETURN Repo
def get_repo(self, dashboard_id: int) -> Repo:
with belief_scope("GitService.get_repo"):
repo_path = self._get_repo_path(dashboard_id)
@@ -292,12 +289,12 @@ class GitServiceBase:
except Exception as e:
log.explore(f"Failed to open repository at {repo_path}", error=str(e))
raise HTTPException(status_code=500, detail="Failed to open local Git repository")
# [/DEF:get_repo:Function]
# #endregion get_repo
# [DEF:configure_identity:Function]
# @PURPOSE: Configure repository-local Git committer identity for user-scoped operations.
# @PRE: dashboard_id repository exists; git_username/git_email may be empty.
# @POST: Repository config has user.name and user.email when both identity values are provided.
# #region configure_identity [TYPE Function]
# @BRIEF Configure repository-local Git committer identity for user-scoped operations.
# @PRE dashboard_id repository exists; git_username/git_email may be empty.
# @POST Repository config has user.name and user.email when both identity values are provided.
def configure_identity(self, dashboard_id: int, git_username: Optional[str], git_email: Optional[str]) -> None:
with belief_scope("GitService.configure_identity"):
normalized_username = str(git_username or "").strip()
@@ -313,6 +310,6 @@ class GitServiceBase:
except Exception as e:
log.explore("Failed to configure git identity", error=str(e))
raise HTTPException(status_code=500, detail=f"Failed to configure git identity: {str(e)}")
# [/DEF:configure_identity:Function]
# [/DEF:GitServiceBase:Class]
# [/DEF:GitServiceBase:Module]
# #endregion configure_identity
# #endregion GitServiceBase
# #endregion GitServiceBase