gitcode-api 1.2.12__py3-none-any.whl → 1.2.14__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 +2 -0
- gitcode_api/_models.py +71 -55
- gitcode_api/llm/openai.py +1 -0
- gitcode_api/resources/_shared.py +307 -1
- gitcode_api/resources/collaboration.py +225 -1
- gitcode_api/resources/misc.py +342 -19
- gitcode_api/utils.py +37 -0
- gitcode_api/version.txt +1 -1
- {gitcode_api-1.2.12.dist-info → gitcode_api-1.2.14.dist-info}/METADATA +22 -2
- {gitcode_api-1.2.12.dist-info → gitcode_api-1.2.14.dist-info}/RECORD +14 -13
- {gitcode_api-1.2.12.dist-info → gitcode_api-1.2.14.dist-info}/WHEEL +0 -0
- {gitcode_api-1.2.12.dist-info → gitcode_api-1.2.14.dist-info}/entry_points.txt +0 -0
- {gitcode_api-1.2.12.dist-info → gitcode_api-1.2.14.dist-info}/licenses/LICENSE +0 -0
- {gitcode_api-1.2.12.dist-info → gitcode_api-1.2.14.dist-info}/top_level.txt +0 -0
gitcode_api/__init__.py
CHANGED
|
@@ -9,6 +9,7 @@ from ._exceptions import (
|
|
|
9
9
|
GitCodeError,
|
|
10
10
|
GitCodeHTTPStatusError,
|
|
11
11
|
)
|
|
12
|
+
from .utils import as_dict
|
|
12
13
|
|
|
13
14
|
__version__ = (Path(__file__).parent / "version.txt").read_text().strip()
|
|
14
15
|
|
|
@@ -20,4 +21,5 @@ __all__ = [
|
|
|
20
21
|
"GitCodeConfigurationError",
|
|
21
22
|
"GitCodeError",
|
|
22
23
|
"GitCodeHTTPStatusError",
|
|
24
|
+
"as_dict",
|
|
23
25
|
]
|
gitcode_api/_models.py
CHANGED
|
@@ -9,7 +9,6 @@ from typing import (
|
|
|
9
9
|
Mapping,
|
|
10
10
|
MutableMapping,
|
|
11
11
|
Optional,
|
|
12
|
-
TypedDict,
|
|
13
12
|
TypeVar,
|
|
14
13
|
Union,
|
|
15
14
|
get_args,
|
|
@@ -136,60 +135,6 @@ def as_model_list(data: List[Mapping[str, Any]], model_type: type[ModelT]) -> Li
|
|
|
136
135
|
return [as_model(item, model_type) for item in data]
|
|
137
136
|
|
|
138
137
|
|
|
139
|
-
class RepositoryCreateParams(TypedDict, total=False):
|
|
140
|
-
"""Typed fields accepted by repository creation endpoints."""
|
|
141
|
-
|
|
142
|
-
name: str
|
|
143
|
-
description: str
|
|
144
|
-
has_issues: bool
|
|
145
|
-
has_wiki: bool
|
|
146
|
-
auto_init: bool
|
|
147
|
-
gitignore_template: str
|
|
148
|
-
license_template: str
|
|
149
|
-
path: str
|
|
150
|
-
private: bool
|
|
151
|
-
public: int
|
|
152
|
-
default_branch: str
|
|
153
|
-
homepage: str
|
|
154
|
-
can_comment: bool
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
class IssueCreateParams(TypedDict, total=False):
|
|
158
|
-
"""Typed fields accepted by issue creation endpoints."""
|
|
159
|
-
|
|
160
|
-
title: str
|
|
161
|
-
body: str
|
|
162
|
-
assignee: str
|
|
163
|
-
labels: List[str]
|
|
164
|
-
milestone: Union[int, str]
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
class PullRequestCreateParams(TypedDict, total=False):
|
|
168
|
-
"""Typed fields accepted by pull request creation endpoints."""
|
|
169
|
-
|
|
170
|
-
title: str
|
|
171
|
-
body: str
|
|
172
|
-
head: str
|
|
173
|
-
base: str
|
|
174
|
-
assignees: List[str]
|
|
175
|
-
testers: List[str]
|
|
176
|
-
labels: List[str]
|
|
177
|
-
draft: bool
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
class WebhookCreateParams(TypedDict, total=False):
|
|
181
|
-
"""Typed fields accepted by webhook creation endpoints."""
|
|
182
|
-
|
|
183
|
-
url: str
|
|
184
|
-
encryption_type: int
|
|
185
|
-
password: str
|
|
186
|
-
push_events: bool
|
|
187
|
-
tag_push_events: bool
|
|
188
|
-
issues_events: bool
|
|
189
|
-
note_events: bool
|
|
190
|
-
merge_requests_events: bool
|
|
191
|
-
|
|
192
|
-
|
|
193
138
|
@dataclass(init=False)
|
|
194
139
|
class UserRef(APIObject):
|
|
195
140
|
"""Compact user payload embedded in other responses.
|
|
@@ -513,6 +458,8 @@ class Repository(APIObject):
|
|
|
513
458
|
:vartype relation: Optional[str]
|
|
514
459
|
:ivar members: Members returned in the repository payload.
|
|
515
460
|
:vartype members: Optional[List[str]]
|
|
461
|
+
:ivar parent: Upstream source repository information
|
|
462
|
+
:vartype parent: Optional[Dict[str, Any]]
|
|
516
463
|
:ivar permission: Permission summary for this object.
|
|
517
464
|
:vartype permission: Optional[RepositoryPermission]
|
|
518
465
|
:ivar enterprise: Enterprise associated with the repository.
|
|
@@ -566,6 +513,7 @@ class Repository(APIObject):
|
|
|
566
513
|
status: Optional[str] = None
|
|
567
514
|
relation: Optional[str] = None
|
|
568
515
|
members: Optional[List[str]] = None
|
|
516
|
+
parent: Optional[Dict[str, Any]] = None
|
|
569
517
|
permission: Optional[RepositoryPermission] = None
|
|
570
518
|
enterprise: Optional[Union[EnterpriseRef, str]] = None
|
|
571
519
|
issue_template_source: Optional[str] = None
|
|
@@ -760,6 +708,31 @@ class ContentObject(APIObject):
|
|
|
760
708
|
_links: Optional[ContentLinks] = None
|
|
761
709
|
|
|
762
710
|
|
|
711
|
+
@dataclass(init=False)
|
|
712
|
+
class RepositoryGitCodeTemplate(APIObject):
|
|
713
|
+
"""Metadata for a ``.gitcode`` issue or pull request template file.
|
|
714
|
+
|
|
715
|
+
Returned by :meth:`~gitcode_api.resources.collaboration.IssuesResource.list_templates`
|
|
716
|
+
and :meth:`~gitcode_api.resources.collaboration.PullsResource.list_templates`. Use
|
|
717
|
+
:meth:`~gitcode_api.resources.collaboration.IssuesResource.get_template` or
|
|
718
|
+
:meth:`~gitcode_api.resources.collaboration.PullsResource.get_template` to load the body.
|
|
719
|
+
|
|
720
|
+
:ivar path: Repository-relative path (under ``.gitcode/``).
|
|
721
|
+
:vartype path: Optional[str]
|
|
722
|
+
:ivar sha: Object SHA for the file.
|
|
723
|
+
:vartype sha: Optional[str]
|
|
724
|
+
:ivar template_owner: Owner path of the repository the template was resolved from.
|
|
725
|
+
:vartype template_owner: Optional[str]
|
|
726
|
+
:ivar template_repo: Repository name the template was resolved from.
|
|
727
|
+
:vartype template_repo: Optional[str]
|
|
728
|
+
"""
|
|
729
|
+
|
|
730
|
+
path: Optional[str] = None
|
|
731
|
+
sha: Optional[str] = None
|
|
732
|
+
template_owner: Optional[str] = None
|
|
733
|
+
template_repo: Optional[str] = None
|
|
734
|
+
|
|
735
|
+
|
|
763
736
|
@dataclass(init=False)
|
|
764
737
|
class CommitIdentity(APIObject):
|
|
765
738
|
"""Commit author/committer identity.
|
|
@@ -2171,6 +2144,23 @@ class RepoMemberPermission(APIObject):
|
|
|
2171
2144
|
permission: Optional[str] = None
|
|
2172
2145
|
|
|
2173
2146
|
|
|
2147
|
+
@dataclass(init=False)
|
|
2148
|
+
class ReleaseAsset(APIObject):
|
|
2149
|
+
"""Asset metadata embedded in release payloads.
|
|
2150
|
+
|
|
2151
|
+
:ivar browser_download_url: Browser download URL for this asset.
|
|
2152
|
+
:vartype browser_download_url: Optional[str]
|
|
2153
|
+
:ivar name: Asset file name.
|
|
2154
|
+
:vartype name: Optional[str]
|
|
2155
|
+
:ivar type: Asset media type.
|
|
2156
|
+
:vartype type: Optional[str]
|
|
2157
|
+
"""
|
|
2158
|
+
|
|
2159
|
+
browser_download_url: Optional[str] = None
|
|
2160
|
+
name: Optional[str] = None
|
|
2161
|
+
type: Optional[str] = None
|
|
2162
|
+
|
|
2163
|
+
|
|
2174
2164
|
@dataclass(init=False)
|
|
2175
2165
|
class Release(APIObject):
|
|
2176
2166
|
"""Release payload.
|
|
@@ -2179,6 +2169,10 @@ class Release(APIObject):
|
|
|
2179
2169
|
:vartype id: Optional[Union[int, str]]
|
|
2180
2170
|
:ivar tag_name: Tag name.
|
|
2181
2171
|
:vartype tag_name: Optional[str]
|
|
2172
|
+
:ivar target_commitish: Branch or commit SHA targeted by the release tag.
|
|
2173
|
+
:vartype target_commitish: Optional[str]
|
|
2174
|
+
:ivar prerelease: Whether this release is a pre-release.
|
|
2175
|
+
:vartype prerelease: Optional[bool]
|
|
2182
2176
|
:ivar name: Display name.
|
|
2183
2177
|
:vartype name: Optional[str]
|
|
2184
2178
|
:ivar body: Body text of the object.
|
|
@@ -2191,16 +2185,38 @@ class Release(APIObject):
|
|
|
2191
2185
|
:vartype published_at: Optional[str]
|
|
2192
2186
|
:ivar html_url: Web URL for this object.
|
|
2193
2187
|
:vartype html_url: Optional[str]
|
|
2188
|
+
:ivar assets: Release source packages and uploaded attachments.
|
|
2189
|
+
:vartype assets: Optional[List[ReleaseAsset]]
|
|
2190
|
+
:ivar release_status: Release status, for example ``pre`` or ``latest``.
|
|
2191
|
+
:vartype release_status: Optional[str]
|
|
2194
2192
|
"""
|
|
2195
2193
|
|
|
2196
2194
|
id: Optional[Union[int, str]] = None
|
|
2197
2195
|
tag_name: Optional[str] = None
|
|
2196
|
+
target_commitish: Optional[str] = None
|
|
2197
|
+
prerelease: Optional[bool] = None
|
|
2198
2198
|
name: Optional[str] = None
|
|
2199
2199
|
body: Optional[str] = None
|
|
2200
2200
|
author: Optional[UserRef] = None
|
|
2201
2201
|
created_at: Optional[str] = None
|
|
2202
2202
|
published_at: Optional[str] = None
|
|
2203
2203
|
html_url: Optional[str] = None
|
|
2204
|
+
assets: Optional[List[ReleaseAsset]] = None
|
|
2205
|
+
release_status: Optional[str] = None
|
|
2206
|
+
|
|
2207
|
+
|
|
2208
|
+
@dataclass(init=False)
|
|
2209
|
+
class ReleaseUploadURL(APIObject):
|
|
2210
|
+
"""Pre-signed release attachment upload target.
|
|
2211
|
+
|
|
2212
|
+
:ivar url: Pre-signed object storage URL for uploading with ``PUT``.
|
|
2213
|
+
:vartype url: Optional[str]
|
|
2214
|
+
:ivar headers: Headers to send unchanged with the upload request.
|
|
2215
|
+
:vartype headers: Optional[Dict[str, str]]
|
|
2216
|
+
"""
|
|
2217
|
+
|
|
2218
|
+
url: Optional[str] = None
|
|
2219
|
+
headers: Optional[Dict[str, str]] = None
|
|
2204
2220
|
|
|
2205
2221
|
|
|
2206
2222
|
@dataclass(init=False)
|
gitcode_api/llm/openai.py
CHANGED
|
@@ -75,6 +75,7 @@ class GitCodeOpenAITool(GitCodeLLMTool):
|
|
|
75
75
|
return self.tool
|
|
76
76
|
|
|
77
77
|
async def __async_call__(self, *args, **kwargs) -> str:
|
|
78
|
+
"""Invoke the configured async tool callable."""
|
|
78
79
|
result = await super().__async_call__(*args, **kwargs)
|
|
79
80
|
return json.dumps(result, ensure_ascii=False, indent=self.indent)
|
|
80
81
|
|
gitcode_api/resources/_shared.py
CHANGED
|
@@ -1,11 +1,317 @@
|
|
|
1
1
|
"""Shared resource base classes for the GitCode SDK."""
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import re
|
|
4
|
+
from typing import Any, Dict, List, Optional, Pattern, Tuple, Union
|
|
4
5
|
|
|
5
6
|
from .._base_client import AsyncAPIClient, SyncAPIClient
|
|
6
7
|
from .._base_resource import BaseResource
|
|
8
|
+
from .._exceptions import GitCodeHTTPStatusError
|
|
7
9
|
from .._models import APIObject, ModelT, as_model, as_model_list
|
|
8
10
|
|
|
11
|
+
GITCODE_ISSUE_TEMPLATE_PATH_RE: Pattern[str] = re.compile(
|
|
12
|
+
r"\.gitcode/ISSUE_TEMPLATE.*\.(md|markdown|ya?ml)$", re.IGNORECASE
|
|
13
|
+
)
|
|
14
|
+
GITCODE_PULL_REQUEST_TEMPLATE_PATH_RE: Pattern[str] = re.compile(
|
|
15
|
+
r"\.gitcode/PULL_REQUEST_TEMPLATE.*\.(md|markdown|ya?ml)$", re.IGNORECASE
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _parse_parent_owner_repo(repo_obj: Any) -> Optional[Tuple[str, str]]:
|
|
20
|
+
parent = getattr(repo_obj, "parent", None)
|
|
21
|
+
if parent is None and hasattr(repo_obj, "get"):
|
|
22
|
+
parent = repo_obj.get("parent")
|
|
23
|
+
if not isinstance(parent, dict):
|
|
24
|
+
return None
|
|
25
|
+
full = str(parent.get("full_name") or "").strip()
|
|
26
|
+
if "/" not in full:
|
|
27
|
+
return None
|
|
28
|
+
owner_path, name = full.rsplit("/", 1)
|
|
29
|
+
owner_path, name = owner_path.strip(), name.strip()
|
|
30
|
+
if not owner_path or not name:
|
|
31
|
+
return None
|
|
32
|
+
return owner_path, name
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _resolution_sources_sync(client: SyncAPIClient, owner: str, repo: str) -> List[Tuple[str, str]]:
|
|
36
|
+
"""Build ordered repo candidates.
|
|
37
|
+
|
|
38
|
+
Starts with ``(owner, repo)`` and ``(owner, ".gitcode")``. For every candidate that is a
|
|
39
|
+
fork (per ``GET /repos/{owner}/{repo}``), appends that repository's parent main repo and
|
|
40
|
+
``(parent_owner, ".gitcode")`` when not already listed (deduplicated, breadth-first).
|
|
41
|
+
"""
|
|
42
|
+
from .repositories import ReposResource
|
|
43
|
+
|
|
44
|
+
sources: List[Tuple[str, str]] = []
|
|
45
|
+
seen: set[Tuple[str, str]] = set()
|
|
46
|
+
|
|
47
|
+
def add(pair: Tuple[str, str]) -> None:
|
|
48
|
+
if pair not in seen:
|
|
49
|
+
seen.add(pair)
|
|
50
|
+
sources.append(pair)
|
|
51
|
+
|
|
52
|
+
add((owner, repo))
|
|
53
|
+
add((owner, ".gitcode"))
|
|
54
|
+
|
|
55
|
+
max_candidates = 64
|
|
56
|
+
index = 0
|
|
57
|
+
while index < len(sources) and len(sources) < max_candidates:
|
|
58
|
+
so, sr = sources[index]
|
|
59
|
+
index += 1
|
|
60
|
+
try:
|
|
61
|
+
meta = ReposResource(client).get(owner=so, repo=sr)
|
|
62
|
+
except GitCodeHTTPStatusError:
|
|
63
|
+
continue
|
|
64
|
+
if not getattr(meta, "fork", None):
|
|
65
|
+
continue
|
|
66
|
+
parsed = _parse_parent_owner_repo(meta)
|
|
67
|
+
if not parsed:
|
|
68
|
+
continue
|
|
69
|
+
po, pr = parsed
|
|
70
|
+
add((po, pr))
|
|
71
|
+
add((po, ".gitcode"))
|
|
72
|
+
|
|
73
|
+
return sources
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
async def _resolution_sources_async(client: AsyncAPIClient, owner: str, repo: str) -> List[Tuple[str, str]]:
|
|
77
|
+
"""Async counterpart of :func:`_resolution_sources_sync`."""
|
|
78
|
+
from .repositories import AsyncReposResource
|
|
79
|
+
|
|
80
|
+
sources: List[Tuple[str, str]] = []
|
|
81
|
+
seen: set[Tuple[str, str]] = set()
|
|
82
|
+
|
|
83
|
+
def add(pair: Tuple[str, str]) -> None:
|
|
84
|
+
if pair not in seen:
|
|
85
|
+
seen.add(pair)
|
|
86
|
+
sources.append(pair)
|
|
87
|
+
|
|
88
|
+
add((owner, repo))
|
|
89
|
+
add((owner, ".gitcode"))
|
|
90
|
+
|
|
91
|
+
max_candidates = 64
|
|
92
|
+
index = 0
|
|
93
|
+
while index < len(sources) and len(sources) < max_candidates:
|
|
94
|
+
so, sr = sources[index]
|
|
95
|
+
index += 1
|
|
96
|
+
try:
|
|
97
|
+
meta = await AsyncReposResource(client).get(owner=so, repo=sr)
|
|
98
|
+
except GitCodeHTTPStatusError:
|
|
99
|
+
continue
|
|
100
|
+
if not getattr(meta, "fork", None):
|
|
101
|
+
continue
|
|
102
|
+
parsed = _parse_parent_owner_repo(meta)
|
|
103
|
+
if not parsed:
|
|
104
|
+
continue
|
|
105
|
+
po, pr = parsed
|
|
106
|
+
add((po, pr))
|
|
107
|
+
add((po, ".gitcode"))
|
|
108
|
+
|
|
109
|
+
return sources
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _walk_dot_gitcode_contents_sync(
|
|
113
|
+
client: SyncAPIClient,
|
|
114
|
+
template_owner: str,
|
|
115
|
+
template_repo: str,
|
|
116
|
+
path: str,
|
|
117
|
+
acc: List[Tuple[str, str, str, str]],
|
|
118
|
+
) -> None:
|
|
119
|
+
try:
|
|
120
|
+
data = client.request(
|
|
121
|
+
"GET",
|
|
122
|
+
client._repo_file_path("contents", path, owner=template_owner, repo=template_repo),
|
|
123
|
+
)
|
|
124
|
+
except GitCodeHTTPStatusError as exc:
|
|
125
|
+
if exc.status_code == 404:
|
|
126
|
+
return
|
|
127
|
+
raise
|
|
128
|
+
|
|
129
|
+
if isinstance(data, dict):
|
|
130
|
+
t = (data.get("type") or "").lower()
|
|
131
|
+
if t == "file":
|
|
132
|
+
sha = data.get("sha") or ""
|
|
133
|
+
pth = data.get("path") or path
|
|
134
|
+
if sha and pth:
|
|
135
|
+
acc.append((template_owner, template_repo, str(pth), str(sha)))
|
|
136
|
+
return
|
|
137
|
+
if t in ("dir", "directory", "tree"):
|
|
138
|
+
pth = data.get("path") or path
|
|
139
|
+
_walk_dot_gitcode_contents_sync(client, template_owner, template_repo, pth, acc)
|
|
140
|
+
return
|
|
141
|
+
return
|
|
142
|
+
|
|
143
|
+
if isinstance(data, list):
|
|
144
|
+
for item in data:
|
|
145
|
+
if not isinstance(item, dict):
|
|
146
|
+
continue
|
|
147
|
+
t = (item.get("type") or "").lower()
|
|
148
|
+
pth = item.get("path") or ""
|
|
149
|
+
if t == "file":
|
|
150
|
+
sha = item.get("sha") or ""
|
|
151
|
+
if sha and pth:
|
|
152
|
+
acc.append((template_owner, template_repo, str(pth), str(sha)))
|
|
153
|
+
elif t in ("dir", "directory", "tree") and pth:
|
|
154
|
+
_walk_dot_gitcode_contents_sync(client, template_owner, template_repo, str(pth), acc)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
async def _walk_dot_gitcode_contents_async(
|
|
158
|
+
client: AsyncAPIClient,
|
|
159
|
+
template_owner: str,
|
|
160
|
+
template_repo: str,
|
|
161
|
+
path: str,
|
|
162
|
+
acc: List[Tuple[str, str, str, str]],
|
|
163
|
+
) -> None:
|
|
164
|
+
try:
|
|
165
|
+
data = await client.request(
|
|
166
|
+
"GET",
|
|
167
|
+
client._repo_file_path("contents", path, owner=template_owner, repo=template_repo),
|
|
168
|
+
)
|
|
169
|
+
except GitCodeHTTPStatusError as exc:
|
|
170
|
+
if exc.status_code == 404:
|
|
171
|
+
return
|
|
172
|
+
raise
|
|
173
|
+
|
|
174
|
+
if isinstance(data, dict):
|
|
175
|
+
t = (data.get("type") or "").lower()
|
|
176
|
+
if t == "file":
|
|
177
|
+
sha = data.get("sha") or ""
|
|
178
|
+
pth = data.get("path") or path
|
|
179
|
+
if sha and pth:
|
|
180
|
+
acc.append((template_owner, template_repo, str(pth), str(sha)))
|
|
181
|
+
return
|
|
182
|
+
if t in ("dir", "directory", "tree"):
|
|
183
|
+
pth = data.get("path") or path
|
|
184
|
+
await _walk_dot_gitcode_contents_async(client, template_owner, template_repo, pth, acc)
|
|
185
|
+
return
|
|
186
|
+
return
|
|
187
|
+
|
|
188
|
+
if isinstance(data, list):
|
|
189
|
+
for item in data:
|
|
190
|
+
if not isinstance(item, dict):
|
|
191
|
+
continue
|
|
192
|
+
t = (item.get("type") or "").lower()
|
|
193
|
+
pth = item.get("path") or ""
|
|
194
|
+
if t == "file":
|
|
195
|
+
sha = item.get("sha") or ""
|
|
196
|
+
if sha and pth:
|
|
197
|
+
acc.append((template_owner, template_repo, str(pth), str(sha)))
|
|
198
|
+
elif t in ("dir", "directory", "tree") and pth:
|
|
199
|
+
await _walk_dot_gitcode_contents_async(client, template_owner, template_repo, str(pth), acc)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def list_gitcode_template_rows_sync(
|
|
203
|
+
client: SyncAPIClient,
|
|
204
|
+
owner: str,
|
|
205
|
+
repo: str,
|
|
206
|
+
path_pattern: Pattern[str],
|
|
207
|
+
) -> List[Tuple[str, str, str, str]]:
|
|
208
|
+
"""Return ``(template_owner, template_repo, path, sha)`` from the first resolution source with matches."""
|
|
209
|
+
for so, sr in _resolution_sources_sync(client, owner, repo):
|
|
210
|
+
acc: List[Tuple[str, str, str, str]] = []
|
|
211
|
+
try:
|
|
212
|
+
_walk_dot_gitcode_contents_sync(client, so, sr, ".gitcode", acc)
|
|
213
|
+
except GitCodeHTTPStatusError:
|
|
214
|
+
continue
|
|
215
|
+
rows = [(t_o, t_r, p, s) for t_o, t_r, p, s in acc if path_pattern.match(p)]
|
|
216
|
+
if rows:
|
|
217
|
+
return rows
|
|
218
|
+
return []
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
async def list_gitcode_template_rows_async(
|
|
222
|
+
client: AsyncAPIClient,
|
|
223
|
+
owner: str,
|
|
224
|
+
repo: str,
|
|
225
|
+
path_pattern: Pattern[str],
|
|
226
|
+
) -> List[Tuple[str, str, str, str]]:
|
|
227
|
+
for so, sr in await _resolution_sources_async(client, owner, repo):
|
|
228
|
+
acc: List[Tuple[str, str, str, str]] = []
|
|
229
|
+
try:
|
|
230
|
+
await _walk_dot_gitcode_contents_async(client, so, sr, ".gitcode", acc)
|
|
231
|
+
except GitCodeHTTPStatusError:
|
|
232
|
+
continue
|
|
233
|
+
rows = [(t_o, t_r, p, s) for t_o, t_r, p, s in acc if path_pattern.match(p)]
|
|
234
|
+
if rows:
|
|
235
|
+
return rows
|
|
236
|
+
return []
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def get_gitcode_template_body_sync(
|
|
240
|
+
client: SyncAPIClient,
|
|
241
|
+
path: str,
|
|
242
|
+
path_pattern: Pattern[str],
|
|
243
|
+
owner: str,
|
|
244
|
+
repo: str,
|
|
245
|
+
) -> str:
|
|
246
|
+
"""Fetch raw template text from the first resolution source that serves ``path``."""
|
|
247
|
+
if not path_pattern.match(path):
|
|
248
|
+
raise GitCodeHTTPStatusError(
|
|
249
|
+
"Path does not match the expected GitCode template pattern for this resource.",
|
|
250
|
+
status_code=404,
|
|
251
|
+
payload=None,
|
|
252
|
+
)
|
|
253
|
+
last_error: Optional[GitCodeHTTPStatusError] = None
|
|
254
|
+
for so, sr in _resolution_sources_sync(client, owner, repo):
|
|
255
|
+
try:
|
|
256
|
+
raw = client.request(
|
|
257
|
+
"GET",
|
|
258
|
+
client._repo_file_path("raw", path, owner=so, repo=sr),
|
|
259
|
+
raw=True,
|
|
260
|
+
)
|
|
261
|
+
except GitCodeHTTPStatusError as exc:
|
|
262
|
+
last_error = exc
|
|
263
|
+
continue
|
|
264
|
+
if isinstance(raw, bytes):
|
|
265
|
+
return raw.decode("utf-8")
|
|
266
|
+
if isinstance(raw, str):
|
|
267
|
+
return raw
|
|
268
|
+
return str(raw)
|
|
269
|
+
if last_error is not None:
|
|
270
|
+
raise last_error
|
|
271
|
+
raise GitCodeHTTPStatusError(
|
|
272
|
+
"No template found for the given path.",
|
|
273
|
+
status_code=404,
|
|
274
|
+
payload=None,
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
async def get_gitcode_template_body_async(
|
|
279
|
+
client: AsyncAPIClient,
|
|
280
|
+
path: str,
|
|
281
|
+
path_pattern: Pattern[str],
|
|
282
|
+
owner: str,
|
|
283
|
+
repo: str,
|
|
284
|
+
) -> str:
|
|
285
|
+
if not path_pattern.match(path):
|
|
286
|
+
raise GitCodeHTTPStatusError(
|
|
287
|
+
"Path does not match the expected GitCode template pattern for this resource.",
|
|
288
|
+
status_code=404,
|
|
289
|
+
payload=None,
|
|
290
|
+
)
|
|
291
|
+
last_error: Optional[GitCodeHTTPStatusError] = None
|
|
292
|
+
for so, sr in await _resolution_sources_async(client, owner, repo):
|
|
293
|
+
try:
|
|
294
|
+
raw = await client.request(
|
|
295
|
+
"GET",
|
|
296
|
+
client._repo_file_path("raw", path, owner=so, repo=sr),
|
|
297
|
+
raw=True,
|
|
298
|
+
)
|
|
299
|
+
except GitCodeHTTPStatusError as exc:
|
|
300
|
+
last_error = exc
|
|
301
|
+
continue
|
|
302
|
+
if isinstance(raw, bytes):
|
|
303
|
+
return raw.decode("utf-8")
|
|
304
|
+
if isinstance(raw, str):
|
|
305
|
+
return raw
|
|
306
|
+
return str(raw)
|
|
307
|
+
if last_error is not None:
|
|
308
|
+
raise last_error
|
|
309
|
+
raise GitCodeHTTPStatusError(
|
|
310
|
+
"No template found for the given path.",
|
|
311
|
+
status_code=404,
|
|
312
|
+
payload=None,
|
|
313
|
+
)
|
|
314
|
+
|
|
9
315
|
|
|
10
316
|
class SyncResource(BaseResource):
|
|
11
317
|
"""Base class for synchronous resource groups."""
|