gitcode-api 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gitcode_api/__init__.py +23 -0
- gitcode_api/_base_client.py +324 -0
- gitcode_api/_client.py +235 -0
- gitcode_api/_exceptions.py +39 -0
- gitcode_api/_models.py +272 -0
- gitcode_api/resources/__init__.py +77 -0
- gitcode_api/resources/_shared.py +75 -0
- gitcode_api/resources/account.py +766 -0
- gitcode_api/resources/collaboration.py +1451 -0
- gitcode_api/resources/misc.py +301 -0
- gitcode_api/resources/repositories.py +1458 -0
- gitcode_api-1.0.0.dist-info/METADATA +208 -0
- gitcode_api-1.0.0.dist-info/RECORD +16 -0
- gitcode_api-1.0.0.dist-info/WHEEL +5 -0
- gitcode_api-1.0.0.dist-info/licenses/LICENSE +21 -0
- gitcode_api-1.0.0.dist-info/top_level.txt +1 -0
gitcode_api/__init__.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Public package exports for the GitCode SDK."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from ._client import AsyncGitCode, GitCode
|
|
6
|
+
from ._exceptions import (
|
|
7
|
+
GitCodeAPIError,
|
|
8
|
+
GitCodeConfigurationError,
|
|
9
|
+
GitCodeError,
|
|
10
|
+
GitCodeHTTPStatusError,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__version__ = (Path(__file__).parent / "version.txt").read_text().strip()
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"__version__",
|
|
17
|
+
"AsyncGitCode",
|
|
18
|
+
"GitCode",
|
|
19
|
+
"GitCodeAPIError",
|
|
20
|
+
"GitCodeConfigurationError",
|
|
21
|
+
"GitCodeError",
|
|
22
|
+
"GitCodeHTTPStatusError",
|
|
23
|
+
]
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
"""Shared transport helpers for the GitCode SDK.
|
|
2
|
+
|
|
3
|
+
The classes in this module normalize authentication, URL construction,
|
|
4
|
+
payload cleanup, and response parsing for both sync and async clients.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
from typing import Any
|
|
9
|
+
from urllib.parse import quote
|
|
10
|
+
|
|
11
|
+
import httpx
|
|
12
|
+
|
|
13
|
+
from ._exceptions import GitCodeConfigurationError, GitCodeHTTPStatusError
|
|
14
|
+
|
|
15
|
+
DEFAULT_BASE_URL = "https://api.gitcode.com/api/v5"
|
|
16
|
+
DEFAULT_TIMEOUT = 30.0
|
|
17
|
+
DEFAULT_TOKEN_ENV = "GITCODE_ACCESS_TOKEN"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _drop_none_values(mapping: dict[str, Any]) -> dict[str, Any]:
|
|
21
|
+
"""Return a copy of ``mapping`` without keys that have ``None`` values."""
|
|
22
|
+
return {key: value for key, value in mapping.items() if value is not None}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class BaseGitCodeClient:
|
|
26
|
+
"""Base configuration shared by synchronous and asynchronous clients.
|
|
27
|
+
|
|
28
|
+
:param api_key: Personal access token for the GitCode API.
|
|
29
|
+
:param owner: Default repository owner for repository-scoped calls.
|
|
30
|
+
:param repo: Default repository name for repository-scoped calls.
|
|
31
|
+
:param base_url: Base URL for the GitCode REST API.
|
|
32
|
+
:param timeout: Request timeout in seconds.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
*,
|
|
38
|
+
api_key: str | None = None,
|
|
39
|
+
owner: str | None = None,
|
|
40
|
+
repo: str | None = None,
|
|
41
|
+
base_url: str = DEFAULT_BASE_URL,
|
|
42
|
+
timeout: float | None = None,
|
|
43
|
+
) -> None:
|
|
44
|
+
"""Store client configuration and resolve authentication."""
|
|
45
|
+
self.api_key = self._resolve_api_key(api_key)
|
|
46
|
+
self.owner = owner
|
|
47
|
+
self.repo = repo
|
|
48
|
+
self.base_url = base_url.rstrip("/")
|
|
49
|
+
self.timeout = timeout if timeout is not None else DEFAULT_TIMEOUT
|
|
50
|
+
|
|
51
|
+
def _resolve_api_key(self, api_key: str | None) -> str:
|
|
52
|
+
"""Resolve the access token from an argument or environment variable."""
|
|
53
|
+
token = api_key or os.getenv(DEFAULT_TOKEN_ENV)
|
|
54
|
+
if not token:
|
|
55
|
+
raise GitCodeConfigurationError("No API key provided. Pass api_key=... or set GITCODE_ACCESS_TOKEN.")
|
|
56
|
+
return token
|
|
57
|
+
|
|
58
|
+
def _resolve_repo_context(
|
|
59
|
+
self,
|
|
60
|
+
owner: str | None = None,
|
|
61
|
+
repo: str | None = None,
|
|
62
|
+
) -> tuple[str, str]:
|
|
63
|
+
"""Return the effective repository owner and name for a request."""
|
|
64
|
+
resolved_owner = owner or self.owner
|
|
65
|
+
resolved_repo = repo or self.repo
|
|
66
|
+
if not resolved_owner or not resolved_repo:
|
|
67
|
+
raise GitCodeConfigurationError(
|
|
68
|
+
"Repository methods require owner and repo, either per-call or on the client."
|
|
69
|
+
)
|
|
70
|
+
return resolved_owner, resolved_repo
|
|
71
|
+
|
|
72
|
+
def _headers(self, extra_headers: dict[str, str] | None = None) -> dict[str, str]:
|
|
73
|
+
"""Build request headers for authenticated JSON API calls."""
|
|
74
|
+
headers = {
|
|
75
|
+
"Accept": "application/json",
|
|
76
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
77
|
+
}
|
|
78
|
+
if extra_headers:
|
|
79
|
+
headers.update(extra_headers)
|
|
80
|
+
return headers
|
|
81
|
+
|
|
82
|
+
def _encode_segment(self, value: str | int) -> str:
|
|
83
|
+
"""Percent-encode a single URL path segment."""
|
|
84
|
+
return quote(str(value), safe="")
|
|
85
|
+
|
|
86
|
+
def _encode_path_value(self, value: str) -> str:
|
|
87
|
+
"""Percent-encode a repository path while preserving slashes."""
|
|
88
|
+
return quote(value, safe="/")
|
|
89
|
+
|
|
90
|
+
def _join_path(self, *segments: str | int) -> str:
|
|
91
|
+
"""Join URL path segments into an API path."""
|
|
92
|
+
return "/" + "/".join(self._encode_segment(segment) for segment in segments)
|
|
93
|
+
|
|
94
|
+
def _repo_path(
|
|
95
|
+
self,
|
|
96
|
+
*segments: str | int,
|
|
97
|
+
owner: str | None = None,
|
|
98
|
+
repo: str | None = None,
|
|
99
|
+
) -> str:
|
|
100
|
+
"""Build a path under ``/repos/{owner}/{repo}``."""
|
|
101
|
+
resolved_owner, resolved_repo = self._resolve_repo_context(owner, repo)
|
|
102
|
+
return self._join_path("repos", resolved_owner, resolved_repo, *segments)
|
|
103
|
+
|
|
104
|
+
def _repo_file_path(
|
|
105
|
+
self,
|
|
106
|
+
prefix: str,
|
|
107
|
+
file_path: str,
|
|
108
|
+
*,
|
|
109
|
+
owner: str | None = None,
|
|
110
|
+
repo: str | None = None,
|
|
111
|
+
) -> str:
|
|
112
|
+
"""Build a file-oriented repository path such as ``contents`` or ``raw``."""
|
|
113
|
+
resolved_owner, resolved_repo = self._resolve_repo_context(owner, repo)
|
|
114
|
+
return (
|
|
115
|
+
f"/repos/{self._encode_segment(resolved_owner)}/"
|
|
116
|
+
f"{self._encode_segment(resolved_repo)}/{self._encode_segment(prefix)}/"
|
|
117
|
+
f"{self._encode_path_value(file_path)}"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
def _path(self, *segments: str | int) -> str:
|
|
121
|
+
"""Build a non-repository API path."""
|
|
122
|
+
return self._join_path(*segments)
|
|
123
|
+
|
|
124
|
+
def _full_url(self, path: str) -> str:
|
|
125
|
+
"""Return an absolute URL for a relative API path."""
|
|
126
|
+
if path.startswith("http://") or path.startswith("https://"):
|
|
127
|
+
return path
|
|
128
|
+
return f"{self.base_url}{path}"
|
|
129
|
+
|
|
130
|
+
def _coerce_payload(
|
|
131
|
+
self,
|
|
132
|
+
*,
|
|
133
|
+
params: dict[str, Any] | None = None,
|
|
134
|
+
json: Any = None,
|
|
135
|
+
data: dict[str, Any] | None = None,
|
|
136
|
+
) -> tuple[dict[str, Any] | None, Any, dict[str, Any] | None]:
|
|
137
|
+
"""Drop ``None`` values from params and form payloads before sending."""
|
|
138
|
+
clean_params = _drop_none_values(params or {}) or None
|
|
139
|
+
clean_data = _drop_none_values(data or {}) or None
|
|
140
|
+
return clean_params, json, clean_data
|
|
141
|
+
|
|
142
|
+
def _raise_for_error(self, response: httpx.Response) -> None:
|
|
143
|
+
"""Raise a typed SDK error for non-successful HTTP responses."""
|
|
144
|
+
if response.is_success:
|
|
145
|
+
return
|
|
146
|
+
|
|
147
|
+
payload: Any
|
|
148
|
+
message = response.text
|
|
149
|
+
try:
|
|
150
|
+
payload = response.json()
|
|
151
|
+
if isinstance(payload, dict) and payload.get("message"):
|
|
152
|
+
message = str(payload["message"])
|
|
153
|
+
except ValueError:
|
|
154
|
+
payload = response.text
|
|
155
|
+
|
|
156
|
+
raise GitCodeHTTPStatusError(
|
|
157
|
+
message or f"GitCode API request failed with status {response.status_code}.",
|
|
158
|
+
status_code=response.status_code,
|
|
159
|
+
request_id=response.headers.get("X-Request-Id"),
|
|
160
|
+
payload=payload,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
def _parse_response(self, response: httpx.Response, *, raw: bool = False) -> Any:
|
|
164
|
+
"""Parse a GitCode API response as raw bytes, JSON, text, or ``None``."""
|
|
165
|
+
self._raise_for_error(response)
|
|
166
|
+
if response.status_code == 204:
|
|
167
|
+
return None
|
|
168
|
+
if raw:
|
|
169
|
+
return response.content
|
|
170
|
+
if not response.content:
|
|
171
|
+
return None
|
|
172
|
+
content_type = response.headers.get("Content-Type", "")
|
|
173
|
+
if "application/json" in content_type or "text/json" in content_type:
|
|
174
|
+
return response.json()
|
|
175
|
+
try:
|
|
176
|
+
return response.json()
|
|
177
|
+
except ValueError:
|
|
178
|
+
return response.text
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class SyncAPIClient(BaseGitCodeClient):
|
|
182
|
+
"""Low-level synchronous HTTP transport used by resource classes.
|
|
183
|
+
|
|
184
|
+
:param api_key: Personal access token for the GitCode API.
|
|
185
|
+
:param owner: Default repository owner for repository-scoped calls.
|
|
186
|
+
:param repo: Default repository name for repository-scoped calls.
|
|
187
|
+
:param base_url: Base URL for the GitCode REST API.
|
|
188
|
+
:param timeout: Request timeout in seconds.
|
|
189
|
+
:param http_client: Optional pre-configured ``httpx.Client`` instance.
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
def __init__(
|
|
193
|
+
self,
|
|
194
|
+
*,
|
|
195
|
+
api_key: str | None = None,
|
|
196
|
+
owner: str | None = None,
|
|
197
|
+
repo: str | None = None,
|
|
198
|
+
base_url: str = DEFAULT_BASE_URL,
|
|
199
|
+
timeout: float | None = None,
|
|
200
|
+
http_client: httpx.Client | None = None,
|
|
201
|
+
) -> None:
|
|
202
|
+
"""Create or reuse an ``httpx.Client`` for synchronous requests."""
|
|
203
|
+
super().__init__(api_key=api_key, owner=owner, repo=repo, base_url=base_url, timeout=timeout)
|
|
204
|
+
self._owns_client = http_client is None
|
|
205
|
+
self._client = http_client or httpx.Client(timeout=self.timeout)
|
|
206
|
+
|
|
207
|
+
def request(
|
|
208
|
+
self,
|
|
209
|
+
method: str,
|
|
210
|
+
path: str,
|
|
211
|
+
*,
|
|
212
|
+
params: dict[str, Any] | None = None,
|
|
213
|
+
json: Any = None,
|
|
214
|
+
data: dict[str, Any] | None = None,
|
|
215
|
+
headers: dict[str, str] | None = None,
|
|
216
|
+
raw: bool = False,
|
|
217
|
+
) -> Any:
|
|
218
|
+
"""Send an HTTP request to the GitCode API and parse the response.
|
|
219
|
+
|
|
220
|
+
:param method: HTTP method such as ``"GET"`` or ``"POST"``.
|
|
221
|
+
:param path: Relative API path or absolute URL.
|
|
222
|
+
:param params: Optional query parameters.
|
|
223
|
+
:param json: Optional JSON request body.
|
|
224
|
+
:param data: Optional form payload.
|
|
225
|
+
:param headers: Optional extra HTTP headers.
|
|
226
|
+
:param raw: When ``True``, return response bytes instead of parsed JSON.
|
|
227
|
+
:returns: Parsed JSON payload, raw bytes, text, or ``None``.
|
|
228
|
+
"""
|
|
229
|
+
clean_params, clean_json, clean_data = self._coerce_payload(params=params, json=json, data=data)
|
|
230
|
+
response = self._client.request(
|
|
231
|
+
method,
|
|
232
|
+
self._full_url(path),
|
|
233
|
+
params=clean_params,
|
|
234
|
+
json=clean_json,
|
|
235
|
+
data=clean_data,
|
|
236
|
+
headers=self._headers(headers),
|
|
237
|
+
)
|
|
238
|
+
return self._parse_response(response, raw=raw)
|
|
239
|
+
|
|
240
|
+
def close(self) -> None:
|
|
241
|
+
"""Close the underlying HTTP client if this instance created it."""
|
|
242
|
+
if self._owns_client:
|
|
243
|
+
self._client.close()
|
|
244
|
+
|
|
245
|
+
def __enter__(self) -> "SyncAPIClient":
|
|
246
|
+
"""Enter a context manager and return the client instance."""
|
|
247
|
+
return self
|
|
248
|
+
|
|
249
|
+
def __exit__(self, exc_type: Any, exc: Any, tb: Any) -> None:
|
|
250
|
+
"""Close the client when leaving a context manager."""
|
|
251
|
+
self.close()
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
class AsyncAPIClient(BaseGitCodeClient):
|
|
255
|
+
"""Low-level asynchronous HTTP transport used by async resource classes.
|
|
256
|
+
|
|
257
|
+
:param api_key: Personal access token for the GitCode API.
|
|
258
|
+
:param owner: Default repository owner for repository-scoped calls.
|
|
259
|
+
:param repo: Default repository name for repository-scoped calls.
|
|
260
|
+
:param base_url: Base URL for the GitCode REST API.
|
|
261
|
+
:param timeout: Request timeout in seconds.
|
|
262
|
+
:param http_client: Optional pre-configured ``httpx.AsyncClient`` instance.
|
|
263
|
+
"""
|
|
264
|
+
|
|
265
|
+
def __init__(
|
|
266
|
+
self,
|
|
267
|
+
*,
|
|
268
|
+
api_key: str | None = None,
|
|
269
|
+
owner: str | None = None,
|
|
270
|
+
repo: str | None = None,
|
|
271
|
+
base_url: str = DEFAULT_BASE_URL,
|
|
272
|
+
timeout: float | None = None,
|
|
273
|
+
http_client: httpx.AsyncClient | None = None,
|
|
274
|
+
) -> None:
|
|
275
|
+
"""Create or reuse an ``httpx.AsyncClient`` for asynchronous requests."""
|
|
276
|
+
super().__init__(api_key=api_key, owner=owner, repo=repo, base_url=base_url, timeout=timeout)
|
|
277
|
+
self._owns_client = http_client is None
|
|
278
|
+
self._client = http_client or httpx.AsyncClient(timeout=self.timeout)
|
|
279
|
+
|
|
280
|
+
async def request(
|
|
281
|
+
self,
|
|
282
|
+
method: str,
|
|
283
|
+
path: str,
|
|
284
|
+
*,
|
|
285
|
+
params: dict[str, Any] | None = None,
|
|
286
|
+
json: Any = None,
|
|
287
|
+
data: dict[str, Any] | None = None,
|
|
288
|
+
headers: dict[str, str] | None = None,
|
|
289
|
+
raw: bool = False,
|
|
290
|
+
) -> Any:
|
|
291
|
+
"""Send an asynchronous HTTP request to the GitCode API.
|
|
292
|
+
|
|
293
|
+
:param method: HTTP method such as ``"GET"`` or ``"POST"``.
|
|
294
|
+
:param path: Relative API path or absolute URL.
|
|
295
|
+
:param params: Optional query parameters.
|
|
296
|
+
:param json: Optional JSON request body.
|
|
297
|
+
:param data: Optional form payload.
|
|
298
|
+
:param headers: Optional extra HTTP headers.
|
|
299
|
+
:param raw: When ``True``, return response bytes instead of parsed JSON.
|
|
300
|
+
:returns: Parsed JSON payload, raw bytes, text, or ``None``.
|
|
301
|
+
"""
|
|
302
|
+
clean_params, clean_json, clean_data = self._coerce_payload(params=params, json=json, data=data)
|
|
303
|
+
response = await self._client.request(
|
|
304
|
+
method,
|
|
305
|
+
self._full_url(path),
|
|
306
|
+
params=clean_params,
|
|
307
|
+
json=clean_json,
|
|
308
|
+
data=clean_data,
|
|
309
|
+
headers=self._headers(headers),
|
|
310
|
+
)
|
|
311
|
+
return self._parse_response(response, raw=raw)
|
|
312
|
+
|
|
313
|
+
async def close(self) -> None:
|
|
314
|
+
"""Close the underlying async HTTP client if this instance created it."""
|
|
315
|
+
if self._owns_client:
|
|
316
|
+
await self._client.aclose()
|
|
317
|
+
|
|
318
|
+
async def __aenter__(self) -> "AsyncAPIClient":
|
|
319
|
+
"""Enter an async context manager and return the client instance."""
|
|
320
|
+
return self
|
|
321
|
+
|
|
322
|
+
async def __aexit__(self, exc_type: Any, exc: Any, tb: Any) -> None:
|
|
323
|
+
"""Close the client when leaving an async context manager."""
|
|
324
|
+
await self.close()
|
gitcode_api/_client.py
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"""Top-level synchronous and asynchronous GitCode API clients.
|
|
2
|
+
|
|
3
|
+
These client classes expose grouped resource helpers that mirror the
|
|
4
|
+
published GitCode REST API documentation.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import httpx
|
|
8
|
+
|
|
9
|
+
from ._base_client import DEFAULT_BASE_URL, AsyncAPIClient, SyncAPIClient
|
|
10
|
+
from .resources import (
|
|
11
|
+
AsyncBranchesResource,
|
|
12
|
+
AsyncCommitsResource,
|
|
13
|
+
AsyncIssuesResource,
|
|
14
|
+
AsyncLabelsResource,
|
|
15
|
+
AsyncMembersResource,
|
|
16
|
+
AsyncMilestonesResource,
|
|
17
|
+
AsyncOAuthResource,
|
|
18
|
+
AsyncOrgsResource,
|
|
19
|
+
AsyncPullsResource,
|
|
20
|
+
AsyncReleasesResource,
|
|
21
|
+
AsyncRepoContentsResource,
|
|
22
|
+
AsyncReposResource,
|
|
23
|
+
AsyncSearchResource,
|
|
24
|
+
AsyncTagsResource,
|
|
25
|
+
AsyncUsersResource,
|
|
26
|
+
AsyncWebhooksResource,
|
|
27
|
+
BranchesResource,
|
|
28
|
+
CommitsResource,
|
|
29
|
+
IssuesResource,
|
|
30
|
+
LabelsResource,
|
|
31
|
+
MembersResource,
|
|
32
|
+
MilestonesResource,
|
|
33
|
+
OAuthResource,
|
|
34
|
+
OrgsResource,
|
|
35
|
+
PullsResource,
|
|
36
|
+
ReleasesResource,
|
|
37
|
+
RepoContentsResource,
|
|
38
|
+
ReposResource,
|
|
39
|
+
SearchResource,
|
|
40
|
+
TagsResource,
|
|
41
|
+
UsersResource,
|
|
42
|
+
WebhooksResource,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class GitCode(SyncAPIClient):
|
|
47
|
+
"""Synchronous GitCode API client.
|
|
48
|
+
|
|
49
|
+
:param api_key: Personal access token used for GitCode API requests.
|
|
50
|
+
:param owner: Default repository owner used by repository-scoped helpers.
|
|
51
|
+
:param repo: Default repository name used by repository-scoped helpers.
|
|
52
|
+
:param base_url: Base URL for the GitCode REST API.
|
|
53
|
+
:param timeout: Request timeout in seconds.
|
|
54
|
+
:param http_client: Optional pre-configured ``httpx.Client`` instance.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
repos: ReposResource
|
|
58
|
+
"""Repository endpoints exposed as ``client.repos``."""
|
|
59
|
+
|
|
60
|
+
contents: RepoContentsResource
|
|
61
|
+
"""Repository content endpoints exposed as ``client.contents``."""
|
|
62
|
+
|
|
63
|
+
branches: BranchesResource
|
|
64
|
+
"""Repository branch endpoints exposed as ``client.branches``."""
|
|
65
|
+
|
|
66
|
+
commits: CommitsResource
|
|
67
|
+
"""Repository commit endpoints exposed as ``client.commits``."""
|
|
68
|
+
|
|
69
|
+
issues: IssuesResource
|
|
70
|
+
"""Issue endpoints exposed as ``client.issues``."""
|
|
71
|
+
|
|
72
|
+
pulls: PullsResource
|
|
73
|
+
"""Pull request endpoints exposed as ``client.pulls``."""
|
|
74
|
+
|
|
75
|
+
labels: LabelsResource
|
|
76
|
+
"""Label endpoints exposed as ``client.labels``."""
|
|
77
|
+
|
|
78
|
+
milestones: MilestonesResource
|
|
79
|
+
"""Milestone endpoints exposed as ``client.milestones``."""
|
|
80
|
+
|
|
81
|
+
members: MembersResource
|
|
82
|
+
"""Repository member endpoints exposed as ``client.members``."""
|
|
83
|
+
|
|
84
|
+
releases: ReleasesResource
|
|
85
|
+
"""Release endpoints exposed as ``client.releases``."""
|
|
86
|
+
|
|
87
|
+
tags: TagsResource
|
|
88
|
+
"""Tag endpoints exposed as ``client.tags``."""
|
|
89
|
+
|
|
90
|
+
webhooks: WebhooksResource
|
|
91
|
+
"""Webhook endpoints exposed as ``client.webhooks``."""
|
|
92
|
+
|
|
93
|
+
users: UsersResource
|
|
94
|
+
"""User endpoints exposed as ``client.users``."""
|
|
95
|
+
|
|
96
|
+
orgs: OrgsResource
|
|
97
|
+
"""Organization endpoints exposed as ``client.orgs``."""
|
|
98
|
+
|
|
99
|
+
search: SearchResource
|
|
100
|
+
"""Search endpoints exposed as ``client.search``."""
|
|
101
|
+
|
|
102
|
+
oauth: OAuthResource
|
|
103
|
+
"""OAuth helper endpoints exposed as ``client.oauth``."""
|
|
104
|
+
|
|
105
|
+
def __init__(
|
|
106
|
+
self,
|
|
107
|
+
*,
|
|
108
|
+
api_key: str | None = None,
|
|
109
|
+
owner: str | None = None,
|
|
110
|
+
repo: str | None = None,
|
|
111
|
+
base_url: str = DEFAULT_BASE_URL,
|
|
112
|
+
timeout: float | None = None,
|
|
113
|
+
http_client: httpx.Client | None = None,
|
|
114
|
+
) -> None:
|
|
115
|
+
"""Create a synchronous client and attach resource groups."""
|
|
116
|
+
super().__init__(
|
|
117
|
+
api_key=api_key,
|
|
118
|
+
owner=owner,
|
|
119
|
+
repo=repo,
|
|
120
|
+
base_url=base_url,
|
|
121
|
+
timeout=timeout,
|
|
122
|
+
http_client=http_client,
|
|
123
|
+
)
|
|
124
|
+
self.repos = ReposResource(self)
|
|
125
|
+
self.contents = RepoContentsResource(self)
|
|
126
|
+
self.branches = BranchesResource(self)
|
|
127
|
+
self.commits = CommitsResource(self)
|
|
128
|
+
self.issues = IssuesResource(self)
|
|
129
|
+
self.pulls = PullsResource(self)
|
|
130
|
+
self.labels = LabelsResource(self)
|
|
131
|
+
self.milestones = MilestonesResource(self)
|
|
132
|
+
self.members = MembersResource(self)
|
|
133
|
+
self.releases = ReleasesResource(self)
|
|
134
|
+
self.tags = TagsResource(self)
|
|
135
|
+
self.webhooks = WebhooksResource(self)
|
|
136
|
+
self.users = UsersResource(self)
|
|
137
|
+
self.orgs = OrgsResource(self)
|
|
138
|
+
self.search = SearchResource(self)
|
|
139
|
+
self.oauth = OAuthResource(self)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class AsyncGitCode(AsyncAPIClient):
|
|
143
|
+
"""Asynchronous GitCode API client.
|
|
144
|
+
|
|
145
|
+
:param api_key: Personal access token used for GitCode API requests.
|
|
146
|
+
:param owner: Default repository owner used by repository-scoped helpers.
|
|
147
|
+
:param repo: Default repository name used by repository-scoped helpers.
|
|
148
|
+
:param base_url: Base URL for the GitCode REST API.
|
|
149
|
+
:param timeout: Request timeout in seconds.
|
|
150
|
+
:param http_client: Optional pre-configured ``httpx.AsyncClient`` instance.
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
repos: AsyncReposResource
|
|
154
|
+
"""Repository endpoints exposed as ``client.repos``."""
|
|
155
|
+
|
|
156
|
+
contents: AsyncRepoContentsResource
|
|
157
|
+
"""Repository content endpoints exposed as ``client.contents``."""
|
|
158
|
+
|
|
159
|
+
branches: AsyncBranchesResource
|
|
160
|
+
"""Repository branch endpoints exposed as ``client.branches``."""
|
|
161
|
+
|
|
162
|
+
commits: AsyncCommitsResource
|
|
163
|
+
"""Repository commit endpoints exposed as ``client.commits``."""
|
|
164
|
+
|
|
165
|
+
issues: AsyncIssuesResource
|
|
166
|
+
"""Issue endpoints exposed as ``client.issues``."""
|
|
167
|
+
|
|
168
|
+
pulls: AsyncPullsResource
|
|
169
|
+
"""Pull request endpoints exposed as ``client.pulls``."""
|
|
170
|
+
|
|
171
|
+
labels: AsyncLabelsResource
|
|
172
|
+
"""Label endpoints exposed as ``client.labels``."""
|
|
173
|
+
|
|
174
|
+
milestones: AsyncMilestonesResource
|
|
175
|
+
"""Milestone endpoints exposed as ``client.milestones``."""
|
|
176
|
+
|
|
177
|
+
members: AsyncMembersResource
|
|
178
|
+
"""Repository member endpoints exposed as ``client.members``."""
|
|
179
|
+
|
|
180
|
+
releases: AsyncReleasesResource
|
|
181
|
+
"""Release endpoints exposed as ``client.releases``."""
|
|
182
|
+
|
|
183
|
+
tags: AsyncTagsResource
|
|
184
|
+
"""Tag endpoints exposed as ``client.tags``."""
|
|
185
|
+
|
|
186
|
+
webhooks: AsyncWebhooksResource
|
|
187
|
+
"""Webhook endpoints exposed as ``client.webhooks``."""
|
|
188
|
+
|
|
189
|
+
users: AsyncUsersResource
|
|
190
|
+
"""User endpoints exposed as ``client.users``."""
|
|
191
|
+
|
|
192
|
+
orgs: AsyncOrgsResource
|
|
193
|
+
"""Organization endpoints exposed as ``client.orgs``."""
|
|
194
|
+
|
|
195
|
+
search: AsyncSearchResource
|
|
196
|
+
"""Search endpoints exposed as ``client.search``."""
|
|
197
|
+
|
|
198
|
+
oauth: AsyncOAuthResource
|
|
199
|
+
"""OAuth helper endpoints exposed as ``client.oauth``."""
|
|
200
|
+
|
|
201
|
+
def __init__(
|
|
202
|
+
self,
|
|
203
|
+
*,
|
|
204
|
+
api_key: str | None = None,
|
|
205
|
+
owner: str | None = None,
|
|
206
|
+
repo: str | None = None,
|
|
207
|
+
base_url: str = DEFAULT_BASE_URL,
|
|
208
|
+
timeout: float | None = None,
|
|
209
|
+
http_client: httpx.AsyncClient | None = None,
|
|
210
|
+
) -> None:
|
|
211
|
+
"""Create an asynchronous client and attach resource groups."""
|
|
212
|
+
super().__init__(
|
|
213
|
+
api_key=api_key,
|
|
214
|
+
owner=owner,
|
|
215
|
+
repo=repo,
|
|
216
|
+
base_url=base_url,
|
|
217
|
+
timeout=timeout,
|
|
218
|
+
http_client=http_client,
|
|
219
|
+
)
|
|
220
|
+
self.repos = AsyncReposResource(self)
|
|
221
|
+
self.contents = AsyncRepoContentsResource(self)
|
|
222
|
+
self.branches = AsyncBranchesResource(self)
|
|
223
|
+
self.commits = AsyncCommitsResource(self)
|
|
224
|
+
self.issues = AsyncIssuesResource(self)
|
|
225
|
+
self.pulls = AsyncPullsResource(self)
|
|
226
|
+
self.labels = AsyncLabelsResource(self)
|
|
227
|
+
self.milestones = AsyncMilestonesResource(self)
|
|
228
|
+
self.members = AsyncMembersResource(self)
|
|
229
|
+
self.releases = AsyncReleasesResource(self)
|
|
230
|
+
self.tags = AsyncTagsResource(self)
|
|
231
|
+
self.webhooks = AsyncWebhooksResource(self)
|
|
232
|
+
self.users = AsyncUsersResource(self)
|
|
233
|
+
self.orgs = AsyncOrgsResource(self)
|
|
234
|
+
self.search = AsyncSearchResource(self)
|
|
235
|
+
self.oauth = AsyncOAuthResource(self)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Custom exceptions raised by the GitCode SDK."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class GitCodeError(Exception):
|
|
7
|
+
"""Base exception for all GitCode SDK errors."""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class GitCodeConfigurationError(GitCodeError):
|
|
11
|
+
"""Raised when client configuration is incomplete or invalid."""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class GitCodeAPIError(GitCodeError):
|
|
15
|
+
"""Raised when the GitCode API returns an error response.
|
|
16
|
+
|
|
17
|
+
:param message: Human-readable error message.
|
|
18
|
+
:param status_code: HTTP status code returned by the API.
|
|
19
|
+
:param request_id: Optional GitCode request identifier.
|
|
20
|
+
:param payload: Parsed error payload when available.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
message: str,
|
|
26
|
+
*,
|
|
27
|
+
status_code: int,
|
|
28
|
+
request_id: str | None = None,
|
|
29
|
+
payload: Any = None,
|
|
30
|
+
) -> None:
|
|
31
|
+
"""Store structured error metadata from a failed API response."""
|
|
32
|
+
super().__init__(message)
|
|
33
|
+
self.status_code = status_code
|
|
34
|
+
self.request_id = request_id
|
|
35
|
+
self.payload = payload
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class GitCodeHTTPStatusError(GitCodeAPIError):
|
|
39
|
+
"""Raised for non-success HTTP responses from the GitCode API."""
|