Coverage for repo_ctx / providers / base.py: 82%
38 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-25 17:42 +0100
« prev ^ index » next coverage.py v7.12.0, created at 2025-11-25 17:42 +0100
1"""Abstract base class for repository providers."""
2from abc import ABC, abstractmethod
3from dataclasses import dataclass
4from typing import Optional, List
7@dataclass
8class ProviderProject:
9 """Normalized project representation across providers."""
10 id: str
11 name: str
12 path: str
13 description: Optional[str]
14 default_branch: str
15 web_url: Optional[str]
18@dataclass
19class ProviderFile:
20 """Normalized file representation."""
21 path: str
22 content: str
23 size: int
26class GitProvider(ABC):
27 """Abstract base class for all repository providers."""
29 @abstractmethod
30 async def get_project(self, path: str) -> ProviderProject:
31 """
32 Get project metadata.
34 Args:
35 path: Provider-specific project identifier
36 GitLab: "group/project" or "group/subgroup/project"
37 GitHub: "owner/repo"
38 Local: "/absolute/path" or "./relative/path"
40 Returns:
41 ProviderProject with normalized metadata
43 Raises:
44 ProviderNotFoundError: Project doesn't exist
45 ProviderAuthError: Authentication failed
46 """
47 pass
49 @abstractmethod
50 async def get_default_branch(self, project: ProviderProject) -> str:
51 """
52 Get default branch name (main, master, etc.).
54 Args:
55 project: Project to query
57 Returns:
58 Default branch name
60 Raises:
61 ProviderError: Error getting branch information
62 """
63 pass
65 @abstractmethod
66 async def get_file_tree(
67 self,
68 project: ProviderProject,
69 ref: str,
70 recursive: bool = True
71 ) -> List[str]:
72 """
73 Get list of all file paths in repository.
75 Args:
76 project: Project to query
77 ref: Branch, tag, or commit SHA
78 recursive: Include subdirectories
80 Returns:
81 List of file paths relative to repo root
83 Raises:
84 ProviderError: Error accessing file tree
85 """
86 pass
88 @abstractmethod
89 async def read_file(
90 self,
91 project: ProviderProject,
92 path: str,
93 ref: str
94 ) -> ProviderFile:
95 """
96 Read file contents.
98 Args:
99 project: Project to query
100 path: File path relative to repo root
101 ref: Branch, tag, or commit SHA
103 Returns:
104 ProviderFile with content and metadata
106 Raises:
107 ProviderFileNotFoundError: File doesn't exist at ref
108 """
109 pass
111 @abstractmethod
112 async def read_config(
113 self,
114 project: ProviderProject,
115 ref: str
116 ) -> Optional[dict]:
117 """
118 Read repo-ctx configuration file if it exists.
120 Searches for configuration files in this order:
121 1. git_context.json (current name)
122 2. .git_context.json
123 3. repo_context.json
124 4. .repo-ctx.json
126 Args:
127 project: Project to query
128 ref: Branch, tag, or commit SHA
130 Returns:
131 Parsed JSON config or None if not found
133 Raises:
134 ProviderError: Error reading configuration
135 """
136 pass
138 @abstractmethod
139 async def get_tags(
140 self,
141 project: ProviderProject,
142 limit: int = 5
143 ) -> List[str]:
144 """
145 Get repository tags (most recent first).
147 Args:
148 project: Project to query
149 limit: Maximum number of tags to return
151 Returns:
152 List of tag names
154 Raises:
155 ProviderError: Error accessing tags
156 """
157 pass
159 @abstractmethod
160 async def list_projects_in_group(
161 self,
162 group_path: str,
163 include_subgroups: bool = True
164 ) -> List[ProviderProject]:
165 """
166 List all projects in a group/organization.
168 Args:
169 group_path: Group identifier
170 GitLab: "group" or "group/subgroup"
171 GitHub: "org"
172 Local: Not supported
174 include_subgroups: Include nested groups (GitLab only)
176 Returns:
177 List of projects in the group
179 Raises:
180 ProviderNotFoundError: Group not found
181 NotImplementedError: Provider doesn't support groups
183 Note:
184 Not all providers support groups (e.g., local repos)
185 """
186 pass