Skip to content

Create a dataclass for version info #12205

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions readthedocs/api/v2/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ def sync_versions_to_db(project, versions, type):
has_user_stable = False
has_user_latest = False
for version in versions:
version_id = version["identifier"]
version_name = version["verbose_name"]
version_id = version.identifier
version_name = version.verbose_name
if version_name == STABLE_VERBOSE_NAME:
has_user_stable = True
created_version, created = _set_or_create_version(
Expand Down Expand Up @@ -170,8 +170,8 @@ def _set_or_create_version(project, slug, version_id, verbose_name, type_):
def _get_deleted_versions_qs(project, tags_data, branches_data):
# We use verbose_name for tags
# because several tags can point to the same identifier.
versions_tags = [version["verbose_name"] for version in tags_data]
versions_branches = [version["identifier"] for version in branches_data]
versions_tags = [version.verbose_name for version in tags_data]
versions_branches = [version.identifier for version in branches_data]

to_delete_qs = (
project.versions(manager=INTERNAL)
Expand Down
30 changes: 21 additions & 9 deletions readthedocs/builds/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from readthedocs.integrations.models import HttpExchange
from readthedocs.notifications.models import Notification
from readthedocs.oauth.notifications import MESSAGE_OAUTH_BUILD_STATUS_FAILURE
from readthedocs.projects.datatypes import ProjectVersionInfo
from readthedocs.projects.models import Project
from readthedocs.projects.models import WebHookEvent
from readthedocs.storage import build_commands_storage
Expand Down Expand Up @@ -274,22 +275,33 @@ def delete_closed_external_versions(limit=200, days=30 * 3):


@app.task(max_retries=1, default_retry_delay=60, queue="web")
def sync_versions_task(project_pk, tags_data, branches_data, **kwargs):
def sync_versions_task(
project_pk: int,
tags_data: list[ProjectVersionInfo],
branches_data: list[ProjectVersionInfo],
**kwargs: object,
):
"""
Sync the version data in the repo (from build server) into our database.

Creates new Version objects for tags/branches that aren't tracked in the database,
and deletes Version objects for tags/branches that don't exists in the repository.
Creates new Version objects for tags/branches that aren't tracked in the
database, and deletes Version objects for tags/branches that don't exists
in the repository.

:param tags_data: List of dictionaries with ``verbose_name`` and ``identifier``
:param tags_data: List of version descriptions
Example: [
{"verbose_name": "v1.0.0",
"identifier": "67a9035990f44cb33091026d7453d51606350519"},
ProjectVersionInfo(
verbose_name="v1.0.0",
identifier="67a9035990f44cb33091026d7453d51606350519",
)
].
:param branches_data: Same as ``tags_data`` but for branches (branch name, branch identifier).
:param branches_data: Same as ``tags_data`` but for branches (branch name,
branch identifier).
Example: [
{"verbose_name": "latest",
"identifier": "main"},
ProjectVersionInfo(
verbose_name="latest",
identifier="main",
)
].
:returns: `True` or `False` if the task succeeded.
"""
Expand Down
23 changes: 23 additions & 0 deletions readthedocs/projects/datatypes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""Simple datatypes defined using dataclasses, for describing project data.

Contrast this with the similar 'models' module, which defines Pydantic model
classes.
"""

import dataclasses


@dataclasses.dataclass
class ProjectVersionInfo:
"""
Version information for a project associated with a branch or tag.

The name fields is the end-user facing description, e.g., as seen in the
version selector menu.

The identifier identifies the source for the build, e.g., a branch or
commit hash.
"""

verbose_name: str
identifier: str
26 changes: 15 additions & 11 deletions readthedocs/projects/tasks/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from readthedocs.builds.constants import STABLE_VERBOSE_NAME
from readthedocs.builds.models import APIVersion

from ..datatypes import ProjectVersionInfo
from ..exceptions import RepositoryError
from ..models import Feature

Expand Down Expand Up @@ -50,18 +51,18 @@ def sync_versions(self, vcs_repository):
)

tags_data = [
{
"identifier": v.identifier,
"verbose_name": v.verbose_name,
}
ProjectVersionInfo(
verbose_name=v.verbose_name,
identifier=v.identifier,
)
for v in tags
]

branches_data = [
{
"identifier": v.identifier,
"verbose_name": v.verbose_name,
}
ProjectVersionInfo(
verbose_name=v.verbose_name,
identifier=v.identifier,
)
for v in branches
]

Expand All @@ -78,7 +79,11 @@ def sync_versions(self, vcs_repository):
branches_data=branches_data,
)

def validate_duplicate_reserved_versions(self, tags_data, branches_data):
def validate_duplicate_reserved_versions(
self,
tags_data: list[ProjectVersionInfo],
branches_data: list[ProjectVersionInfo],
) -> None:
"""
Check if there are duplicated names of reserved versions.

Expand All @@ -88,8 +93,7 @@ def validate_duplicate_reserved_versions(self, tags_data, branches_data):

:param data: Dict containing the versions from tags and branches
"""
version_names = [version["verbose_name"] for version in tags_data + branches_data]
counter = Counter(version_names)
counter = Counter(v.verbose_name for v in tags_data + branches_data)
for reserved_name in [STABLE_VERBOSE_NAME, LATEST_VERBOSE_NAME]:
if counter[reserved_name] > 1:
raise RepositoryError(
Expand Down
Loading