Skip to content

Commit 88f44ed

Browse files
authored
Build: use actual git identifier for READTHEDOCS_GIT_IDENTIFIER (#11875)
A commit can point to more than one branch/tag, so using git describe/name-rev or similar doesn't work reliably. Since we already have the tag/branch name for most of the versions (verbose_name), we can just use that, there are only three special cases: - LATEST: this is an alias for the default branch - STABLE: this is an alias for the stable version - External versions: we don't save the name of the base branch, just the commit and PR number, so not sure what to return here, I'm returning the commit for now. Maybe we can update the docs to mention this. `commit_name` was doing exactly that, except for stable, so I went ahead and renamed it and refactored it (we were no longer using it) to use it in our API, so builders have access to it. Closes #11662
1 parent 882ebdb commit 88f44ed

File tree

8 files changed

+62
-68
lines changed

8 files changed

+62
-68
lines changed

readthedocs/api/v2/serializers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ class Meta(VersionSerializer.Meta):
187187
"build_data",
188188
"canonical_url",
189189
"machine",
190+
"git_identifier",
190191
]
191192

192193

readthedocs/builds/models.py

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
PREDEFINED_MATCH_ARGS,
3232
PREDEFINED_MATCH_ARGS_VALUES,
3333
STABLE,
34-
TAG,
3534
VERSION_TYPES,
3635
)
3736
from readthedocs.builds.managers import (
@@ -330,50 +329,38 @@ def config(self):
330329
return None
331330

332331
@property
333-
def commit_name(self):
332+
def git_identifier(self):
334333
"""
335-
Return the branch name, the tag name or the revision identifier.
334+
Return the branch or tag name of the version.
336335
337336
The result could be used as ref in a git repo, e.g. for linking to
338337
GitHub, Bitbucket or GitLab.
338+
339+
- If the version is latest (machine created), we resolve to the default branch of the project.
340+
- If the version is stable (machine created), we resolve to the branch that the stable version points to.
341+
- If the version is external, we return the identifier, since we don't have access to the name of the branch.
339342
"""
340-
# LATEST is special as it is usually a branch but does not contain the
341-
# name in verbose_name.
343+
# Latest is special as it doesn't contain the actual name in verbose_name.
342344
if self.slug == LATEST and self.machine:
343345
return self.project.get_default_branch()
344346

347+
# Stable is special as it doesn't contain the actual name in verbose_name.
345348
if self.slug == STABLE and self.machine:
346-
if self.type == BRANCH:
347-
# Special case, as we do not store the original branch name
348-
# that the stable version works on. We can only interpolate the
349-
# name from the commit identifier, but it's hacky.
350-
# TODO: Refactor ``Version`` to store more actual info about
351-
# the underlying commits.
352-
if self.identifier.startswith("origin/"):
353-
return self.identifier[len("origin/") :]
354-
return self.identifier
355-
356-
if self.type in (BRANCH, TAG):
357-
# If this version is a branch or a tag, the verbose_name will
358-
# contain the actual name. We cannot use identifier as this might
359-
# include the "origin/..." part in the case of a branch. A tag
360-
# would contain the hash in identifier, which is not as pretty as
361-
# the actual tag name.
362-
return self.verbose_name
349+
original_stable = self.project.get_original_stable_version()
350+
# NOTE: we no longer save branch names with the "origin/" prefix,
351+
# but we remove it for old versions.
352+
if original_stable:
353+
return original_stable.verbose_name.removeprefix("origin/")
354+
return self.identifier.removeprefix("origin/")
363355

364356
if self.type == EXTERNAL:
365357
# If this version is a EXTERNAL version, the identifier will
366358
# contain the actual commit hash. which we can use to
367359
# generate url for a given file name
368360
return self.identifier
369361

370-
# If we came that far it's not a special version
371-
# nor a branch, tag or EXTERNAL version.
372-
# Therefore just return the identifier to make a safe guess.
373-
log.debug(
374-
"TODO: Raise an exception here. Testing what cases it happens",
375-
)
376-
return self.identifier
362+
# For all other cases, verbose_name contains the actual name of the branch/tag.
363+
return self.verbose_name
377364

378365
def get_absolute_url(self):
379366
"""
@@ -561,13 +548,18 @@ class APIVersion(Version):
561548
"""
562549

563550
project = None
551+
# This is a property in the original model, in order to
552+
# be able to assign it a value in the constructor, we need to re-declare it
553+
# as an attribute here.
554+
git_identifier = None
564555

565556
class Meta:
566557
proxy = True
567558

568559
def __init__(self, *args, **kwargs):
569560
self.project = APIProject(**kwargs.pop("project", {}))
570561
self.canonical_url = kwargs.pop("canonical_url", None)
562+
self.git_identifier = kwargs.pop("git_identifier", None)
571563
# These fields only exist on the API return, not on the model, so we'll
572564
# remove them to avoid throwing exceptions due to unexpected fields
573565
for key in ["resource_uri", "absolute_url", "downloads"]:

readthedocs/doc_builder/director.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,7 @@ def get_rtd_env_vars(self):
696696
# TODO: we don't have access to the database from the builder.
697697
# We need to find a way to expose HTML_URL here as well.
698698
# "READTHEDOCS_GIT_HTML_URL": self.data.project.remote_repository.html_url,
699-
"READTHEDOCS_GIT_IDENTIFIER": self.data.version.identifier,
699+
"READTHEDOCS_GIT_IDENTIFIER": self.data.version.git_identifier,
700700
"READTHEDOCS_GIT_COMMIT_HASH": self.data.build["commit"],
701701
"READTHEDOCS_PRODUCTION_DOMAIN": settings.PRODUCTION_DOMAIN,
702702
}

