github-rest-api 0.42.0__tar.gz → 0.42.1__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.
Files changed (43) hide show
  1. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/PKG-INFO +1 -1
  2. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/github.py +32 -1
  3. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/cargo/benchmark.py +8 -6
  4. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/cargo/profiling.py +7 -5
  5. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/container/build_container_images.py +7 -6
  6. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/container/config_container.py +3 -2
  7. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/container/update_version_containerfile.py +4 -2
  8. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/github/add_github_repo.py +2 -1
  9. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/github/create_pull_request.py +2 -1
  10. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/github/release_on_github.py +3 -2
  11. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/github/remove_branch.py +2 -1
  12. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/utils.py +4 -3
  13. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/utils.py +2 -2
  14. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/pyproject.toml +6 -1
  15. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/tests/test_build_container_images.py +1 -0
  16. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/tests/test_github.py +36 -1
  17. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/tests/test_release_on_github.py +2 -0
  18. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/tests/test_utils.py +1 -0
  19. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/uv.lock +1 -1
  20. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/.devcontainer/devcontainer.json +0 -0
  21. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/.github/workflows/create_pr_to_main.yaml +0 -0
  22. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/.github/workflows/lint.yaml +0 -0
  23. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/.github/workflows/release.yaml +0 -0
  24. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/.github/workflows/remove_branch.yaml +0 -0
  25. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/.github/workflows/test.yaml +0 -0
  26. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/.gitignore +0 -0
  27. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/GEMINI.md +0 -0
  28. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/README.md +0 -0
  29. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/__init__.py +0 -0
  30. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/__init__.py +0 -0
  31. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/cargo/__init__.py +0 -0
  32. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/cargo/utils.py +0 -0
  33. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/container/__init__.py +0 -0
  34. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/github/__init__.py +0 -0
  35. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/github/workflows/create_pr_dev_to_main.yaml +0 -0
  36. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/github/workflows/create_pr_to_dev.yaml +0 -0
  37. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/github/workflows/create_pr_to_main.yaml +0 -0
  38. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/github/workflows/python/lint.yaml +0 -0
  39. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/github/workflows/python/test.yaml +0 -0
  40. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/github_rest_api/scripts/github/workflows/remove_branch.yaml +0 -0
  41. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/memory/MEMORY.md +0 -0
  42. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/memory/feedback_test_runner.md +0 -0
  43. {github_rest_api-0.42.0 → github_rest_api-0.42.1}/tests/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: github-rest-api
3
- Version: 0.42.0
3
+ Version: 0.42.1
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
@@ -1,16 +1,45 @@
1
1
  """Simple wrapper of GitHub REST APIs."""
2
2
 
3
+ import re
3
4
  from abc import ABCMeta, abstractmethod
4
5
  from base64 import b64encode
5
6
  from collections.abc import Sequence
6
7
  from enum import StrEnum
7
- from typing import Any, Callable
8
8
  from pathlib import Path
9
+ from typing import Any, Callable
10
+
9
11
  import requests
10
12
  from nacl import encoding, public
11
13
 
12
14
  URL_API = "https://api.github.com"
13
15
 
16
+ _SECRET_NAME_PATTERN = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
17
+
18
+
19
+ def _validate_secret_name(name: str) -> None:
20
+ """Validate a secret name against GitHub's naming rules.
21
+
22
+ GitHub rejects invalid secret names with a 422 response. Validating the
23
+ name client-side surfaces a clear error before the request is sent.
24
+
25
+ :param name: The name of the secret.
26
+ :raises ValueError: If the name is empty, starts with the reserved
27
+ ``GITHUB_`` prefix, starts with a digit, or contains characters other
28
+ than alphanumerics and underscores.
29
+ """
30
+ if not name:
31
+ raise ValueError("A secret name must not be empty.")
32
+ if name.upper().startswith("GITHUB_"):
33
+ raise ValueError(
34
+ f"Invalid secret name {name!r}: names must not start with the "
35
+ "reserved 'GITHUB_' prefix."
36
+ )
37
+ if not _SECRET_NAME_PATTERN.fullmatch(name):
38
+ raise ValueError(
39
+ f"Invalid secret name {name!r}: names may only contain alphanumeric "
40
+ "characters and underscores, and must not start with a digit."
41
+ )
42
+
14
43
 
15
44
  def _encrypt_secret(public_key: str, value: str) -> str:
16
45
  """Encrypt a secret value using a LibSodium sealed box.
@@ -354,6 +383,7 @@ class Repository(GitHub):
354
383
  automatically. Fetch it once and reuse it to avoid a redundant
355
384
  request when creating or updating multiple secrets.
356
385
  """
386
+ _validate_secret_name(name)
357
387
  if public_key is None:
358
388
  public_key = self.get_secret_public_key()
