gitcode-api 1.2.11__py3-none-any.whl → 1.2.13__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/_models.py +43 -0
- gitcode_api/cli.py +72 -7
- gitcode_api/resources/misc.py +342 -19
- gitcode_api/run_mcp.py +1 -1
- gitcode_api/version.txt +1 -1
- {gitcode_api-1.2.11.dist-info → gitcode_api-1.2.13.dist-info}/METADATA +6 -4
- {gitcode_api-1.2.11.dist-info → gitcode_api-1.2.13.dist-info}/RECORD +11 -11
- {gitcode_api-1.2.11.dist-info → gitcode_api-1.2.13.dist-info}/WHEEL +0 -0
- {gitcode_api-1.2.11.dist-info → gitcode_api-1.2.13.dist-info}/entry_points.txt +0 -0
- {gitcode_api-1.2.11.dist-info → gitcode_api-1.2.13.dist-info}/licenses/LICENSE +0 -0
- {gitcode_api-1.2.11.dist-info → gitcode_api-1.2.13.dist-info}/top_level.txt +0 -0
gitcode_api/_models.py
CHANGED
|
@@ -2171,6 +2171,23 @@ class RepoMemberPermission(APIObject):
|
|
|
2171
2171
|
permission: Optional[str] = None
|
|
2172
2172
|
|
|
2173
2173
|
|
|
2174
|
+
@dataclass(init=False)
|
|
2175
|
+
class ReleaseAsset(APIObject):
|
|
2176
|
+
"""Asset metadata embedded in release payloads.
|
|
2177
|
+
|
|
2178
|
+
:ivar browser_download_url: Browser download URL for this asset.
|
|
2179
|
+
:vartype browser_download_url: Optional[str]
|
|
2180
|
+
:ivar name: Asset file name.
|
|
2181
|
+
:vartype name: Optional[str]
|
|
2182
|
+
:ivar type: Asset media type.
|
|
2183
|
+
:vartype type: Optional[str]
|
|
2184
|
+
"""
|
|
2185
|
+
|
|
2186
|
+
browser_download_url: Optional[str] = None
|
|
2187
|
+
name: Optional[str] = None
|
|
2188
|
+
type: Optional[str] = None
|
|
2189
|
+
|
|
2190
|
+
|
|
2174
2191
|
@dataclass(init=False)
|
|
2175
2192
|
class Release(APIObject):
|
|
2176
2193
|
"""Release payload.
|
|
@@ -2179,6 +2196,10 @@ class Release(APIObject):
|
|
|
2179
2196
|
:vartype id: Optional[Union[int, str]]
|
|
2180
2197
|
:ivar tag_name: Tag name.
|
|
2181
2198
|
:vartype tag_name: Optional[str]
|
|
2199
|
+
:ivar target_commitish: Branch or commit SHA targeted by the release tag.
|
|
2200
|
+
:vartype target_commitish: Optional[str]
|
|
2201
|
+
:ivar prerelease: Whether this release is a pre-release.
|
|
2202
|
+
:vartype prerelease: Optional[bool]
|
|
2182
2203
|
:ivar name: Display name.
|
|
2183
2204
|
:vartype name: Optional[str]
|
|
2184
2205
|
:ivar body: Body text of the object.
|
|
@@ -2191,16 +2212,38 @@ class Release(APIObject):
|
|
|
2191
2212
|
:vartype published_at: Optional[str]
|
|
2192
2213
|
:ivar html_url: Web URL for this object.
|
|
2193
2214
|
:vartype html_url: Optional[str]
|
|
2215
|
+
:ivar assets: Release source packages and uploaded attachments.
|
|
2216
|
+
:vartype assets: Optional[List[ReleaseAsset]]
|
|
2217
|
+
:ivar release_status: Release status, for example ``pre`` or ``latest``.
|
|
2218
|
+
:vartype release_status: Optional[str]
|
|
2194
2219
|
"""
|
|
2195
2220
|
|
|
2196
2221
|
id: Optional[Union[int, str]] = None
|
|
2197
2222
|
tag_name: Optional[str] = None
|
|
2223
|
+
target_commitish: Optional[str] = None
|
|
2224
|
+
prerelease: Optional[bool] = None
|
|
2198
2225
|
name: Optional[str] = None
|
|
2199
2226
|
body: Optional[str] = None
|
|
2200
2227
|
author: Optional[UserRef] = None
|
|
2201
2228
|
created_at: Optional[str] = None
|
|
2202
2229
|
published_at: Optional[str] = None
|
|
2203
2230
|
html_url: Optional[str] = None
|
|
2231
|
+
assets: Optional[List[ReleaseAsset]] = None
|
|
2232
|
+
release_status: Optional[str] = None
|
|
2233
|
+
|
|
2234
|
+
|
|
2235
|
+
@dataclass(init=False)
|
|
2236
|
+
class ReleaseUploadURL(APIObject):
|
|
2237
|
+
"""Pre-signed release attachment upload target.
|
|
2238
|
+
|
|
2239
|
+
:ivar url: Pre-signed object storage URL for uploading with ``PUT``.
|
|
2240
|
+
:vartype url: Optional[str]
|
|
2241
|
+
:ivar headers: Headers to send unchanged with the upload request.
|
|
2242
|
+
:vartype headers: Optional[Dict[str, str]]
|
|
2243
|
+
"""
|
|
2244
|
+
|
|
2245
|
+
url: Optional[str] = None
|
|
2246
|
+
headers: Optional[Dict[str, str]] = None
|
|
2204
2247
|
|
|
2205
2248
|
|
|
2206
2249
|
@dataclass(init=False)
|
gitcode_api/cli.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Command-line interface for the GitCode SDK."""
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
|
+
import codecs
|
|
4
5
|
import inspect
|
|
5
6
|
import json
|
|
6
7
|
import re
|
|
@@ -8,7 +9,7 @@ import sys
|
|
|
8
9
|
import textwrap
|
|
9
10
|
from collections.abc import Mapping, Sequence
|
|
10
11
|
from pathlib import Path
|
|
11
|
-
from typing import Any, List, Optional, Union, get_args, get_origin
|
|
12
|
+
from typing import Any, Dict, List, Optional, Union, get_args, get_origin
|
|
12
13
|
|
|
13
14
|
import httpx
|
|
14
15
|
|
|
@@ -36,6 +37,40 @@ def _plain_cli_inline(text: str) -> str:
|
|
|
36
37
|
return t
|
|
37
38
|
|
|
38
39
|
|
|
40
|
+
_ESCAPE_PATTERN = re.compile(r"\\\w+")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _unescape_input(value: str, replacements: Dict[str, str]) -> str:
|
|
44
|
+
"""Unescape CLI input with provided escape sequences."""
|
|
45
|
+
for token, decoded in replacements.items():
|
|
46
|
+
value = value.replace(token, decoded)
|
|
47
|
+
return value
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _unescape_namespace(args: argparse.Namespace) -> None:
|
|
51
|
+
mapping = ((token, codecs.decode(token, "unicode-escape")) for token in _ESCAPE_PATTERN.findall(str(args.escape)))
|
|
52
|
+
replacements = {token: decoded for token, decoded in mapping if token and (token != decoded)}
|
|
53
|
+
if not replacements:
|
|
54
|
+
raise argparse.ArgumentTypeError("No valid escape sequence provided!")
|
|
55
|
+
for key, value in vars(args).items():
|
|
56
|
+
if key in {"escape", "base_url", "resource", "method", "api_key"}:
|
|
57
|
+
continue
|
|
58
|
+
if isinstance(value, str):
|
|
59
|
+
setattr(args, key, _unescape_input(value, replacements=replacements))
|
|
60
|
+
continue
|
|
61
|
+
if isinstance(value, list):
|
|
62
|
+
updated = []
|
|
63
|
+
changed = False
|
|
64
|
+
for item in value:
|
|
65
|
+
if isinstance(item, str):
|
|
66
|
+
updated.append(_unescape_input(item, replacements=replacements))
|
|
67
|
+
changed = True
|
|
68
|
+
else:
|
|
69
|
+
updated.append(item)
|
|
70
|
+
if changed:
|
|
71
|
+
setattr(args, key, updated)
|
|
72
|
+
|
|
73
|
+
|
|
39
74
|
def _unwrap_optional(annotation: Any) -> Any:
|
|
40
75
|
origin = get_origin(annotation)
|
|
41
76
|
if origin is Union:
|
|
@@ -179,12 +214,17 @@ def _invocation_parent_parser() -> argparse.ArgumentParser:
|
|
|
179
214
|
"""Parser with flags for real API calls (attached only to leaf METHOD parsers, not top-level usage)."""
|
|
180
215
|
parser = argparse.ArgumentParser(add_help=False)
|
|
181
216
|
parser.add_argument("--api-key", help=f"GitCode access token. Defaults to {DEFAULT_TOKEN_ENV}.")
|
|
182
|
-
parser.add_argument("--owner", help="Default repository owner.")
|
|
183
|
-
parser.add_argument("--repo", help="Default repository name.")
|
|
184
217
|
parser.add_argument("--base-url", default=DEFAULT_BASE_URL, help="Base URL for the REST API.")
|
|
185
218
|
parser.add_argument("--timeout", type=float, default=None, help="Request timeout in seconds.")
|
|
186
219
|
parser.add_argument("--output-file", help="Write the response to a file instead of stdout.")
|
|
187
220
|
parser.add_argument("--compact", action="store_true", help="Print JSON without indentation.")
|
|
221
|
+
parser.add_argument(
|
|
222
|
+
"-e",
|
|
223
|
+
"--escape",
|
|
224
|
+
default="",
|
|
225
|
+
metavar="SEQUENCES",
|
|
226
|
+
help='Unescape certain escape sequences (e.g. -e "\\n\\t") in arguments.',
|
|
227
|
+
)
|
|
188
228
|
return parser
|
|
189
229
|
|
|
190
230
|
|
|
@@ -192,6 +232,15 @@ def _root_banner() -> str:
|
|
|
192
232
|
return "Connection and defaults are documented on each method's help: %(prog)s RESOURCE METHOD -h."
|
|
193
233
|
|
|
194
234
|
|
|
235
|
+
def _parse_true_false(raw: str) -> bool:
|
|
236
|
+
value = raw.strip().lower()
|
|
237
|
+
if value == "true":
|
|
238
|
+
return True
|
|
239
|
+
if value == "false":
|
|
240
|
+
return False
|
|
241
|
+
raise argparse.ArgumentTypeError("Expected 'true' or 'false'.")
|
|
242
|
+
|
|
243
|
+
|
|
195
244
|
def _serve_parser() -> argparse.ArgumentParser:
|
|
196
245
|
"""Parser with options for starting the bundled MCP server."""
|
|
197
246
|
parser = argparse.ArgumentParser(add_help=False)
|
|
@@ -201,10 +250,25 @@ def _serve_parser() -> argparse.ArgumentParser:
|
|
|
201
250
|
parser.add_argument("--repo", help="Default repository name.")
|
|
202
251
|
parser.add_argument("--base-url", default=DEFAULT_BASE_URL, help="Base URL for the REST API.")
|
|
203
252
|
parser.add_argument("--timeout", type=float, default=None, help="Request timeout in seconds.")
|
|
204
|
-
parser.add_argument(
|
|
253
|
+
parser.add_argument(
|
|
254
|
+
"--transport",
|
|
255
|
+
default="stdio",
|
|
256
|
+
choices=("stdio", "http", "sse"),
|
|
257
|
+
metavar="{stdio,http,sse}",
|
|
258
|
+
help="FastMCP transport to run, such as stdio or http.",
|
|
259
|
+
)
|
|
205
260
|
parser.add_argument("--host", default=None, help="Host for HTTP-based transports.")
|
|
206
261
|
parser.add_argument("--port", type=int, default=None, help="Port for HTTP-based transports.")
|
|
207
262
|
parser.add_argument("--path", default=None, help="Path for HTTP-based transports.")
|
|
263
|
+
parser.add_argument(
|
|
264
|
+
"-b",
|
|
265
|
+
"--show-banner",
|
|
266
|
+
type=_parse_true_false,
|
|
267
|
+
choices=(True, False),
|
|
268
|
+
default=None,
|
|
269
|
+
metavar="{true,false}",
|
|
270
|
+
help="Show the FastMCP startup banner.",
|
|
271
|
+
)
|
|
208
272
|
return parser
|
|
209
273
|
|
|
210
274
|
|
|
@@ -356,7 +420,7 @@ def _run_mcp_server(args: argparse.Namespace) -> int:
|
|
|
356
420
|
if value is not None:
|
|
357
421
|
run_kwargs[key] = value
|
|
358
422
|
|
|
359
|
-
server.run(**run_kwargs)
|
|
423
|
+
server.run(show_banner=args.show_banner, **run_kwargs)
|
|
360
424
|
return 0
|
|
361
425
|
|
|
362
426
|
|
|
@@ -402,6 +466,9 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
|
|
|
402
466
|
parser.epilog = saved_epilog
|
|
403
467
|
return 0
|
|
404
468
|
args = parser.parse_args(effective)
|
|
469
|
+
escape_seq = getattr(args, "escape", None)
|
|
470
|
+
if escape_seq and isinstance(escape_seq, str):
|
|
471
|
+
_unescape_namespace(args)
|
|
405
472
|
|
|
406
473
|
try:
|
|
407
474
|
if getattr(args, "command", None) == "serve":
|
|
@@ -409,8 +476,6 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
|
|
|
409
476
|
|
|
410
477
|
with GitCode(
|
|
411
478
|
api_key=args.api_key,
|
|
412
|
-
owner=args.owner,
|
|
413
|
-
repo=args.repo,
|
|
414
479
|
base_url=args.base_url,
|
|
415
480
|
timeout=args.timeout,
|
|
416
481
|
) as client:
|
gitcode_api/resources/misc.py
CHANGED
|
@@ -1,39 +1,128 @@
|
|
|
1
1
|
"""Release, tag, and webhook resource groups."""
|
|
2
2
|
|
|
3
|
+
from pathlib import Path
|
|
3
4
|
from typing import List, Optional, Union
|
|
4
5
|
|
|
5
|
-
from .._models import ProtectedTag, Release, Tag, Webhook
|
|
6
|
+
from .._models import ProtectedTag, Release, ReleaseUploadURL, Tag, Webhook
|
|
6
7
|
from ._shared import AsyncResource, SyncResource
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class ReleasesResource(SyncResource):
|
|
10
11
|
"""Synchronous release endpoints."""
|
|
11
12
|
|
|
13
|
+
def create(
|
|
14
|
+
self,
|
|
15
|
+
*,
|
|
16
|
+
tag: str,
|
|
17
|
+
name: str,
|
|
18
|
+
body: str,
|
|
19
|
+
owner: Optional[str] = None,
|
|
20
|
+
repo: Optional[str] = None,
|
|
21
|
+
target_commitish: Optional[str] = None,
|
|
22
|
+
release_status: Optional[str] = None,
|
|
23
|
+
) -> Release:
|
|
24
|
+
"""Create a repository release.
|
|
25
|
+
|
|
26
|
+
:param tag: Tag name for the release.
|
|
27
|
+
:param name: Release title.
|
|
28
|
+
:param body: Release description.
|
|
29
|
+
:param owner: Repository owner path. Uses the client default when omitted.
|
|
30
|
+
:param repo: Repository path. Uses the client default when omitted.
|
|
31
|
+
:param target_commitish: Branch name or commit SHA for creating a missing tag.
|
|
32
|
+
:param release_status: Release status, such as ``pre`` or ``latest``.
|
|
33
|
+
:returns: Created release payload.
|
|
34
|
+
"""
|
|
35
|
+
return self._model(
|
|
36
|
+
"POST",
|
|
37
|
+
self._client._repo_path("releases", owner=owner, repo=repo),
|
|
38
|
+
Release,
|
|
39
|
+
json={
|
|
40
|
+
"tag_name": tag,
|
|
41
|
+
"name": name,
|
|
42
|
+
"body": body,
|
|
43
|
+
"target_commitish": target_commitish,
|
|
44
|
+
"release_status": release_status,
|
|
45
|
+
},
|
|
46
|
+
)
|
|
47
|
+
|
|
12
48
|
def update(
|
|
13
49
|
self,
|
|
14
50
|
*,
|
|
15
|
-
|
|
16
|
-
tag_name: str,
|
|
51
|
+
tag: str,
|
|
17
52
|
name: str,
|
|
18
53
|
body: str,
|
|
19
54
|
owner: Optional[str] = None,
|
|
20
55
|
repo: Optional[str] = None,
|
|
56
|
+
release_status: Optional[str] = None,
|
|
21
57
|
) -> Release:
|
|
22
58
|
"""Update a repository release.
|
|
23
59
|
|
|
24
|
-
:param
|
|
25
|
-
:param tag_name: Tag name for the release.
|
|
60
|
+
:param tag: Tag name in the release URL path.
|
|
26
61
|
:param name: Release name.
|
|
27
62
|
:param body: Release description.
|
|
28
63
|
:param owner: Repository owner path. Uses the client default when omitted.
|
|
29
|
-
:param repo: Repository
|
|
64
|
+
:param repo: Repository path. Uses the client default when omitted.
|
|
65
|
+
:param release_status: Release status, such as ``pre`` or ``latest``.
|
|
30
66
|
:returns: Updated release payload.
|
|
31
67
|
"""
|
|
32
68
|
return self._model(
|
|
33
69
|
"PATCH",
|
|
34
|
-
self._client._repo_path("releases",
|
|
70
|
+
self._client._repo_path("releases", tag, owner=owner, repo=repo),
|
|
35
71
|
Release,
|
|
36
|
-
json={"
|
|
72
|
+
json={"name": name, "body": body, "release_status": release_status},
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
def get_upload_url(
|
|
76
|
+
self, *, tag: str, file_name: str, owner: Optional[str] = None, repo: Optional[str] = None
|
|
77
|
+
) -> ReleaseUploadURL:
|
|
78
|
+
"""Get a pre-signed URL for uploading a release attachment.
|
|
79
|
+
|
|
80
|
+
:param tag: Tag name in the release URL path.
|
|
81
|
+
:param file_name: Attachment file name to upload.
|
|
82
|
+
:param owner: Repository owner path. Uses the client default when omitted.
|
|
83
|
+
:param repo: Repository path. Uses the client default when omitted.
|
|
84
|
+
:returns: Upload URL and required headers.
|
|
85
|
+
"""
|
|
86
|
+
return self._model(
|
|
87
|
+
"GET",
|
|
88
|
+
self._client._repo_path("releases", tag, "upload_url", owner=owner, repo=repo),
|
|
89
|
+
ReleaseUploadURL,
|
|
90
|
+
params={"file_name": file_name},
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
def upload(
|
|
94
|
+
self,
|
|
95
|
+
*,
|
|
96
|
+
tag: str,
|
|
97
|
+
file_name: str,
|
|
98
|
+
content: Union[bytes, str],
|
|
99
|
+
owner: Optional[str] = None,
|
|
100
|
+
repo: Optional[str] = None,
|
|
101
|
+
upload_timeout: Optional[float] = 300.0,
|
|
102
|
+
) -> None:
|
|
103
|
+
"""Upload a release attachment through the pre-signed upload URL.
|
|
104
|
+
|
|
105
|
+
:param tag: Tag name in the release URL path.
|
|
106
|
+
:param file_name: Attachment file name to upload.
|
|
107
|
+
:param content: Attachment bytes, or a local file path to read as bytes.
|
|
108
|
+
:param owner: Repository owner path. Uses the client default when omitted.
|
|
109
|
+
:param repo: Repository path. Uses the client default when omitted.
|
|
110
|
+
:param upload_timeout: Timeout for upload operation. Default to 300 (5 minutes).
|
|
111
|
+
"""
|
|
112
|
+
upload_content = Path(content).read_bytes() if isinstance(content, str) else content
|
|
113
|
+
if not isinstance(upload_content, bytes):
|
|
114
|
+
raise TypeError("content must be bytes or a file path string.")
|
|
115
|
+
|
|
116
|
+
upload_url = self.get_upload_url(tag=tag, file_name=file_name, owner=owner, repo=repo)
|
|
117
|
+
if not upload_url.url:
|
|
118
|
+
raise ValueError("Release upload URL response did not include a URL.")
|
|
119
|
+
|
|
120
|
+
self._client._client.request(
|
|
121
|
+
"PUT",
|
|
122
|
+
upload_url.url,
|
|
123
|
+
content=upload_content,
|
|
124
|
+
headers=upload_url.headers or {},
|
|
125
|
+
timeout=upload_timeout,
|
|
37
126
|
)
|
|
38
127
|
|
|
39
128
|
def get_by_tag(self, *, tag: str, owner: Optional[str] = None, repo: Optional[str] = None) -> Release:
|
|
@@ -50,14 +139,87 @@ class ReleasesResource(SyncResource):
|
|
|
50
139
|
Release,
|
|
51
140
|
)
|
|
52
141
|
|
|
53
|
-
def list(
|
|
142
|
+
def list(
|
|
143
|
+
self,
|
|
144
|
+
*,
|
|
145
|
+
owner: Optional[str] = None,
|
|
146
|
+
repo: Optional[str] = None,
|
|
147
|
+
direction: Optional[str] = None,
|
|
148
|
+
page: Optional[int] = None,
|
|
149
|
+
per_page: Optional[int] = None,
|
|
150
|
+
) -> List[Release]:
|
|
54
151
|
"""List releases for a repository.
|
|
55
152
|
|
|
56
153
|
:param owner: Repository owner path. Uses the client default when omitted.
|
|
57
154
|
:param repo: Repository path. Uses the client default when omitted.
|
|
155
|
+
:param direction: Sort direction, for example ``asc`` or ``desc``.
|
|
156
|
+
:param page: Page number.
|
|
157
|
+
:param per_page: Page size, up to 100.
|
|
58
158
|
:returns: Releases ordered as returned by the API.
|
|
59
159
|
"""
|
|
60
|
-
return self._models(
|
|
160
|
+
return self._models(
|
|
161
|
+
"GET",
|
|
162
|
+
self._client._repo_path("releases", owner=owner, repo=repo),
|
|
163
|
+
Release,
|
|
164
|
+
params={"direction": direction, "page": page, "per_page": per_page},
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
def get_latest(
|
|
168
|
+
self, *, owner: Optional[str] = None, repo: Optional[str] = None, type: Optional[str] = None
|
|
169
|
+
) -> Release:
|
|
170
|
+
"""Get the latest repository release.
|
|
171
|
+
|
|
172
|
+
:param owner: Repository owner path. Uses the client default when omitted.
|
|
173
|
+
:param repo: Repository path. Uses the client default when omitted.
|
|
174
|
+
:param type: Selection type, either ``updated`` or ``latest``.
|
|
175
|
+
:returns: Latest release metadata.
|
|
176
|
+
"""
|
|
177
|
+
return self._model(
|
|
178
|
+
"GET",
|
|
179
|
+
self._client._repo_path("releases", "latest", owner=owner, repo=repo),
|
|
180
|
+
Release,
|
|
181
|
+
params={"type": type},
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
def get(
|
|
185
|
+
self,
|
|
186
|
+
*,
|
|
187
|
+
tag: str,
|
|
188
|
+
owner: Optional[str] = None,
|
|
189
|
+
repo: Optional[str] = None,
|
|
190
|
+
temp_download_url: Optional[Union[bool, str]] = None,
|
|
191
|
+
) -> Release:
|
|
192
|
+
"""Get a repository release by tag path.
|
|
193
|
+
|
|
194
|
+
:param tag: Tag name in the release URL path.
|
|
195
|
+
:param owner: Repository owner path. Uses the client default when omitted.
|
|
196
|
+
:param repo: Repository path. Uses the client default when omitted.
|
|
197
|
+
:param temp_download_url: Whether to return temporary source package and attachment URLs.
|
|
198
|
+
:returns: Release metadata.
|
|
199
|
+
"""
|
|
200
|
+
return self._model(
|
|
201
|
+
"GET",
|
|
202
|
+
self._client._repo_path("releases", tag, owner=owner, repo=repo),
|
|
203
|
+
Release,
|
|
204
|
+
params={"temp_download_url": temp_download_url},
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
def download_attachment(
|
|
208
|
+
self, *, tag: str, file_name: str, owner: Optional[str] = None, repo: Optional[str] = None
|
|
209
|
+
) -> bytes:
|
|
210
|
+
"""Download a release attachment as bytes.
|
|
211
|
+
|
|
212
|
+
:param tag: Tag name in the release URL path.
|
|
213
|
+
:param file_name: Attachment file name.
|
|
214
|
+
:param owner: Repository owner path. Uses the client default when omitted.
|
|
215
|
+
:param repo: Repository path. Uses the client default when omitted.
|
|
216
|
+
:returns: Attachment bytes.
|
|
217
|
+
"""
|
|
218
|
+
return self._request(
|
|
219
|
+
"GET",
|
|
220
|
+
self._client._repo_path("releases", tag, "attach_files", file_name, "download", owner=owner, repo=repo),
|
|
221
|
+
raw=True,
|
|
222
|
+
)
|
|
61
223
|
|
|
62
224
|
|
|
63
225
|
class TagsResource(SyncResource):
|
|
@@ -288,31 +450,119 @@ class AsyncReleasesResource(AsyncResource):
|
|
|
288
450
|
Mirrors :class:`ReleasesResource`; see that class for parameters (Release API in ``docs/rest_api``).
|
|
289
451
|
"""
|
|
290
452
|
|
|
453
|
+
async def create(
|
|
454
|
+
self,
|
|
455
|
+
*,
|
|
456
|
+
tag: str,
|
|
457
|
+
name: str,
|
|
458
|
+
body: str,
|
|
459
|
+
owner: Optional[str] = None,
|
|
460
|
+
repo: Optional[str] = None,
|
|
461
|
+
target_commitish: Optional[str] = None,
|
|
462
|
+
release_status: Optional[str] = None,
|
|
463
|
+
) -> Release:
|
|
464
|
+
"""Create a repository release.
|
|
465
|
+
|
|
466
|
+
:param tag: Tag name for the release.
|
|
467
|
+
:param name: Release title.
|
|
468
|
+
:param body: Release description.
|
|
469
|
+
:param owner: Repository owner path. Uses the client default when omitted.
|
|
470
|
+
:param repo: Repository path. Uses the client default when omitted.
|
|
471
|
+
:param target_commitish: Branch name or commit SHA for creating a missing tag.
|
|
472
|
+
:param release_status: Release status, such as ``pre`` or ``latest``.
|
|
473
|
+
:returns: Created release payload.
|
|
474
|
+
"""
|
|
475
|
+
return await self._model(
|
|
476
|
+
"POST",
|
|
477
|
+
self._client._repo_path("releases", owner=owner, repo=repo),
|
|
478
|
+
Release,
|
|
479
|
+
json={
|
|
480
|
+
"tag_name": tag,
|
|
481
|
+
"name": name,
|
|
482
|
+
"body": body,
|
|
483
|
+
"target_commitish": target_commitish,
|
|
484
|
+
"release_status": release_status,
|
|
485
|
+
},
|
|
486
|
+
)
|
|
487
|
+
|
|
291
488
|
async def update(
|
|
292
489
|
self,
|
|
293
490
|
*,
|
|
294
|
-
|
|
295
|
-
tag_name: str,
|
|
491
|
+
tag: str,
|
|
296
492
|
name: str,
|
|
297
493
|
body: str,
|
|
298
494
|
owner: Optional[str] = None,
|
|
299
495
|
repo: Optional[str] = None,
|
|
496
|
+
release_status: Optional[str] = None,
|
|
300
497
|
) -> Release:
|
|
301
498
|
"""Update a repository release.
|
|
302
499
|
|
|
303
|
-
:param
|
|
304
|
-
:param tag_name: Tag name for the release.
|
|
500
|
+
:param tag: Tag name in the release URL path.
|
|
305
501
|
:param name: Release name.
|
|
306
502
|
:param body: Release description.
|
|
307
503
|
:param owner: Repository owner path. Uses the client default when omitted.
|
|
308
|
-
:param repo: Repository
|
|
504
|
+
:param repo: Repository path. Uses the client default when omitted.
|
|
505
|
+
:param release_status: Release status, such as ``pre`` or ``latest``.
|
|
309
506
|
:returns: Updated release payload.
|
|
310
507
|
"""
|
|
311
508
|
return await self._model(
|
|
312
509
|
"PATCH",
|
|
313
|
-
self._client._repo_path("releases",
|
|
510
|
+
self._client._repo_path("releases", tag, owner=owner, repo=repo),
|
|
314
511
|
Release,
|
|
315
|
-
json={"
|
|
512
|
+
json={"name": name, "body": body, "release_status": release_status},
|
|
513
|
+
)
|
|
514
|
+
|
|
515
|
+
async def get_upload_url(
|
|
516
|
+
self, *, tag: str, file_name: str, owner: Optional[str] = None, repo: Optional[str] = None
|
|
517
|
+
) -> ReleaseUploadURL:
|
|
518
|
+
"""Get a pre-signed URL for uploading a release attachment.
|
|
519
|
+
|
|
520
|
+
:param tag: Tag name in the release URL path.
|
|
521
|
+
:param file_name: Attachment file name to upload.
|
|
522
|
+
:param owner: Repository owner path. Uses the client default when omitted.
|
|
523
|
+
:param repo: Repository path. Uses the client default when omitted.
|
|
524
|
+
:returns: Upload URL and required headers.
|
|
525
|
+
"""
|
|
526
|
+
return await self._model(
|
|
527
|
+
"GET",
|
|
528
|
+
self._client._repo_path("releases", tag, "upload_url", owner=owner, repo=repo),
|
|
529
|
+
ReleaseUploadURL,
|
|
530
|
+
params={"file_name": file_name},
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
async def upload(
|
|
534
|
+
self,
|
|
535
|
+
*,
|
|
536
|
+
tag: str,
|
|
537
|
+
file_name: str,
|
|
538
|
+
content: Union[bytes, str],
|
|
539
|
+
owner: Optional[str] = None,
|
|
540
|
+
repo: Optional[str] = None,
|
|
541
|
+
upload_timeout: Optional[float] = 300.0,
|
|
542
|
+
) -> None:
|
|
543
|
+
"""Upload a release attachment through the pre-signed upload URL.
|
|
544
|
+
|
|
545
|
+
:param tag: Tag name in the release URL path.
|
|
546
|
+
:param file_name: Attachment file name to upload.
|
|
547
|
+
:param content: Attachment bytes, or a local file path to read as bytes.
|
|
548
|
+
:param owner: Repository owner path. Uses the client default when omitted.
|
|
549
|
+
:param repo: Repository path. Uses the client default when omitted.
|
|
550
|
+
:param upload_timeout: Timeout for upload operation. Default to 300 (5 minutes).
|
|
551
|
+
"""
|
|
552
|
+
upload_content = Path(content).read_bytes() if isinstance(content, str) else content
|
|
553
|
+
if not isinstance(upload_content, bytes):
|
|
554
|
+
raise TypeError("content must be bytes or a file path string.")
|
|
555
|
+
|
|
556
|
+
upload_url = await self.get_upload_url(tag=tag, file_name=file_name, owner=owner, repo=repo)
|
|
557
|
+
if not upload_url.url:
|
|
558
|
+
raise ValueError("Release upload URL response did not include a URL.")
|
|
559
|
+
|
|
560
|
+
await self._client._client.request(
|
|
561
|
+
"PUT",
|
|
562
|
+
upload_url.url,
|
|
563
|
+
content=upload_content,
|
|
564
|
+
headers=upload_url.headers or {},
|
|
565
|
+
timeout=upload_timeout,
|
|
316
566
|
)
|
|
317
567
|
|
|
318
568
|
async def get_by_tag(self, *, tag: str, owner: Optional[str] = None, repo: Optional[str] = None) -> Release:
|
|
@@ -327,14 +577,87 @@ class AsyncReleasesResource(AsyncResource):
|
|
|
327
577
|
"GET", self._client._repo_path("releases", "tags", tag, owner=owner, repo=repo), Release
|
|
328
578
|
)
|
|
329
579
|
|
|
330
|
-
async def list(
|
|
580
|
+
async def list(
|
|
581
|
+
self,
|
|
582
|
+
*,
|
|
583
|
+
owner: Optional[str] = None,
|
|
584
|
+
repo: Optional[str] = None,
|
|
585
|
+
direction: Optional[str] = None,
|
|
586
|
+
page: Optional[int] = None,
|
|
587
|
+
per_page: Optional[int] = None,
|
|
588
|
+
) -> List[Release]:
|
|
331
589
|
"""List releases for a repository.
|
|
332
590
|
|
|
333
591
|
:param owner: Repository owner path. Uses the client default when omitted.
|
|
334
592
|
:param repo: Repository path. Uses the client default when omitted.
|
|
593
|
+
:param direction: Sort direction, for example ``asc`` or ``desc``.
|
|
594
|
+
:param page: Page number.
|
|
595
|
+
:param per_page: Page size, up to 100.
|
|
335
596
|
:returns: Releases ordered as returned by the API.
|
|
336
597
|
"""
|
|
337
|
-
return await self._models(
|
|
598
|
+
return await self._models(
|
|
599
|
+
"GET",
|
|
600
|
+
self._client._repo_path("releases", owner=owner, repo=repo),
|
|
601
|
+
Release,
|
|
602
|
+
params={"direction": direction, "page": page, "per_page": per_page},
|
|
603
|
+
)
|
|
604
|
+
|
|
605
|
+
async def get_latest(
|
|
606
|
+
self, *, owner: Optional[str] = None, repo: Optional[str] = None, type: Optional[str] = None
|
|
607
|
+
) -> Release:
|
|
608
|
+
"""Get the latest repository release.
|
|
609
|
+
|
|
610
|
+
:param owner: Repository owner path. Uses the client default when omitted.
|
|
611
|
+
:param repo: Repository path. Uses the client default when omitted.
|
|
612
|
+
:param type: Selection type, either ``updated`` or ``latest``.
|
|
613
|
+
:returns: Latest release metadata.
|
|
614
|
+
"""
|
|
615
|
+
return await self._model(
|
|
616
|
+
"GET",
|
|
617
|
+
self._client._repo_path("releases", "latest", owner=owner, repo=repo),
|
|
618
|
+
Release,
|
|
619
|
+
params={"type": type},
|
|
620
|
+
)
|
|
621
|
+
|
|
622
|
+
async def get(
|
|
623
|
+
self,
|
|
624
|
+
*,
|
|
625
|
+
tag: str,
|
|
626
|
+
owner: Optional[str] = None,
|
|
627
|
+
repo: Optional[str] = None,
|
|
628
|
+
temp_download_url: Optional[Union[bool, str]] = None,
|
|
629
|
+
) -> Release:
|
|
630
|
+
"""Get a repository release by tag path.
|
|
631
|
+
|
|
632
|
+
:param tag: Tag name in the release URL path.
|
|
633
|
+
:param owner: Repository owner path. Uses the client default when omitted.
|
|
634
|
+
:param repo: Repository path. Uses the client default when omitted.
|
|
635
|
+
:param temp_download_url: Whether to return temporary source package and attachment URLs.
|
|
636
|
+
:returns: Release metadata.
|
|
637
|
+
"""
|
|
638
|
+
return await self._model(
|
|
639
|
+
"GET",
|
|
640
|
+
self._client._repo_path("releases", tag, owner=owner, repo=repo),
|
|
641
|
+
Release,
|
|
642
|
+
params={"temp_download_url": temp_download_url},
|
|
643
|
+
)
|
|
644
|
+
|
|
645
|
+
async def download_attachment(
|
|
646
|
+
self, *, tag: str, file_name: str, owner: Optional[str] = None, repo: Optional[str] = None
|
|
647
|
+
) -> bytes:
|
|
648
|
+
"""Download a release attachment as bytes.
|
|
649
|
+
|
|
650
|
+
:param tag: Tag name in the release URL path.
|
|
651
|
+
:param file_name: Attachment file name.
|
|
652
|
+
:param owner: Repository owner path. Uses the client default when omitted.
|
|
653
|
+
:param repo: Repository path. Uses the client default when omitted.
|
|
654
|
+
:returns: Attachment bytes.
|
|
655
|
+
"""
|
|
656
|
+
return await self._request(
|
|
657
|
+
"GET",
|
|
658
|
+
self._client._repo_path("releases", tag, "attach_files", file_name, "download", owner=owner, repo=repo),
|
|
659
|
+
raw=True,
|
|
660
|
+
)
|
|
338
661
|
|
|
339
662
|
|
|
340
663
|
class AsyncTagsResource(AsyncResource):
|
gitcode_api/run_mcp.py
CHANGED
gitcode_api/version.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.2.
|
|
1
|
+
1.2.13
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gitcode-api
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.13
|
|
4
4
|
Summary: Easy to use Python SDK for the GitCode REST API. Providing builtin CLI tool, and optional LLM integration (MCP, OpenAI tool, and openJiuwen tool) for agents. Community-maintained.
|
|
5
5
|
Author-email: Hugo Huang <hugo@hugohuang.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -9,7 +9,7 @@ Project-URL: issues, https://github.com/Trenza1ore/GitCode-API/issues
|
|
|
9
9
|
Project-URL: documentation, https://gitcode-api.readthedocs.io
|
|
10
10
|
Project-URL: gitcode, https://gitcode.com/SushiNinja/GitCode-API
|
|
11
11
|
Project-URL: github, https://github.com/Trenza1ore/GitCode-API
|
|
12
|
-
Project-URL: homepage, https://
|
|
12
|
+
Project-URL: homepage, https://hugohuang.com/gitcode-api
|
|
13
13
|
Project-URL: author, https://hugohuang.com
|
|
14
14
|
Keywords: gitcode,git,devops,api,sdk,python,httpx,client,mcp,agent,fastmcp,llm,openjiuwen,mcp client,mcp server,model context protocol
|
|
15
15
|
Classifier: Development Status :: 4 - Beta
|
|
@@ -37,7 +37,7 @@ Dynamic: license-file
|
|
|
37
37
|
|
|
38
38
|
# GitCode-API
|
|
39
39
|
|
|
40
|
-
[](https://pypi.org/project/gitcode-api) [](https://pepy.tech/projects/gitcode-api) [](https://www.codefactor.io/repository/github/trenza1ore/gitcode-api)
|
|
40
|
+
[](https://pypi.org/project/gitcode-api) [](https://pepy.tech/projects/gitcode-api) [](https://www.codefactor.io/repository/github/trenza1ore/gitcode-api)
|
|
41
41
|
[](https://cursor.com/en/install-mcp?name=GitCode%20API&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJnaXRjb2RlLWFwaVttY3BdIiwiZ2l0Y29kZS1hcGkiLCJzZXJ2ZSJdLCJlbnYiOnsiR0lUQ09ERV9BQ0NFU1NfVE9LRU4iOiIke2lucHV0OmdpdGNvZGVfYWNjZXNzX3Rva2VufSJ9LCJpbnB1dHMiOlt7ImlkIjoiZ2l0Y29kZV9hY2Nlc3NfdG9rZW4iLCJ0eXBlIjoicHJvbXB0U3RyaW5nIiwiZGVzY3JpcHRpb24iOiJFbnRlciBHSVRDT0RFX0FDQ0VTU19UT0tFTiIsInBhc3N3b3JkIjp0cnVlfV19) [](https://vscode.dev/redirect/mcp/install?name=GitCode%20API&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22gitcode-api%5Bmcp%5D%22%2C%22gitcode-api%22%2C%22serve%22%5D%2C%22env%22%3A%7B%22GITCODE_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitcode_access_token%7D%22%7D%2C%22inputs%22%3A%5B%7B%22id%22%3A%22gitcode_access_token%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Enter%20GITCODE_ACCESS_TOKEN%22%2C%22password%22%3Atrue%7D%5D%7D)
|
|
42
42
|
[](https://github.com/Trenza1ore/GitCode-API) [](https://gitcode.com/SushiNinja/GitCode-API)
|
|
43
43
|
|
|
@@ -111,12 +111,14 @@ With `gitcode-api[mcp]` installed (Python 3.10+), you can start the bundled Fast
|
|
|
111
111
|
gitcode-api serve --api-key "$GITCODE_ACCESS_TOKEN"
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
Use `gitcode-api serve -h` for defaults such as `--owner`, `--repo`, and
|
|
114
|
+
Use `gitcode-api serve -h` for defaults such as `--owner`, `--repo`, `--transport` (`stdio`, `http`, or `sse`), and other options.
|
|
115
115
|
|
|
116
116
|
Commands mirror the synchronous resource methods on `GitCode`, using the pattern
|
|
117
117
|
`gitcode-api <resource> <method> ...`. For methods that accept extra `**params`
|
|
118
118
|
or `**payload`, pass repeated `--set key=value` flags or `--set-json '{"key": "value"}'`.
|
|
119
119
|
|
|
120
|
+
When using string arguments with escape sequence (such as line break `\n`), pass `-e` / `--escape` with the sequences to un-escape, such as `-e '\n\t'`.
|
|
121
|
+
|
|
120
122
|
## Quick Start
|
|
121
123
|
|
|
122
124
|
### Sync client
|
|
@@ -5,11 +5,11 @@ gitcode_api/_base_resource.py,sha256=mlKe1b_1AKcqxhptaCpP-AOjKkLNzCbYG-Pkp1HYWrA
|
|
|
5
5
|
gitcode_api/_cli_banner.py,sha256=3DsoJ2qZ-mWWB4yD-cnxDN_osXzrUKabrA5tbV6752M,978
|
|
6
6
|
gitcode_api/_client.py,sha256=bmZxBHdfshM5Kv_EurHUVu8rsEj0k3Up3ATSIPaFrvc,8258
|
|
7
7
|
gitcode_api/_exceptions.py,sha256=T5N8gBGmPSktDkLP5P_hxbzOHw3W378TzxN1xja40pA,1140
|
|
8
|
-
gitcode_api/_models.py,sha256=
|
|
9
|
-
gitcode_api/cli.py,sha256=
|
|
8
|
+
gitcode_api/_models.py,sha256=7MqQJSEZiXkqcBAKdaKUQN_I61QjkHRIJYIR70tYMWU,110559
|
|
9
|
+
gitcode_api/cli.py,sha256=Z-X5gK8iI2wCEXqT-igVKpVzO4ZhaRYaxmTbqMbIUx8,18735
|
|
10
10
|
gitcode_api/py.typed,sha256=mDShSrm8qg9qjacQc2F-rI8ATllqP6EdgHuEYxuCXZ0,7
|
|
11
|
-
gitcode_api/run_mcp.py,sha256=
|
|
12
|
-
gitcode_api/version.txt,sha256=
|
|
11
|
+
gitcode_api/run_mcp.py,sha256=3_JOrjg9_yL-0M-H-F8mPgxdVKh7K2ggipu7UHeNCg0,147
|
|
12
|
+
gitcode_api/version.txt,sha256=whaYM0seIwi4VWrB0QQCNCuNPoN_ZfocQx6yM5KCSx0,7
|
|
13
13
|
gitcode_api/llm/__init__.py,sha256=rU75ZlJvTWNVxBLc3QzdfWmSjqVc9z6hfQ8z6jVVKOk,1693
|
|
14
14
|
gitcode_api/llm/_tool.py,sha256=b65iUiHo1H29uA6mFM3WlD0zZlISsENx1tpEqlkiUoA,16239
|
|
15
15
|
gitcode_api/llm/jiuwen.py,sha256=axwAcoG86XkPkN37PTh47Cdzwh3yACUpe4bTjlaAFDc,4244
|
|
@@ -19,11 +19,11 @@ gitcode_api/resources/__init__.py,sha256=nsCKW0bFDZ5ombJZxLThmO82sOuF7o4OKUMRkAm
|
|
|
19
19
|
gitcode_api/resources/_shared.py,sha256=7bCym8bIfs818SiYYrBGI7-ZtiYlxECSDG3RduInu10,5387
|
|
20
20
|
gitcode_api/resources/account.py,sha256=mnc2p7wI-nBnHFNdWPNiHfmZpT6d3RDQC777gewtm4M,38801
|
|
21
21
|
gitcode_api/resources/collaboration.py,sha256=8lyk78GTjVXddiE9fieutsMGovRjteGfTJcAhwLoR0M,101607
|
|
22
|
-
gitcode_api/resources/misc.py,sha256=
|
|
22
|
+
gitcode_api/resources/misc.py,sha256=w7bq8rmgKr2ScBKeWZ3EZJmAdylDdPtSPrhi3AQre7w,34747
|
|
23
23
|
gitcode_api/resources/repositories.py,sha256=EAK2znZhEsgVUu-NDEQslSEEYJzvb-kHuh4mW57y6sc,78178
|
|
24
|
-
gitcode_api-1.2.
|
|
25
|
-
gitcode_api-1.2.
|
|
26
|
-
gitcode_api-1.2.
|
|
27
|
-
gitcode_api-1.2.
|
|
28
|
-
gitcode_api-1.2.
|
|
29
|
-
gitcode_api-1.2.
|
|
24
|
+
gitcode_api-1.2.13.dist-info/licenses/LICENSE,sha256=gOACXuWhMu6PJKVLr9RQbxX3HULnZIGNXCaMFJIXhoA,1067
|
|
25
|
+
gitcode_api-1.2.13.dist-info/METADATA,sha256=sqYMb5Au9bBv9TpDu8d6sK29DzIzl2XwsP3Mrllwfng,22335
|
|
26
|
+
gitcode_api-1.2.13.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
27
|
+
gitcode_api-1.2.13.dist-info/entry_points.txt,sha256=dIPylJcgohIE2RRIlt3In2WzcwDK8TOdkL_ReKuij4o,53
|
|
28
|
+
gitcode_api-1.2.13.dist-info/top_level.txt,sha256=gIlg0ptyOUHJT64ajOjWIhRPYgIQnMIvnhhnesw9fxU,12
|
|
29
|
+
gitcode_api-1.2.13.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|