Skip to content

Releases

list_releases (GitHub)

Also reachable as github.list_releases.

ocx_mirror_sdk.github._router.list_releases

list_releases(path: str, *, backend: Backend | str = Backend.REST, include_prereleases: bool = True, include_drafts: bool = True, cache: FileCache | None = None, client: Client | None = None) -> list[Release]

Return releases for a GitHub repository as :class:Release objects.

PARAMETER DESCRIPTION
path

Repository path "owner/repo" (e.g. "cli/cli").

TYPE: str

backend

:class:Backend selection. Accepts a :class:Backend member or its string value ("rest" / "graphql"). Default: :attr:Backend.REST.

TYPE: Backend | str DEFAULT: REST

include_prereleases

If False, pre-releases are excluded.

TYPE: bool DEFAULT: True

include_drafts

If False, draft releases are excluded.

TYPE: bool DEFAULT: True

cache

Optional :class:FileCache override.

TYPE: FileCache | None DEFAULT: None

client

Optional injected httpx.Client (used by both backends). Tests should pass httpx.Client(transport=httpx.MockTransport(...)).

TYPE: Client | None DEFAULT: None

RAISES DESCRIPTION
ValueError

path is not "owner/repo", or backend is not a valid :class:Backend value.

ConfigurationError

GITHUB_TOKEN is missing (GraphQL only).

TransportError

HTTP failure.

ApiResponseError

Server returned an unusable payload.

Example

from ocx_mirror_sdk import github releases = github.list_releases("shellcheck/shellcheck", backend=github.Backend.REST) sorted({r.tag_name for r in releases}) # doctest: +SKIP ['v0.10.0', 'v0.9.0', ...]

Source code in src/ocx_mirror_sdk/github/_router.py
def list_releases(
    path: str,
    *,
    backend: Backend | str = Backend.REST,
    include_prereleases: bool = True,
    include_drafts: bool = True,
    cache: FileCache | None = None,
    client: httpx.Client | None = None,
) -> list[Release]:
    """Return releases for a GitHub repository as :class:`Release` objects.

    Args:
        path: Repository path ``"owner/repo"`` (e.g. ``"cli/cli"``).
        backend: :class:`Backend` selection. Accepts a :class:`Backend`
            member or its string value (``"rest"`` / ``"graphql"``).
            Default: :attr:`Backend.REST`.
        include_prereleases: If ``False``, pre-releases are excluded.
        include_drafts: If ``False``, draft releases are excluded.
        cache: Optional :class:`FileCache` override.
        client: Optional injected ``httpx.Client`` (used by both backends).
            Tests should pass ``httpx.Client(transport=httpx.MockTransport(...))``.

    Raises:
        ValueError: ``path`` is not ``"owner/repo"``, or ``backend`` is not a
            valid :class:`Backend` value.
        ConfigurationError: ``GITHUB_TOKEN`` is missing (GraphQL only).
        TransportError: HTTP failure.
        ApiResponseError: Server returned an unusable payload.

    Example:
        >>> from ocx_mirror_sdk import github
        >>> releases = github.list_releases("shellcheck/shellcheck", backend=github.Backend.REST)
        >>> sorted({r.tag_name for r in releases})  # doctest: +SKIP
        ['v0.10.0', 'v0.9.0', ...]
    """
    owner, repo = _split_repo_path(path)
    backend = Backend(backend)
    try:
        if backend is Backend.REST:
            return list_releases_rest(
                owner,
                repo,
                include_prereleases=include_prereleases,
                include_drafts=include_drafts,
                cache=cache,
                client=client,
            )
        # Backend.GRAPHQL
        return list_releases_graphql(
            owner,
            repo,
            include_prereleases=include_prereleases,
            include_drafts=include_drafts,
            cache=cache,
            client=client,
        )
    except OcxMirrorError as e:
        log.warning("list_releases(%s, backend=%s) failed: %s", path, backend, e)
        raise

Backend

ocx_mirror_sdk.github._router.Backend

Bases: StrEnum

GitHub release-fetch backend selection.

Values

REST: httpx-backed REST API. Default. Cheap on rate budget (request-count limited, asset lists inline) and pages adaptively, so it handles asset-heavy repos too. GRAPHQL: httpx-backed GraphQL API. Points-budget limited; prefer REST unless a specific repo needs it.

gitlab.list_releases

ocx_mirror_sdk.gitlab._rest.list_releases

list_releases(path: str, *, host: str = DEFAULT_HOST, include_prereleases: bool = True, cache: FileCache | None = None, client: Client | None = None) -> list[Release]

Return releases for a GitLab project as :class:Release objects.

PARAMETER DESCRIPTION
path

Project path "namespace/project". The namespace may contain nested subgroups (e.g. "gitlab-org/security/tooling"); only the final segment is the project name.

TYPE: str

host

GitLab instance base URL. Default: "https://gitlab.com". Set this for self-hosted instances (e.g. "https://gitlab.example.com").

TYPE: str DEFAULT: DEFAULT_HOST

include_prereleases

