Skip to content
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

Versions: allow latest to be a tag #10738

Merged
merged 5 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 0 additions & 4 deletions readthedocs/api/v2/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,6 @@ def sync_versions_to_db(project, versions, type):
if latest_version:
# Put back the RTD's latest version
latest_version.machine = True
latest_version.identifier = project.get_default_branch()
latest_version.verbose_name = LATEST_VERBOSE_NAME
# The machine created latest version always points to a branch.
latest_version.type = BRANCH
latest_version.save()
if added:
log.info(
Expand Down
2 changes: 2 additions & 0 deletions readthedocs/builds/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ def sync_versions_task(project_pk, tags_data, branches_data, **kwargs):
versions=added_versions,
)

# Sync latest and stable to match the correct type and identifier.
project.update_latest_version()
# TODO: move this to an automation rule
promoted_version = project.update_stable_version()
new_stable = project.get_stable_version()
Expand Down
45 changes: 40 additions & 5 deletions readthedocs/projects/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,14 @@
from django_extensions.db.models import TimeStampedModel
from taggit.managers import TaggableManager

from readthedocs.builds.constants import EXTERNAL, INTERNAL, LATEST, STABLE
from readthedocs.builds.constants import (
BRANCH,
EXTERNAL,
INTERNAL,
LATEST,
LATEST_VERBOSE_NAME,
STABLE,
)
from readthedocs.core.history import ExtraHistoricalRecords
from readthedocs.core.resolver import resolve, resolve_domain
from readthedocs.core.utils import extract_valid_attributes_for_model, slugify
Expand Down Expand Up @@ -52,10 +59,7 @@
from readthedocs.storage import build_media_storage
from readthedocs.vcs_support.backends import backend_cls

from .constants import (
DOWNLOADABLE_MEDIA_TYPES,
MEDIA_TYPES,
)
from .constants import DOWNLOADABLE_MEDIA_TYPES, MEDIA_TYPES

log = structlog.get_logger(__name__)

Expand Down Expand Up @@ -1040,6 +1044,37 @@ def get_original_stable_version(self):
)
return original_stable

def update_latest_version(self):
"""
If the current latest version is machine created, update it.

A machine created LATEST version is an alias for the default branch/tag,
so we need to update it to match the type and identifier of the default branch/tag.
"""
latest = self.versions.filter(slug=LATEST).first()
if not latest:
latest = self.versions.create_latest()
if not latest.machine:
return

# default_branch can be a tag or a branch name!
default_version_name = self.get_default_branch()
original_latest_type = (
self.versions(manager=INTERNAL)
.exclude(slug=LATEST)
humitos marked this conversation as resolved.
Show resolved Hide resolved
.filter(
verbose_name=default_version_name,
)
.values_list("type", flat=True)
.first()
)
latest.verbose_name = LATEST_VERBOSE_NAME
latest.type = original_latest_type or BRANCH
# For latest, the identifier is the name of the branch/tag.
latest.identifier = default_version_name
latest.save()
return latest

def update_stable_version(self):
"""
Returns the version that was promoted to be the new stable version.
Expand Down
47 changes: 47 additions & 0 deletions readthedocs/rtd_tests/tests/test_sync_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,53 @@ def test_update_latest_version_type(self):
self.assertEqual(latest_version.verbose_name, "latest")
self.assertEqual(latest_version.machine, True)

# Latest points to the default branch/tag.
self.pip.default_branch = "2.6"
self.pip.save()

sync_versions_task(
self.pip.pk,
branches_data=[
{
"identifier": "master",
"verbose_name": "master",
},
{
"identifier": "2.6",
"verbose_name": "2.6",
},
],
tags_data=[],
)

latest_version = self.pip.versions.get(slug=LATEST)
self.assertEqual(latest_version.type, BRANCH)
self.assertEqual(latest_version.identifier, "2.6")
self.assertEqual(latest_version.verbose_name, "latest")
self.assertEqual(latest_version.machine, True)

sync_versions_task(
self.pip.pk,
branches_data=[
{
"identifier": "master",
"verbose_name": "master",
},
],
tags_data=[
{
"identifier": "abc123",
"verbose_name": "2.6",
}
],
)

latest_version = self.pip.versions.get(slug=LATEST)
self.assertEqual(latest_version.type, TAG)
self.assertEqual(latest_version.identifier, "2.6")
self.assertEqual(latest_version.verbose_name, "latest")
self.assertEqual(latest_version.machine, True)

def test_machine_attr_when_user_define_stable_tag_and_delete_it(self):
"""
The user creates a tag named ``stable`` on an existing repo,
Expand Down
19 changes: 16 additions & 3 deletions readthedocs/vcs_support/backends/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@

import structlog

from readthedocs.builds.constants import BRANCH, EXTERNAL, TAG
from readthedocs.builds.constants import (
BRANCH,
EXTERNAL,
LATEST_VERBOSE_NAME,
STABLE_VERBOSE_NAME,
TAG,
)
from readthedocs.config import ALL
from readthedocs.projects.constants import (
GITHUB_BRAND,
Expand Down Expand Up @@ -115,12 +121,19 @@ def get_remote_fetch_refspec(self):
# denoting that it's not a branch/tag that really exists.
# Because we don't know if it originates from the default branch or some
# other tagged release, we will fetch the exact commit it points to.
if self.version_machine and self.verbose_name == "stable":
if self.version_machine and self.verbose_name == STABLE_VERBOSE_NAME:
if self.version_identifier:
return f"{self.version_identifier}"
log.error("'stable' version without a commit hash.")
return None
return f"refs/tags/{self.verbose_name}:refs/tags/{self.verbose_name}"

tag_name = self.verbose_name
# For a machine created "latest" tag, the name of the tag is set
# in the `Version.identifier` field, note that it isn't a commit
# hash, but the name of the tag.
if self.version_machine and self.verbose_name == LATEST_VERBOSE_NAME:
tag_name = self.version_identifier
return f"refs/tags/{tag_name}:refs/tags/{tag_name}"
humitos marked this conversation as resolved.
Show resolved Hide resolved

if self.version_type == EXTERNAL:
# TODO: We should be able to resolve this without looking up in oauth registry
Expand Down