Source code for action0.github.operations.repos
"""The repository operations (`GitHub docs <https://docs.github.com/en/rest/repos/repos>`__)."""
from __future__ import annotations
from enum import StrEnum
from typing import Any
from action0.client import json_field
from action0.client import path_param
from action0.client import query
from action0.req import Method
from ..models.repo import Repo
from ..models.tag import Tag
from ..models.user import Contributor
from .base import GitHubOperation
from .base import PaginatedOperation
from .base import SortDirection
__all__ = [
"GetRepo",
"GetRepoTopics",
"ListContributors",
"ListLanguages",
"ListOrgRepos",
"ListRepoTags",
"ListUserRepos",
"OrgRepoType",
"ReplaceRepoTopics",
"RepoSort",
"SortDirection", # re-exported: it moved to .base when the issues listings arrived
"UserRepoType",
]
[docs]
class RepoSort(StrEnum):
"""The sort orders of the repository listings."""
CREATED = "created"
UPDATED = "updated"
PUSHED = "pushed"
FULL_NAME = "full_name"
[docs]
class OrgRepoType(StrEnum):
"""The repository-type filter of :py:class:`ListOrgRepos`."""
ALL = "all"
PUBLIC = "public"
PRIVATE = "private"
FORKS = "forks"
SOURCES = "sources"
MEMBER = "member"
[docs]
class UserRepoType(StrEnum):
"""The repository-type filter of :py:class:`ListUserRepos`."""
ALL = "all"
OWNER = "owner"
MEMBER = "member"
[docs]
class GetRepo(GitHubOperation[Repo]):
"""
``GET /repos/{owner}/{repo}`` — fetch one repository.
>>> GetRepo(owner="python", repo="cpython").as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/cpython'
"""
method = Method.GET
path = "/repos/{owner}/{repo}"
owner: str = path_param()
repo: str = path_param()
[docs]
def load_json(self, data: Any) -> Repo:
"""
:param data: the decoded JSON payload
:return: the repository
"""
return Repo.from_json(data)
class _ListRepos(PaginatedOperation[Repo]):
"""
The shared shape of the repository listings: sorting query fields
(enums are serialized to their values, ``None`` fields are simply not
sent) on top of the pagination ones, and pages of repositories as the
result.
"""
sort: RepoSort | None = query(default=None)
"""The sort order; ``None`` uses GitHub's default (``created``)."""
direction: SortDirection | None = query(default=None)
"""The sort direction; GitHub's default is ``asc`` when :py:attr:`sort`
is ``full_name``, ``desc`` otherwise."""
def load_item(self, data: Any) -> Repo:
"""
:param data: one decoded JSON array item
:return: the repository
"""
return Repo.from_json(data)
[docs]
class ListOrgRepos(_ListRepos):
"""
``GET /orgs/{org}/repos`` — list an organization's repositories.
>>> operation = ListOrgRepos(org="python", sort=RepoSort.PUSHED, per_page=5)
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/orgs/python/repos?per_page=5&page=1&sort=pushed'
"""
method = Method.GET
path = "/orgs/{org}/repos"
org: str = path_param()
type: OrgRepoType | None = query(default=None)
"""The repository-type filter; ``None`` uses GitHub's default (``all``)."""
[docs]
class ListUserRepos(_ListRepos):
"""``GET /users/{username}/repos`` — list a user's repositories."""
method = Method.GET
path = "/users/{username}/repos"
username: str = path_param()
type: UserRepoType | None = query(default=None)
"""The repository-type filter; ``None`` uses GitHub's default (``owner``)."""
[docs]
class ListContributors(PaginatedOperation[Contributor]):
"""
``GET /repos/{owner}/{repo}/contributors`` — list who contributed,
most commits first (each item a
:py:class:`~action0.github.models.user.Contributor` — a user plus
their commit count).
"""
method = Method.GET
path = "/repos/{owner}/{repo}/contributors"
owner: str = path_param()
repo: str = path_param()
[docs]
def load_item(self, data: Any) -> Contributor:
"""
:param data: one decoded JSON array item
:return: the contributor
"""
return Contributor.from_json(data)
[docs]
class ListLanguages(GitHubOperation[dict[str, int]]):
"""
``GET /repos/{owner}/{repo}/languages`` — the repository's language
breakdown, handed through as GitHub sends it: language name →
bytes of code, largest first.
>>> operation = ListLanguages(owner="python", repo="cpython")
>>> operation.as_request("https://api.github.com").url.as_str()
'https://api.github.com/repos/python/cpython/languages'
"""
method = Method.GET
path = "/repos/{owner}/{repo}/languages"
owner: str = path_param()
repo: str = path_param()
[docs]
def load_json(self, data: Any) -> dict[str, int]:
"""
:param data: the decoded JSON payload
:return: language name → bytes of code
"""
return dict(data)
[docs]
class GetRepoTopics(GitHubOperation[list[str]]):
"""
``GET /repos/{owner}/{repo}/topics`` — the repository's topics, as
the plain list of names (unwrapped from GitHub's ``{names: [...]}``
envelope).
"""
method = Method.GET
path = "/repos/{owner}/{repo}/topics"
owner: str = path_param()
repo: str = path_param()
[docs]
def load_json(self, data: Any) -> list[str]:
"""
:param data: the decoded JSON payload (the envelope)
:return: the topic names
"""
return list(data["names"])
[docs]
class ReplaceRepoTopics(GitHubOperation[list[str]]):
"""
``PUT /repos/{owner}/{repo}/topics`` — replace the repository's
topics wholesale (there is no incremental add/remove in GitHub's
API; read-modify-write via :py:class:`GetRepoTopics`). Requires a
token with write access; ``[]`` clears them.
"""
method = Method.PUT
path = "/repos/{owner}/{repo}/topics"
owner: str = path_param()
repo: str = path_param()
names: list[str] = json_field()
"""The complete new topic set (lowercase letters, digits and
hyphens — GitHub answers 422 otherwise)."""
[docs]
def load_json(self, data: Any) -> list[str]:
"""
:param data: the decoded JSON payload (the envelope)
:return: the topic names as stored
"""
return list(data["names"])