If False, upcoming (pre-)releases are excluded.

TYPE: bool DEFAULT: True

cache

Optional :class:FileCache override.

TYPE: FileCache | None DEFAULT: None

client

Optional injected httpx.Client (tests pass a MockTransport client).

TYPE: Client | None DEFAULT: None

RAISES DESCRIPTION
ValueError

path is not "namespace/project".

TransportError

HTTP failure (e.g. HttpStatusError 404 when the project does not exist or is private).

ApiResponseError

Server returned an unusable payload.

Example

from ocx_mirror_sdk import gitlab releases = gitlab.list_releases("gitlab-org/gitlab-runner") # doctest: +SKIP sorted({r.tag_name for r in releases}) # doctest: +SKIP ['v16.0.0', 'v16.1.0', ...]

Source code in src/ocx_mirror_sdk/gitlab/_rest.py
def list_releases(
    path: str,
    *,
    host: str = DEFAULT_HOST,
    include_prereleases: bool = True,
    cache: FileCache | None = None,
    client: httpx.Client | None = None,
) -> list[Release]:
    """Return releases for a GitLab project as :class:`Release` objects.

    Args:
        path: Project path ``"namespace/project"``. The namespace may contain
            nested subgroups (e.g. ``"gitlab-org/security/tooling"``); only the
            final segment is the project name.
        host: GitLab instance base URL. Default: ``"https://gitlab.com"``.
            Set this for self-hosted instances (e.g. ``"https://gitlab.example.com"``).
        include_prereleases: If ``False``, upcoming (pre-)releases are excluded.
        cache: Optional :class:`FileCache` override.
        client: Optional injected ``httpx.Client`` (tests pass a
            ``MockTransport`` client).

    Raises:
        ValueError: ``path`` is not ``"namespace/project"``.
        TransportError: HTTP failure (e.g. ``HttpStatusError`` 404 when the
            project does not exist or is private).
        ApiResponseError: Server returned an unusable payload.

    Example:
        >>> from ocx_mirror_sdk import gitlab
        >>> releases = gitlab.list_releases("gitlab-org/gitlab-runner")  # doctest: +SKIP
        >>> sorted({r.tag_name for r in releases})  # doctest: +SKIP
        ['v16.0.0', 'v16.1.0', ...]
    """
    namespace, project = _split_project_path(path)
    try:
        return _do_list_releases(
            namespace,
            project,
            host=host,
            include_prereleases=include_prereleases,
            cache=cache,
            client=client,
        )
    except OcxMirrorError as e:
        log.warning("gitlab.list_releases(%s @ %s) failed: %s", path, host, e)
        raise

Asset

ocx_mirror_sdk.releases.Asset dataclass

Asset(name: str, browser_download_url: str)

A downloadable file attached to a release.

ATTRIBUTE DESCRIPTION
name

Filename of the asset (e.g. "node-v22.15.0-linux-x64.tar.gz").

TYPE: str

browser_download_url

Stable HTTPS URL the asset can be downloaded from.

TYPE: str

Release

ocx_mirror_sdk.releases.Release dataclass

Release(tag_name: str, body: str, prerelease: bool, draft: bool, assets: list[Asset])

A release with its metadata and assets.

ATTRIBUTE DESCRIPTION
tag_name

The release tag (e.g. "v22.15.0").

TYPE: str

body

Release-notes body (may be empty).

TYPE: str

prerelease

Whether the release is flagged as pre-release upstream.

TYPE: bool

draft

Whether the release is a draft.

TYPE: bool

assets

List of downloadable :class:Asset objects.

TYPE: list[Asset]

to_dict

to_dict() -> dict[str, Any]

Return a JSON-serializable dict representation.

Source code in src/ocx_mirror_sdk/releases.py
def to_dict(self) -> dict[str, Any]:
    """Return a JSON-serializable dict representation."""
    return {
        "tag_name": self.tag_name,
        "body": self.body,
        "prerelease": self.prerelease,
        "draft": self.draft,
        "assets": [{"name": a.name, "browser_download_url": a.browser_download_url} for a in self.assets],
    }

from_dict classmethod

from_dict(data: dict[str, Any]) -> Release

Construct a :class:Release from a JSON-decoded dict.

RAISES DESCRIPTION
SchemaError

A required field is missing or wrongly typed.

Source code in src/ocx_mirror_sdk/releases.py
@classmethod
def from_dict(cls, data: dict[str, Any]) -> Release:
    """Construct a :class:`Release` from a JSON-decoded dict.

    Raises:
        SchemaError: A required field is missing or wrongly typed.
    """
    try:
        return cls(
            tag_name=data["tag_name"],
            body=data.get("body", "") or "",
            prerelease=data["prerelease"],
            draft=data["draft"],
            assets=[Asset(name=a["name"], browser_download_url=a["browser_download_url"]) for a in data["assets"]],
        )
    except KeyError as e:
        field = e.args[0] if e.args else None
        raise SchemaError("missing required field", field=field) from e
    except TypeError as e:
        raise SchemaError("wrong field type") from e