readthedocs/projects/tests/test_build_tasks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ def test_get_env_vars(self, load_yaml_config, build_environment, config, externa
372372
self.project.checkout_path(self.version.slug), "_readthedocs/"
373373
),
374374
"READTHEDOCS_GIT_CLONE_URL": self.project.repo,
375-
"READTHEDOCS_GIT_IDENTIFIER": self.version.identifier,
375+
"READTHEDOCS_GIT_IDENTIFIER": self.version.git_identifier,
376376
"READTHEDOCS_GIT_COMMIT_HASH": self.build.commit,
377377
"READTHEDOCS_PRODUCTION_DOMAIN": settings.PRODUCTION_DOMAIN,
378378
}

readthedocs/rtd_tests/tests/test_api.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3292,6 +3292,7 @@ def test_get_version_by_id(self):
32923292
"privacy_level": "public",
32933293
"downloads": {},
32943294
"identifier": "2404a34eba4ee9c48cc8bc4055b99a48354f4950",
3295+
"git_identifier": "0.8",
32953296
"slug": "0.8",
32963297
"has_epub": False,
32973298
"has_htmlzip": False,

readthedocs/rtd_tests/tests/test_project_forms.py

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -478,29 +478,6 @@ def test_list_user_created_latest_and_stable_versions_in_default_branch_choices(
478478
],
479479
)
480480