359
389
  return self._put(
@@ -549,6 +579,7 @@ class Organization(Owner):
549
579
  :param selected_repository_ids: Repository IDs that can access the secret
550
580
  when visibility is `selected`.
551
581
  """
582
+ _validate_secret_name(name)
552
583
  if selected_repository_ids and visibility != SecretVisibility.SELECTED:
553
584
  raise ValueError(
554
585
  "`selected_repository_ids` can only be provided when `visibility` is 'selected'."
@@ -1,18 +1,20 @@
1
1
  """Benchmark action using cargo criterion."""
2
2
 
3
- from typing import Callable
4
- import tempfile
5
- from pathlib import Path
6
3
  import datetime
7
4
  import shutil
8
5
  import subprocess as sp
6
+ import tempfile
7
+ from pathlib import Path
8
+ from typing import Callable
9
+
9
10
  from dulwich import porcelain
11
+
10
12
  from ..utils import (
13
+ commit_benchmarks,
11
14
  config_git,
12
- switch_branch,
13
- push_branch,
14
15
  gen_temp_branch,
15
- commit_benchmarks,
16
+ push_branch,
17
+ switch_branch,
16
18
  )
17
19
 
18
20
 
@@ -1,14 +1,16 @@
1
1
  """Utils for profiling Rust applications."""
2
2
 
3
- from typing import Iterable
4
- from pathlib import Path
5
- import time
6
3
  import datetime
7
4
  import subprocess as sp
5
+ import time
6
+ from pathlib import Path
7
+ from typing import Iterable
8
+
8
9
  import psutil
9
- from .utils import build_project
10
- from ..utils import config_git, switch_branch, push_branch, commit_profiling
10
+
11
11
  from ...utils import partition
12
+ from ..utils import commit_profiling, config_git, push_branch, switch_branch
13
+ from .utils import build_project
12
14
 
13
15
 
14
16
  def launch_application(cmd: list[str]) -> int:
@@ -1,16 +1,17 @@
1
1
  import argparse
2
- from collections.abc import Sequence
3
2
  import datetime
4
- from pathlib import Path
5
3
  import subprocess as sp
6
4
  import sys
5
+ from collections.abc import Sequence
6
+ from pathlib import Path
7
7
  from typing import cast
8
+
8
9
  import yaml
9
- from dulwich.repo import Repo
10
- from dulwich.refs import Ref
11
- from dulwich.objects import Commit
12
- from dulwich.errors import NotGitRepository
13
10
  from dulwich.diff_tree import tree_changes
11
+ from dulwich.errors import NotGitRepository
12
+ from dulwich.objects import Commit
13
+ from dulwich.refs import Ref
14
+ from dulwich.repo import Repo
14
15
  from tenacity import retry, stop_after_attempt, wait_exponential
15
16
 
16
17
 
@@ -1,11 +1,12 @@
1
1
  import argparse
2
2
  import json
3
3
  import shutil
4
+ import subprocess as sp
4
5
  import sys
5
6
  import tomllib
6
- import tomli_w
7
7
  from pathlib import Path
8
- import subprocess as sp
8
+
9
+ import tomli_w
9
10
 
10
11
 
11
12
  def config_docker(data_root: str = "/mnt/docker"):
@@ -1,13 +1,15 @@
1
1
  import argparse
2
2
  import datetime
3
3
  import os
4
+ import re
4
5
  import sys
5
6
  from pathlib import Path
6
- import re
7
+
7
8
  from dulwich import porcelain
9
+ from requests.exceptions import HTTPError
10
+
8
11
  from github_rest_api import Repository
9
12
  from github_rest_api.utils import next_minor_or_strip_patch
10
- from requests.exceptions import HTTPError
11
13
 
12
14
 
13
15
  def parse_latest_version(repo: str) -> str:
@@ -7,9 +7,10 @@ import shutil
7
7
  import sys
8
8
  from collections.abc import Sequence
9
9
  from pathlib import Path
10
+
10
11
  from dulwich import porcelain
11
12
 
12
- from github_rest_api import User, Organization
13
+ from github_rest_api import Organization, User
13
14
 
14
15
 
15
16
  def _validate_repo(repo: str) -> None:
@@ -2,9 +2,10 @@
2
2
  The branch is updated (using dev) before creating the PR.
3
3
  """
4
4
 
5
- from argparse import ArgumentParser, Namespace
6
5
  import os
7
6
  import sys
7
+ from argparse import ArgumentParser, Namespace
8
+
8
9
  from github_rest_api import Repository
9
10
  from github_rest_api.utils import compile_patterns
10
11
 
@@ -1,9 +1,10 @@
1
+ import argparse
2
+ import getpass
1
3
  import os
2
4
  import re
3
5
  import sys
4
- import argparse
5
- import getpass
6
6
  from pathlib import Path
7
+
7
8
  from github_rest_api import Repository
8
9
  from github_rest_api.scripts.utils import (
9
10
  find_project_root,
@@ -1,7 +1,8 @@
1
1
  import argparse
2
+ import datetime
2
3
  import re
3
4
  import sys
4
- import datetime
5
+
5
6
  from github_rest_api import Repository
6
7
 
7
8
 
@@ -1,10 +1,11 @@
1
1
  """Util functions for GitHub actions."""
2
2
 
3
+ import random
3
4
  import tomllib
4
- from typing import Any, Iterable
5
- from pathlib import Path
6
5
  from collections.abc import Sequence
7
- import random
6
+ from pathlib import Path
7
+ from typing import Any, Iterable
8
+
8
9
  from dulwich import porcelain
9
10
  from dulwich.repo import Repo
10
11
 
@@ -1,8 +1,8 @@
1
1
  """Some generally useful util functions."""
2
2
 
3
- from collections.abc import Sequence
4
- from itertools import tee, filterfalse
5
3
  import re
4
+ from collections.abc import Sequence
5
+ from itertools import filterfalse, tee
6
6
 
7
7
 
8
8
  def partition(pred, iterable):
@@ -4,7 +4,7 @@ requires = [ "hatchling" ]
4
4
 
5
5
  [project]
6
6
  name = "github-rest-api"
7
- version = "0.42.0"
7
+ version = "0.42.1"
8
8
  description = "Simple wrapper of GitHub REST APIs."
9
9
  readme = "README.md"
10
10
  authors = [ { name = "Ben Du", email = "longendu@yahoo.com" } ]
@@ -41,3 +41,8 @@ dev = [
41
41
  "ruff>=0.14.10",
42
42
  "ty>=0.0.8",
43
43
  ]
44
+
45
+ [tool.ruff.lint]
46
+ # select the 'I' rule set for import sorting
47
+ extend-select = ["I"]
48
+
@@ -1,5 +1,6 @@
1
1
  from pathlib import Path
2
2
  from unittest.mock import patch
3
+
3
4
  from github_rest_api.scripts.container.build_container_images import (
4
5
  has_relevant_changes,
5
6
  )
@@ -1,7 +1,16 @@
1
1
  import os
2
2
  from base64 import b64decode
3
+
4
+ import pytest
3
5
  from nacl import encoding, public
4
- from github_rest_api.github import User, Organization, Repository, _encrypt_secret
6
+
7
+ from github_rest_api.github import (
8
+ Organization,
9
+ Repository,
10
+ User,
11
+ _encrypt_secret,
12
+ _validate_secret_name,
13
+ )
5
14
 
6
15
  TOKEN = os.environ.get("GITHUB_TOKEN", "")
7
16
 
@@ -14,6 +23,32 @@ def test_encrypt_secret_roundtrip():
14
23
  assert decrypted == b"s3cret-value"
15
24
 
16
25
 
26
+ @pytest.mark.parametrize(
27
+ "name",
28
+ ["MY_SECRET", "_underscore", "Token123", "a"],
29
+ )
30
+ def test_validate_secret_name_valid(name):
31
+ _validate_secret_name(name)
32
+
33
+
34
+ @pytest.mark.parametrize(
35
+ "name",
36
+ [
37
+ "",
38
+ "GITHUB_ACTIONS",
39
+ "GITHUB_TOKEN",
40
+ "github_token",
41
+ "GitHub_Token",
42
+ "1SECRET",
43
+ "MY-SECRET",
44
+ "MY SECRET",
45
+ ],
46
+ )
47
+ def test_validate_secret_name_invalid(name):
48
+ with pytest.raises(ValueError):
49
+ _validate_secret_name(name)
50
+
51
+
17
52
  def test_user_get_repositories():
18
53
  user = User(TOKEN, "dclong")
19
54
  repos = user.get_repositories()
@@ -1,6 +1,8 @@
1
1
  from pathlib import Path
2
2
  from unittest.mock import patch
3
+
3
4
  import pytest
5
+
4
6
  from github_rest_api.scripts.github.release_on_github import _get_release_tag
5
7
 
6
8
  ROOT = Path(".")
@@ -1,4 +1,5 @@
1
1
  import pytest
2
+
2
3
  from github_rest_api.utils import next_minor_or_strip_patch, strip_patch_version
3
4
 
4
5
 
@@ -223,7 +223,7 @@ wheels = [
223
223
 
224
224
  [[package]]
225
225
  name = "github-rest-api"
226
- version = "0.41.0"
226
+ version = "0.42.1"
227
227
  source = { editable = "." }
228
228
  dependencies = [
229
229
  { name = "dulwich" },