github-rest-api 0.40.0__tar.gz → 0.42.0__tar.gz
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.
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/PKG-INFO +2 -1
- github_rest_api-0.42.0/github_rest_api/__init__.py +11 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/github.py +176 -28
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/pyproject.toml +2 -1
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/tests/test_github.py +11 -1
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/uv.lock +104 -1
- github_rest_api-0.40.0/.claude/settings.json +0 -9
- github_rest_api-0.40.0/github_rest_api/__init__.py +0 -5
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/.devcontainer/devcontainer.json +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/.github/workflows/create_pr_to_main.yaml +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/.github/workflows/lint.yaml +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/.github/workflows/release.yaml +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/.github/workflows/remove_branch.yaml +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/.github/workflows/test.yaml +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/.gitignore +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/GEMINI.md +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/README.md +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/__init__.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/cargo/__init__.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/cargo/benchmark.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/cargo/profiling.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/cargo/utils.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/container/__init__.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/container/build_container_images.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/container/config_container.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/container/update_version_containerfile.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/github/__init__.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/github/add_github_repo.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/github/create_pull_request.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/github/release_on_github.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/github/remove_branch.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/github/workflows/create_pr_dev_to_main.yaml +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/github/workflows/create_pr_to_dev.yaml +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/github/workflows/create_pr_to_main.yaml +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/github/workflows/python/lint.yaml +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/github/workflows/python/test.yaml +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/github/workflows/remove_branch.yaml +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/utils.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/utils.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/memory/MEMORY.md +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/memory/feedback_test_runner.md +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/tests/__init__.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/tests/test_build_container_images.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/tests/test_release_on_github.py +0 -0
- {github_rest_api-0.40.0 → github_rest_api-0.42.0}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: github-rest-api
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.42.0
|
|
4
4
|
Summary: Simple wrapper of GitHub REST APIs.
|
|
5
5
|
Author-email: Ben Du <longendu@yahoo.com>
|
|
6
6
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
@@ -10,6 +10,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
10
10
|
Requires-Python: <4,>=3.12
|
|
11
11
|
Requires-Dist: dulwich>=0.25.1
|
|
12
12
|
Requires-Dist: psutil>=5.9.4
|
|
13
|
+
Requires-Dist: pynacl>=1.5
|
|
13
14
|
Requires-Dist: pyyaml>=6
|
|
14
15
|
Requires-Dist: requests>=2.28.2
|
|
15
16
|
Requires-Dist: tenacity>=9.1.4
|
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
"""Simple wrapper of GitHub REST APIs."""
|
|
2
2
|
|
|
3
3
|
from abc import ABCMeta, abstractmethod
|
|
4
|
+
from base64 import b64encode
|
|
5
|
+
from collections.abc import Sequence
|
|
4
6
|
from enum import StrEnum
|
|
5
7
|
from typing import Any, Callable
|
|
6
8
|
from pathlib import Path
|
|
7
9
|
import requests
|
|
10
|
+
from nacl import encoding, public
|
|
11
|
+
|
|
12
|
+
URL_API = "https://api.github.com"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _encrypt_secret(public_key: str, value: str) -> str:
|
|
16
|
+
"""Encrypt a secret value using a LibSodium sealed box.
|
|
17
|
+
:param public_key: The base64-encoded public key to encrypt against.
|
|
18
|
+
:param value: The plaintext secret value to encrypt.
|
|
19
|
+
"""
|
|
20
|
+
pkey = public.PublicKey(public_key.encode(), encoding.Base64Encoder)
|
|
21
|
+
encrypted = public.SealedBox(pkey).encrypt(value.encode())
|
|
22
|
+
return b64encode(encrypted).decode()
|
|
8
23
|
|
|
9
24
|
|
|
10
25
|
def build_http_headers(token: str) -> dict[str, str]:
|
|
@@ -36,6 +51,12 @@ class GitHub:
|
|
|
36
51
|
def _get(
|
|
37
52
|
self, url: str, raise_for_status: bool = True, **kwargs
|
|
38
53
|
) -> requests.Response:
|
|
54
|
+
"""Send a GET request to a GitHub REST API endpoint.
|
|
55
|
+
:param url: The endpoint URL to request.
|
|
56
|
+
:param raise_for_status: Whether to raise on a non-2xx response.
|
|
57
|
+
:param kwargs: Additional keyword arguments (e.g. `params`) forwarded
|
|
58
|
+
to `requests.get`.
|
|
59
|
+
"""
|
|
39
60
|
resp = requests.get(
|
|
40
61
|
url=url,
|
|
41
62
|
headers=self._headers,
|
|
@@ -49,6 +70,13 @@ class GitHub:
|
|
|
49
70
|
def _post(
|
|
50
71
|
self, url: str, headers=None, raise_for_status: bool = True, **kwargs
|
|
51
72
|
) -> requests.Response:
|
|
73
|
+
"""Send a POST request to a GitHub REST API endpoint.
|
|
74
|
+
:param url: The endpoint URL to request.
|
|
75
|
+
:param headers: Request headers; defaults to the standard auth headers.
|
|
76
|
+
:param raise_for_status: Whether to raise on a non-2xx response.
|
|
77
|
+
:param kwargs: Additional keyword arguments (e.g. `json`) forwarded
|
|
78
|
+
to `requests.post`.
|
|
79
|
+
"""
|
|
52
80
|
if headers is None:
|
|
53
81
|
headers = self._headers
|
|
54
82
|
resp = requests.post(
|
|
@@ -67,17 +95,32 @@ class GitHub:
|
|
|
67
95
|
resp.raise_for_status()
|
|
68
96
|
return resp
|
|
69
97
|
|
|
70
|
-
def _put(
|
|
98
|
+
def _put(
|
|
99
|
+
self, url: str, raise_for_status: bool = True, **kwargs
|
|
100
|
+
) -> requests.Response:
|
|
101
|
+
"""Send a PUT request to a GitHub REST API endpoint.
|
|
102
|
+
:param url: The endpoint URL to request.
|
|
103
|
+
:param raise_for_status: Whether to raise on a non-2xx response.
|
|
104
|
+
:param kwargs: Additional keyword arguments (e.g. `json`) forwarded
|
|
105
|
+
to `requests.put`.
|
|
106
|
+
"""
|
|
71
107
|
resp = requests.put(
|
|
72
108
|
url=url,
|
|
73
109
|
headers=self._headers,
|
|
74
110
|
timeout=10,
|
|
111
|
+
**kwargs,
|
|
75
112
|
)
|
|
76
113
|
if raise_for_status:
|
|
77
114
|
resp.raise_for_status()
|
|
78
115
|
return resp
|
|
79
116
|
|
|
80
117
|
def _patch(self, url, raise_for_status: bool = True, **kwargs) -> requests.Response:
|
|
118
|
+
"""Send a PATCH request to a GitHub REST API endpoint.
|
|
119
|
+
:param url: The endpoint URL to request.
|
|
120
|
+
:param raise_for_status: Whether to raise on a non-2xx response.
|
|
121
|
+
:param kwargs: Additional keyword arguments (e.g. `json`) forwarded
|
|
122
|
+
to `requests.patch`.
|
|
123
|
+
"""
|
|
81
124
|
resp = requests.patch(
|
|
82
125
|
url=url,
|
|
83
126
|
headers=self._headers,
|
|
@@ -89,8 +132,19 @@ class GitHub:
|
|
|
89
132
|
return resp
|
|
90
133
|
|
|
91
134
|
def _extract_all(
|
|
92
|
-
self,
|
|
135
|
+
self,
|
|
136
|
+
url: str,
|
|
137
|
+
params: dict[str, Any] | None = None,
|
|
138
|
+
n: int = 0,
|
|
139
|
+
key: str | None = None,
|
|
93
140
|
) -> list[dict[str, Any]]:
|
|
141
|
+
"""Collect all paginated items from a GitHub REST API endpoint.
|
|
142
|
+
:param url: The endpoint URL to request.
|
|
143
|
+
:param params: Query parameters forwarded to each request.
|
|
144
|
+
:param n: The maximum number of items to return (0 means all).
|
|
145
|
+
:param key: The key under which the list is nested in the response.
|
|
146
|
+
Defaults to None for endpoints that return a plain JSON array.
|
|
147
|
+
"""
|
|
94
148
|
params = params.copy() if params else {}
|
|
95
149
|
if "per_page" not in params:
|
|
96
150
|
params["per_page"] = min(100, n) if n > 0 else 100
|
|
@@ -100,10 +154,11 @@ class GitHub:
|
|
|
100
154
|
resp = self._get(url=url, params=params.copy())
|
|
101
155
|
resp.raise_for_status()
|
|
102
156
|
data = resp.json()
|
|
103
|
-
|
|
157
|
+
items = data if key is None else data[key]
|
|
158
|
+
res.extend(items)
|
|
104
159
|
if n and len(res) >= n:
|
|
105
160
|
return res[:n]
|
|
106
|
-
if len(
|
|
161
|
+
if len(items) < params["per_page"]:
|
|
107
162
|
return res
|
|
108
163
|
params["page"] += 1
|
|
109
164
|
|
|
@@ -118,8 +173,7 @@ class Repository(GitHub):
|
|
|
118
173
|
"""
|
|
119
174
|
super().__init__(token)
|
|
120
175
|
self._repo = repo
|
|
121
|
-
self.
|
|
122
|
-
self._url_repo = f"{self._url}/{repo}"
|
|
176
|
+
self._url_repo = f"{URL_API}/repos/{repo}"
|
|
123
177
|
self._url_tags = f"{self._url_repo}/tags"
|
|
124
178
|
self._url_transfer = f"{self._url_repo}/transfer"
|
|
125
179
|
self._url_pull = f"{self._url_repo}/pulls"
|
|
@@ -127,6 +181,7 @@ class Repository(GitHub):
|
|
|
127
181
|
self._url_refs = f"{self._url_repo}/git/refs"
|
|
128
182
|
self._url_issues = f"{self._url_repo}/issues"
|
|
129
183
|
self._url_releases = f"{self._url_repo}/releases"
|
|
184
|
+
self._url_secrets = f"{self._url_repo}/actions/secrets"
|
|
130
185
|
|
|
131
186
|
def get_releases(self, n: int = 0) -> list[dict[str, Any]]:
|
|
132
187
|
"""List releases in this repository."""
|
|
@@ -157,8 +212,6 @@ class Repository(GitHub):
|
|
|
157
212
|
For more details, please refer to
|
|
158
213
|
https://docs.github.com/en/rest/releases/releases#create-a-release.
|
|
159
214
|
"""
|
|
160
|
-
if not isinstance(json, dict):
|
|
161
|
-
raise ValueError("A dict value is required for `json`.")
|
|
162
215
|
return self._post(
|
|
163
216
|
url=self._url_releases,
|
|
164
217
|
json=json,
|
|
@@ -171,7 +224,9 @@ class Repository(GitHub):
|
|
|
171
224
|
path = Path(path)
|
|
172
225
|
with path.open(mode="rb") as fin:
|
|
173
226
|
return self._post(
|
|
174
|
-
url=f"{self._url_releases.replace('api', 'uploads', 1)}/{
|
|
227
|
+
url=f"{self._url_releases.replace('api', 'uploads', 1)}/{
|
|
228
|
+
release
|
|
229
|
+
}/assets",
|
|
175
230
|
params={
|
|
176
231
|
"name": name,
|
|
177
232
|
},
|
|
@@ -193,8 +248,6 @@ class Repository(GitHub):
|
|
|
193
248
|
about the pull request to be created.
|
|
194
249
|
It's passed to the json parameter of requests.post.
|
|
195
250
|
"""
|
|
196
|
-
if not isinstance(json, dict):
|
|
197
|
-
raise ValueError("A dict value is required for `json`.")
|
|
198
251
|
if not ("head" in json and "base" in json):
|
|
199
252
|
raise ValueError("The data dict must contains keys head and base!")
|
|
200
253
|
# return an existing PR
|
|
@@ -217,8 +270,6 @@ class Repository(GitHub):
|
|
|
217
270
|
"""Merge a pull request in this repository.
|
|
218
271
|
:param pr_number: The number of the pull quest to be merged.
|
|
219
272
|
"""
|
|
220
|
-
if not isinstance(pr_number, int):
|
|
221
|
-
raise ValueError("An integer value is required for `pr_number`.")
|
|
222
273
|
return self._put(
|
|
223
274
|
url=f"{self._url_pull}/{pr_number}/merge",
|
|
224
275
|
).json()
|
|
@@ -228,10 +279,6 @@ class Repository(GitHub):
|
|
|
228
279
|
:param update: The branch to update.
|
|
229
280
|
:param upstream: The upstream branch.
|
|
230
281
|
"""
|
|
231
|
-
if not isinstance(update, str):
|
|
232
|
-
raise ValueError("A string value is required for `update`.")
|
|
233
|
-
if not isinstance(upstream, str):
|
|
234
|
-
raise ValueError("A string value is required for `upstream`.")
|
|
235
282
|
pr = self.create_pull_request(
|
|
236
283
|
{
|
|
237
284
|
"base": update,
|
|
@@ -250,8 +297,6 @@ class Repository(GitHub):
|
|
|
250
297
|
|
|
251
298
|
:param pr_number: The number of the pull request.
|
|
252
299
|
"""
|
|
253
|
-
if not isinstance(pr_number, int):
|
|
254
|
-
raise ValueError("An integer value is required for `pr_number`.")
|
|
255
300
|
return self._extract_all(url=f"{self._url_pull}/{pr_number}/files", n=n)
|
|
256
301
|
|
|
257
302
|
def get_branches(self, n: int = 0) -> list[dict[str, Any]]:
|
|
@@ -272,8 +317,6 @@ class Repository(GitHub):
|
|
|
272
317
|
"""Delete a reference from this repository.
|
|
273
318
|
:param ref: The reference to delete from this repository.
|
|
274
319
|
"""
|
|
275
|
-
if not isinstance(ref, str):
|
|
276
|
-
raise ValueError("A string value is required for `ref`.")
|
|
277
320
|
return self._delete(
|
|
278
321
|
url=f"{self._url_refs}/{ref}",
|
|
279
322
|
)
|
|
@@ -284,6 +327,43 @@ class Repository(GitHub):
|
|
|
284
327
|
"""
|
|
285
328
|
return self.delete_ref(ref=f"heads/{branch}")
|
|
286
329
|
|
|
330
|
+
def get_secrets(self, n: int = 0) -> list[dict[str, Any]]:
|
|
331
|
+
"""List secrets in this repository."""
|
|
332
|
+
return self._extract_all(url=self._url_secrets, n=n, key="secrets")
|
|
333
|
+
|
|
334
|
+
def delete_secret(self, name: str) -> requests.Response:
|
|
335
|
+
"""Delete a secret from this repository.
|
|
336
|
+
:param name: The name of the secret to delete.
|
|
337
|
+
"""
|
|
338
|
+
return self._delete(
|
|
339
|
+
url=f"{self._url_secrets}/{name}",
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
def get_secret_public_key(self) -> dict[str, Any]:
|
|
343
|
+
"""Get the public key for encrypting secrets in this repository."""
|
|
344
|
+
return self._get(url=f"{self._url_secrets}/public-key").json()
|
|
345
|
+
|
|
346
|
+
def create_or_update_secret(
|
|
347
|
+
self, name: str, value: str, public_key: dict[str, Any] | None = None
|
|
348
|
+
) -> requests.Response:
|
|
349
|
+
"""Create or update a secret in this repository.
|
|
350
|
+
:param name: The name of the secret.
|
|
351
|
+
:param value: The plaintext value of the secret.
|
|
352
|
+
:param public_key: A public key (as returned by `get_secret_public_key`)
|
|
353
|
+
to encrypt the secret with. If not provided, it is fetched
|
|
354
|
+
automatically. Fetch it once and reuse it to avoid a redundant
|
|
355
|
+
request when creating or updating multiple secrets.
|
|
356
|
+
"""
|
|
357
|
+
if public_key is None:
|
|
358
|
+
public_key = self.get_secret_public_key()
|
|
359
|
+
return self._put(
|
|
360
|
+
url=f"{self._url_secrets}/{name}",
|
|
361
|
+
json={
|
|
362
|
+
"encrypted_value": _encrypt_secret(public_key["key"], value),
|
|
363
|
+
"key_id": public_key["key_id"],
|
|
364
|
+
},
|
|
365
|
+
)
|
|
366
|
+
|
|
287
367
|
def pr_has_change(
|
|
288
368
|
self, pr_number: int, pred: Callable[[str], bool] = lambda _: True
|
|
289
369
|
) -> bool:
|
|
@@ -313,10 +393,6 @@ class Repository(GitHub):
|
|
|
313
393
|
:param issue_number: The number of the issue.
|
|
314
394
|
:param body: Body text of the new comment.
|
|
315
395
|
"""
|
|
316
|
-
if not isinstance(issue_number, int):
|
|
317
|
-
raise ValueError("An integer value is required for `issue_number`.")
|
|
318
|
-
if not isinstance(body, str):
|
|
319
|
-
raise ValueError("A string message is required for `body`.")
|
|
320
396
|
return self._post(
|
|
321
397
|
url=f"{self._url_issues}/{issue_number}/comments",
|
|
322
398
|
json={"body": body},
|
|
@@ -344,6 +420,12 @@ class RepositoryType(StrEnum):
|
|
|
344
420
|
PRIVATE = "private"
|
|
345
421
|
|
|
346
422
|
|
|
423
|
+
class SecretVisibility(StrEnum):
|
|
424
|
+
ALL = "all"
|
|
425
|
+
PRIVATE = "private"
|
|
426
|
+
SELECTED = "selected"
|
|
427
|
+
|
|
428
|
+
|
|
347
429
|
class Owner(GitHub, metaclass=ABCMeta):
|
|
348
430
|
"""An abstract owner class representing an organization or user."""
|
|
349
431
|
|
|
@@ -354,6 +436,7 @@ class Owner(GitHub, metaclass=ABCMeta):
|
|
|
354
436
|
"""
|
|
355
437
|
super().__init__(token)
|
|
356
438
|
self._owner = owner
|
|
439
|
+
self._url_owner = ""
|
|
357
440
|
self._url_repos = ""
|
|
358
441
|
self._url_create_repo = ""
|
|
359
442
|
|
|
@@ -376,6 +459,14 @@ class Owner(GitHub, metaclass=ABCMeta):
|
|
|
376
459
|
def create_repository(
|
|
377
460
|
self, name: str, description: str = "", private: bool = True, **kwargs
|
|
378
461
|
) -> dict[str, Any]:
|
|
462
|
+
"""Create a repository for this owner.
|
|
463
|
+
:param name: The name of the repository.
|
|
464
|
+
:param description: A short description of the repository.
|
|
465
|
+
:param private: Whether the repository is private.
|
|
466
|
+
:param kwargs: Additional keyword arguments forwarded to `_post`
|
|
467
|
+
(e.g. `params` or `raise_for_status`). Note `json` is already set
|
|
468
|
+
from the other parameters and must not be passed here.
|
|
469
|
+
"""
|
|
379
470
|
data = {
|
|
380
471
|
"name": name,
|
|
381
472
|
"description": description,
|
|
@@ -400,8 +491,9 @@ class User(Owner):
|
|
|
400
491
|
self._set_urls()
|
|
401
492
|
|
|
402
493
|
def _set_urls(self) -> None:
|
|
403
|
-
self.
|
|
404
|
-
self.
|
|
494
|
+
self._url_owner = f"{URL_API}/users/{self._owner}"
|
|
495
|
+
self._url_repos = f"{self._url_owner}/repos"
|
|
496
|
+
self._url_create_repo = f"{URL_API}/user/repos"
|
|
405
497
|
|
|
406
498
|
|
|
407
499
|
class Organization(Owner):
|
|
@@ -416,5 +508,61 @@ class Organization(Owner):
|
|
|
416
508
|
self._set_urls()
|
|
417
509
|
|
|
418
510
|
def _set_urls(self) -> None:
|
|
419
|
-
self.
|
|
511
|
+
self._url_owner = f"{URL_API}/orgs/{self._owner}"
|
|
512
|
+
self._url_repos = f"{self._url_owner}/repos"
|
|
420
513
|
self._url_create_repo = self._url_repos
|
|
514
|
+
self._url_secrets = f"{self._url_owner}/actions/secrets"
|
|
515
|
+
|
|
516
|
+
def get_secrets(self, n: int = 0) -> list[dict[str, Any]]:
|
|
517
|
+
"""List secrets in this organization."""
|
|
518
|
+
return self._extract_all(url=self._url_secrets, n=n, key="secrets")
|
|
519
|
+
|
|
520
|
+
def delete_secret(self, name: str) -> requests.Response:
|
|
521
|
+
"""Delete an organization secret.
|
|
522
|
+
:param name: The name of the secret to delete.
|
|
523
|
+
"""
|
|
524
|
+
return self._delete(
|
|
525
|
+
url=f"{self._url_secrets}/{name}",
|
|
526
|
+
)
|
|
527
|
+
|
|
528
|
+
def get_secret_public_key(self) -> dict[str, Any]:
|
|
529
|
+
"""Get the public key for encrypting secrets in this organization."""
|
|
530
|
+
return self._get(url=f"{self._url_secrets}/public-key").json()
|
|
531
|
+
|
|
532
|
+
def create_or_update_secret(
|
|
533
|
+
self,
|
|
534
|
+
name: str,
|
|
535
|
+
value: str,
|
|
536
|
+
public_key: dict[str, Any] | None = None,
|
|
537
|
+
visibility: SecretVisibility = SecretVisibility.ALL,
|
|
538
|
+
selected_repository_ids: Sequence[int] = (),
|
|
539
|
+
) -> requests.Response:
|
|
540
|
+
"""Create or update an organization secret.
|
|
541
|
+
:param name: The name of the secret.
|
|
542
|
+
:param value: The plaintext value of the secret.
|
|
543
|
+
:param public_key: A public key (as returned by `get_secret_public_key`)
|
|
544
|
+
to encrypt the secret with. If not provided, it is fetched
|
|
545
|
+
automatically. Fetch it once and reuse it to avoid a redundant
|
|
546
|
+
request when creating or updating multiple secrets.
|
|
547
|
+
:param visibility: Which repositories can access the secret
|
|
548
|
+
(all, private, or selected).
|
|
549
|
+
:param selected_repository_ids: Repository IDs that can access the secret
|
|
550
|
+
when visibility is `selected`.
|
|
551
|
+
"""
|
|
552
|
+
if selected_repository_ids and visibility != SecretVisibility.SELECTED:
|
|
553
|
+
raise ValueError(
|
|
554
|
+
"`selected_repository_ids` can only be provided when `visibility` is 'selected'."
|
|
555
|
+
)
|
|
556
|
+
if public_key is None:
|
|
557
|
+
public_key = self.get_secret_public_key()
|
|
558
|
+
json: dict[str, Any] = {
|
|
559
|
+
"encrypted_value": _encrypt_secret(public_key["key"], value),
|
|
560
|
+
"key_id": public_key["key_id"],
|
|
561
|
+
"visibility": visibility,
|
|
562
|
+
}
|
|
563
|
+
if selected_repository_ids:
|
|
564
|
+
json["selected_repository_ids"] = list(selected_repository_ids)
|
|
565
|
+
return self._put(
|
|
566
|
+
url=f"{self._url_secrets}/{name}",
|
|
567
|
+
json=json,
|
|
568
|
+
)
|
|
@@ -4,7 +4,7 @@ requires = [ "hatchling" ]
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "github-rest-api"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.42.0"
|
|
8
8
|
description = "Simple wrapper of GitHub REST APIs."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [ { name = "Ben Du", email = "longendu@yahoo.com" } ]
|
|
@@ -18,6 +18,7 @@ classifiers = [
|
|
|
18
18
|
dependencies = [
|
|
19
19
|
"dulwich>=0.25.1",
|
|
20
20
|
"psutil>=5.9.4",
|
|
21
|
+
"pynacl>=1.5",
|
|
21
22
|
"pyyaml>=6",
|
|
22
23
|
"requests>=2.28.2",
|
|
23
24
|
"tenacity>=9.1.4",
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import os
|
|
2
|
-
from
|
|
2
|
+
from base64 import b64decode
|
|
3
|
+
from nacl import encoding, public
|
|
4
|
+
from github_rest_api.github import User, Organization, Repository, _encrypt_secret
|
|
3
5
|
|
|
4
6
|
TOKEN = os.environ.get("GITHUB_TOKEN", "")
|
|
5
7
|
|
|
6
8
|
|
|
9
|
+
def test_encrypt_secret_roundtrip():
|
|
10
|
+
private_key = public.PrivateKey.generate()
|
|
11
|
+
public_key = private_key.public_key.encode(encoding.Base64Encoder).decode()
|
|
12
|
+
encrypted = _encrypt_secret(public_key, "s3cret-value")
|
|
13
|
+
decrypted = public.SealedBox(private_key).decrypt(b64decode(encrypted))
|
|
14
|
+
assert decrypted == b"s3cret-value"
|
|
15
|
+
|
|
16
|
+
|
|
7
17
|
def test_user_get_repositories():
|
|
8
18
|
user = User(TOKEN, "dclong")
|
|
9
19
|
repos = user.get_repositories()
|
|
@@ -11,6 +11,63 @@ wheels = [
|
|
|
11
11
|
{ url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" },
|
|
12
12
|
]
|
|
13
13
|
|
|
14
|
+
[[package]]
|
|
15
|
+
name = "cffi"
|
|
16
|
+
version = "2.0.0"
|
|
17
|
+
source = { registry = "https://pypi.org/simple" }
|
|
18
|
+
dependencies = [
|
|
19
|
+
{ name = "pycparser", marker = "implementation_name != 'PyPy'" },
|
|
20
|
+
]
|
|
21
|
+
sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" }
|
|
22
|
+
wheels = [
|
|
23
|
+
{ url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" },
|
|
24
|
+
{ url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" },
|
|
25
|
+
{ url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" },
|
|
26
|
+
{ url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" },
|
|
27
|
+
{ url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" },
|
|
28
|
+
{ url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" },
|
|
29
|
+
{ url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" },
|
|
30
|
+
{ url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" },
|
|
31
|
+
{ url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" },
|
|
32
|
+
{ url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" },
|
|
33
|
+
{ url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" },
|
|
34
|
+
{ url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" },
|
|
35
|
+
{ url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" },
|
|
36
|
+
{ url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" },
|
|
37
|
+
{ url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" },
|
|
38
|
+
{ url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" },
|
|
39
|
+
{ url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" },
|
|
40
|
+
{ url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" },
|
|
41
|
+
{ url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" },
|
|
42
|
+
{ url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" },
|
|
43
|
+
{ url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" },
|
|
44
|
+
{ url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" },
|
|
45
|
+
{ url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" },
|
|
46
|
+
{ url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" },
|
|
47
|
+
{ url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" },
|
|
48
|
+
{ url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" },
|
|
49
|
+
{ url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" },
|
|
50
|
+
{ url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" },
|
|
51
|
+
{ url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" },
|
|
52
|
+
{ url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" },
|
|
53
|
+
{ url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" },
|
|
54
|
+
{ url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" },
|
|
55
|
+
{ url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" },
|
|
56
|
+
{ url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" },
|
|
57
|
+
{ url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" },
|
|
58
|
+
{ url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" },
|
|
59
|
+
{ url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" },
|
|
60
|
+
{ url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" },
|
|
61
|
+
{ url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" },
|
|
62
|
+
{ url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" },
|
|
63
|
+
{ url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" },
|
|
64
|
+
{ url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" },
|
|
65
|
+
{ url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" },
|
|
66
|
+
{ url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" },
|
|
67
|
+
{ url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" },
|
|
68
|
+
{ url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
|
|
69
|
+
]
|
|
70
|
+
|
|
14
71
|
[[package]]
|
|
15
72
|
name = "charset-normalizer"
|
|
16
73
|
version = "3.4.7"
|
|
@@ -166,11 +223,12 @@ wheels = [
|
|
|
166
223
|
|
|
167
224
|
[[package]]
|
|
168
225
|
name = "github-rest-api"
|
|
169
|
-
version = "0.
|
|
226
|
+
version = "0.41.0"
|
|
170
227
|
source = { editable = "." }
|
|
171
228
|
dependencies = [
|
|
172
229
|
{ name = "dulwich" },
|
|
173
230
|
{ name = "psutil" },
|
|
231
|
+
{ name = "pynacl" },
|
|
174
232
|
{ name = "pyyaml" },
|
|
175
233
|
{ name = "requests" },
|
|
176
234
|
{ name = "tenacity" },
|
|
@@ -191,6 +249,7 @@ dev = [
|
|
|
191
249
|
requires-dist = [
|
|
192
250
|
{ name = "dulwich", specifier = ">=0.25.1" },
|
|
193
251
|
{ name = "psutil", specifier = ">=5.9.4" },
|
|
252
|
+
{ name = "pynacl", specifier = ">=1.5" },
|
|
194
253
|
{ name = "pyyaml", specifier = ">=6" },
|
|
195
254
|
{ name = "requests", specifier = ">=2.28.2" },
|
|
196
255
|
{ name = "tenacity", specifier = ">=9.1.4" },
|
|
@@ -280,6 +339,15 @@ wheels = [
|
|
|
280
339
|
{ url = "https://files.pythonhosted.org/packages/8c/c7/7bb2e321574b10df20cbde462a94e2b71d05f9bbda251ef27d104668306a/psutil-7.2.2-cp37-abi3-win_arm64.whl", hash = "sha256:8c233660f575a5a89e6d4cb65d9f938126312bca76d8fe087b947b3a1aaac9ee", size = 134617, upload-time = "2026-01-28T18:15:36.514Z" },
|
|
281
340
|
]
|
|
282
341
|
|
|
342
|
+
[[package]]
|
|
343
|
+
name = "pycparser"
|
|
344
|
+
version = "3.0"
|
|
345
|
+
source = { registry = "https://pypi.org/simple" }
|
|
346
|
+
sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" }
|
|
347
|
+
wheels = [
|
|
348
|
+
{ url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
|
|
349
|
+
]
|
|
350
|
+
|
|
283
351
|
[[package]]
|
|
284
352
|
name = "pygments"
|
|
285
353
|
version = "2.20.0"
|
|
@@ -289,6 +357,41 @@ wheels = [
|
|
|
289
357
|
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
|
|
290
358
|
]
|
|
291
359
|
|
|
360
|
+
[[package]]
|
|
361
|
+
name = "pynacl"
|
|
362
|
+
version = "1.6.2"
|
|
363
|
+
source = { registry = "https://pypi.org/simple" }
|
|
364
|
+
dependencies = [
|
|
365
|
+
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
|
|
366
|
+
]
|
|
367
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d9/9a/4019b524b03a13438637b11538c82781a5eda427394380381af8f04f467a/pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c", size = 3511692, upload-time = "2026-01-01T17:48:10.851Z" }
|
|
368
|
+
wheels = [
|
|
369
|
+
{ url = "https://files.pythonhosted.org/packages/4b/79/0e3c34dc3c4671f67d251c07aa8eb100916f250ee470df230b0ab89551b4/pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594", size = 390064, upload-time = "2026-01-01T17:31:57.264Z" },
|
|
370
|
+
{ url = "https://files.pythonhosted.org/packages/eb/1c/23a26e931736e13b16483795c8a6b2f641bf6a3d5238c22b070a5112722c/pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0", size = 809370, upload-time = "2026-01-01T17:31:59.198Z" },
|
|
371
|
+
{ url = "https://files.pythonhosted.org/packages/87/74/8d4b718f8a22aea9e8dcc8b95deb76d4aae380e2f5b570cc70b5fd0a852d/pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9", size = 1408304, upload-time = "2026-01-01T17:32:01.162Z" },
|
|
372
|
+
{ url = "https://files.pythonhosted.org/packages/fd/73/be4fdd3a6a87fe8a4553380c2b47fbd1f7f58292eb820902f5c8ac7de7b0/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574", size = 844871, upload-time = "2026-01-01T17:32:02.824Z" },
|
|
373
|
+
{ url = "https://files.pythonhosted.org/packages/55/ad/6efc57ab75ee4422e96b5f2697d51bbcf6cdcc091e66310df91fbdc144a8/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634", size = 1446356, upload-time = "2026-01-01T17:32:04.452Z" },
|
|
374
|
+
{ url = "https://files.pythonhosted.org/packages/78/b7/928ee9c4779caa0a915844311ab9fb5f99585621c5d6e4574538a17dca07/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88", size = 826814, upload-time = "2026-01-01T17:32:06.078Z" },
|
|
375
|
+
{ url = "https://files.pythonhosted.org/packages/f7/a9/1bdba746a2be20f8809fee75c10e3159d75864ef69c6b0dd168fc60e485d/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14", size = 1411742, upload-time = "2026-01-01T17:32:07.651Z" },
|
|
376
|
+
{ url = "https://files.pythonhosted.org/packages/f3/2f/5e7ea8d85f9f3ea5b6b87db1d8388daa3587eed181bdeb0306816fdbbe79/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444", size = 801714, upload-time = "2026-01-01T17:32:09.558Z" },
|
|
377
|
+
{ url = "https://files.pythonhosted.org/packages/06/ea/43fe2f7eab5f200e40fb10d305bf6f87ea31b3bbc83443eac37cd34a9e1e/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b", size = 1372257, upload-time = "2026-01-01T17:32:11.026Z" },
|
|
378
|
+
{ url = "https://files.pythonhosted.org/packages/4d/54/c9ea116412788629b1347e415f72195c25eb2f3809b2d3e7b25f5c79f13a/pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145", size = 231319, upload-time = "2026-01-01T17:32:12.46Z" },
|
|
379
|
+
{ url = "https://files.pythonhosted.org/packages/ce/04/64e9d76646abac2dccf904fccba352a86e7d172647557f35b9fe2a5ee4a1/pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590", size = 244044, upload-time = "2026-01-01T17:32:13.781Z" },
|
|
380
|
+
{ url = "https://files.pythonhosted.org/packages/33/33/7873dc161c6a06f43cda13dec67b6fe152cb2f982581151956fa5e5cdb47/pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2", size = 188740, upload-time = "2026-01-01T17:32:15.083Z" },
|
|
381
|
+
{ url = "https://files.pythonhosted.org/packages/be/7b/4845bbf88e94586ec47a432da4e9107e3fc3ce37eb412b1398630a37f7dd/pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465", size = 388458, upload-time = "2026-01-01T17:32:16.829Z" },
|
|
382
|
+
{ url = "https://files.pythonhosted.org/packages/1e/b4/e927e0653ba63b02a4ca5b4d852a8d1d678afbf69b3dbf9c4d0785ac905c/pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0", size = 800020, upload-time = "2026-01-01T17:32:18.34Z" },
|
|
383
|
+
{ url = "https://files.pythonhosted.org/packages/7f/81/d60984052df5c97b1d24365bc1e30024379b42c4edcd79d2436b1b9806f2/pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4", size = 1399174, upload-time = "2026-01-01T17:32:20.239Z" },
|
|
384
|
+
{ url = "https://files.pythonhosted.org/packages/68/f7/322f2f9915c4ef27d140101dd0ed26b479f7e6f5f183590fd32dfc48c4d3/pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87", size = 835085, upload-time = "2026-01-01T17:32:22.24Z" },
|
|
385
|
+
{ url = "https://files.pythonhosted.org/packages/3e/d0/f301f83ac8dbe53442c5a43f6a39016f94f754d7a9815a875b65e218a307/pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c", size = 1437614, upload-time = "2026-01-01T17:32:23.766Z" },
|
|
386
|
+
{ url = "https://files.pythonhosted.org/packages/c4/58/fc6e649762b029315325ace1a8c6be66125e42f67416d3dbd47b69563d61/pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130", size = 818251, upload-time = "2026-01-01T17:32:25.69Z" },
|
|
387
|
+
{ url = "https://files.pythonhosted.org/packages/c9/a8/b917096b1accc9acd878819a49d3d84875731a41eb665f6ebc826b1af99e/pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6", size = 1402859, upload-time = "2026-01-01T17:32:27.215Z" },
|
|
388
|
+
{ url = "https://files.pythonhosted.org/packages/85/42/fe60b5f4473e12c72f977548e4028156f4d340b884c635ec6b063fe7e9a5/pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e", size = 791926, upload-time = "2026-01-01T17:32:29.314Z" },
|
|
389
|
+
{ url = "https://files.pythonhosted.org/packages/fa/f9/e40e318c604259301cc091a2a63f237d9e7b424c4851cafaea4ea7c4834e/pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577", size = 1363101, upload-time = "2026-01-01T17:32:31.263Z" },
|
|
390
|
+
{ url = "https://files.pythonhosted.org/packages/48/47/e761c254f410c023a469284a9bc210933e18588ca87706ae93002c05114c/pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa", size = 227421, upload-time = "2026-01-01T17:32:33.076Z" },
|
|
391
|
+
{ url = "https://files.pythonhosted.org/packages/41/ad/334600e8cacc7d86587fe5f565480fde569dfb487389c8e1be56ac21d8ac/pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0", size = 239754, upload-time = "2026-01-01T17:32:34.557Z" },
|
|
392
|
+
{ url = "https://files.pythonhosted.org/packages/29/7d/5945b5af29534641820d3bd7b00962abbbdfee84ec7e19f0d5b3175f9a31/pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c", size = 184801, upload-time = "2026-01-01T17:32:36.309Z" },
|
|
393
|
+
]
|
|
394
|
+
|
|
292
395
|
[[package]]
|
|
293
396
|
name = "pyproject-fmt"
|
|
294
397
|
version = "2.21.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/cargo/benchmark.py
RENAMED
|
File without changes
|
{github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/cargo/profiling.py
RENAMED
|
File without changes
|
|
File without changes
|
{github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/container/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/github/__init__.py
RENAMED
|
File without changes
|
{github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/github/add_github_repo.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{github_rest_api-0.40.0 → github_rest_api-0.42.0}/github_rest_api/scripts/github/remove_branch.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|