481-
def test_commit_name_not_in_default_branch_choices(self):
482-
form = UpdateProjectForm(instance=self.project)
483-
# This version is created by the user
484-
latest = self.project.versions.filter(slug=LATEST)
485-
# This version is created by the user
486-
stable = self.project.versions.filter(slug=STABLE)
487-
488-
# `commit_name` can not be used as the value for the choices
489-
self.assertNotIn(
490-
latest.first().commit_name,
491-
[
492-
identifier
493-
for identifier, _ in form.fields["default_branch"].widget.choices
494-
],
495-
)
496-
self.assertNotIn(
497-
stable.first().commit_name,
498-
[
499-
identifier
500-
for identifier, _ in form.fields["default_branch"].widget.choices
501-
],
502-
)
503-
504481
def test_external_version_not_in_default_branch_choices(self):
505482
external_version = get(
506483
Version,

readthedocs/rtd_tests/tests/test_version.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,15 @@ def test_vcs_url_for_manual_stable_version(self):
9494
stable.save()
9595
assert "https://github.com/pypa/pip/tree/stable/" == stable.vcs_url
9696

97-
def test_commit_name_for_stable_version(self):
98-
self.assertEqual(self.branch_version.commit_name, "stable")
97+
def test_git_identifier_for_stable_version(self):
98+
self.assertEqual(self.branch_version.git_identifier, "stable")
9999

100-
def test_commit_name_for_latest_version(self):
101-
self.assertEqual(self.tag_version.commit_name, "master")
100+
def test_git_identifier_for_latest_version(self):
101+
self.assertEqual(self.tag_version.git_identifier, "master")
102102

103-
def test_commit_name_for_external_version(self):
103+
def test_git_identifier_for_external_version(self):
104104
self.assertEqual(
105-
self.external_version.commit_name, self.external_version.identifier
105+
self.external_version.git_identifier, self.external_version.identifier
106106
)
107107

108108
@override_settings(

readthedocs/rtd_tests/tests/test_version_commit_name.py

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def test_branch_name(self):
3333
verbose_name="release-2.5.x",
3434
type=BRANCH,
3535
)
36-
self.assertEqual(version.commit_name, "release-2.5.x")
36+
self.assertEqual(version.git_identifier, "release-2.5.x")
3737

3838
def test_tag_name(self):
3939
version = new(
@@ -43,7 +43,7 @@ def test_tag_name(self):
4343
verbose_name="release-2.5.0",
4444
type=TAG,
4545
)
46-
self.assertEqual(version.commit_name, "release-2.5.0")
46+
self.assertEqual(version.git_identifier, "release-2.5.0")
4747

4848
def test_branch_with_name_stable(self):
4949
version = new(
@@ -53,7 +53,7 @@ def test_branch_with_name_stable(self):
5353
verbose_name="stable",
5454
type=BRANCH,
5555
)
56-
self.assertEqual(version.commit_name, "stable")
56+
self.assertEqual(version.git_identifier, "stable")
5757

5858
def test_stable_version_tag(self):
5959
version = new(
@@ -65,10 +65,33 @@ def test_stable_version_tag(self):
6565
machine=True,
6666
)
6767
self.assertEqual(
68-
version.commit_name,
68+
version.git_identifier,
6969
"3d92b728b7d7b842259ac2020c2fa389f13aff0d",
7070
)
7171

72+
def test_stable_version_tag_uses_original_stable(self):
73+
project = get(Project)
74+
stable = get(
75+
Version,
76+
project=project,
77+
identifier="3d92b728b7d7b842259ac2020c2fa389f13aff0d",
78+
slug=STABLE,
79+
verbose_name=STABLE,
80+
type=TAG,
81+
machine=True,
82+
)
83+
original_stable = get(
84+
Version,
85+
project=project,
86+
identifier="3d92b728b7d7b842259ac2020c2fa389f13aff0d",
87+
slug="v2.0",
88+
verbose_name="v2.0",
89+
type=TAG,
90+
machine=True,
91+
)
92+
self.assertEqual(stable.git_identifier, "v2.0")
93+
self.assertEqual(original_stable.git_identifier, "v2.0")
94+
7295
def test_manual_stable_version(self):
7396
project = get(Project)
7497
version = get(
@@ -80,7 +103,7 @@ def test_manual_stable_version(self):
80103
type=BRANCH,
81104
machine=False,
82105
)
83-
self.assertEqual(version.commit_name, "stable")
106+
self.assertEqual(version.git_identifier, "stable")
84107

85108
def test_git_latest_branch(self):
86109
git_project = get(Project, repo_type=REPO_TYPE_GIT)
@@ -93,14 +116,14 @@ def test_git_latest_branch(self):
93116
type=BRANCH,
94117
machine=True,
95118
)
96-
self.assertEqual(version.commit_name, "master")
119+
self.assertEqual(version.git_identifier, "master")
97120

98121
def test_manual_latest_version(self):
99122
project = get(Project)
100123
version = project.versions.get(slug=LATEST)
101124
version.machine = False
102125
version.save()
103-
self.assertEqual(version.commit_name, "latest")
126+
self.assertEqual(version.git_identifier, "latest")
104127

105128
def test_external_version(self):
106129
identifier = "ec26de721c3235aad62de7213c562f8c821"
@@ -111,4 +134,4 @@ def test_external_version(self):
111134
verbose_name="11",
112135
type=EXTERNAL,
113136
)
114-
self.assertEqual(version.commit_name, identifier)
137+
self.assertEqual(version.git_identifier, identifier)

0 commit comments

Comments
 (0)