Skip to content
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
2 changes: 2 additions & 0 deletions docs/user/api/v3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ Project details
"privacy_level": "public",
"external_builds_privacy_level": "public",
"versioning_scheme": "multiple_versions_with_translations",
"readthedocs_yaml_path": null,
"_links": {
"_self": "/api/v3/projects/pip/",
"versions": "/api/v3/projects/pip/versions/",
Expand Down Expand Up @@ -466,6 +467,7 @@ Project update
"analytics_code": "UA000000",
"analytics_disabled": false,
"versioning_scheme": "multiple_versions_with_translations",
"readthedocs_yaml_path": "docs/.readthedocs.yaml",
"external_builds_enabled": true,
"privacy_level": "public",
"external_builds_privacy_level": "public"
Expand Down
9 changes: 9 additions & 0 deletions readthedocs/api/v3/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from readthedocs.projects.models import EnvironmentVariable
from readthedocs.projects.models import Project
from readthedocs.projects.models import ProjectRelationship
from readthedocs.projects.validators import normalize_readthedocs_yaml_path
from readthedocs.projects.validators import validate_environment_variable_size
from readthedocs.redirects.constants import TYPE_CHOICES as REDIRECT_TYPE_CHOICES
from readthedocs.redirects.models import Redirect
Expand Down Expand Up @@ -700,6 +701,7 @@ class Meta:
"external_builds_enabled",
"privacy_level",
"external_builds_privacy_level",
"readthedocs_yaml_path",
# NOTE: we do not allow to change any setting that can be set via
# the YAML config file.
)
Expand All @@ -712,6 +714,9 @@ def __init__(self, *args, **kwargs):
self.fields.pop("privacy_level")
self.fields.pop("external_builds_privacy_level")

def validate_readthedocs_yaml_path(self, value):
return normalize_readthedocs_yaml_path(value)


class ProjectUpdateSerializer(SettingsOverrideObject):
_default_class = ProjectUpdateSerializerBase
Expand Down Expand Up @@ -794,6 +799,7 @@ class Meta:
"urls",
"tags",
"privacy_level",
"readthedocs_yaml_path",
"external_builds_privacy_level",
"versioning_scheme",
# Kept for backwards compatibility,
Expand Down Expand Up @@ -853,6 +859,9 @@ def get_homepage(self, obj):
# Overridden only to return ``None`` when the project_url is ``''``
return obj.project_url or None

def validate_readthedocs_yaml_path(self, value):
return normalize_readthedocs_yaml_path(value)

def get_translation_of(self, obj):
if obj.main_language_project:
# Since the related project can be private, we use a restricted serializer.
Expand Down
1 change: 1 addition & 0 deletions readthedocs/api/v3/tests/responses/projects-detail.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"test"
],
"translation_of": null,
"readthedocs_yaml_path": null,
"urls": {
"builds": "https://readthedocs.org/projects/project/builds/",
"documentation": "http://project.readthedocs.io/en/latest/",
Expand Down
1 change: 1 addition & 0 deletions readthedocs/api/v3/tests/responses/projects-list.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"default_branch": "master",
"subproject_of": null,
"translation_of": null,
"readthedocs_yaml_path": null,
"urls": {
"builds": "https://readthedocs.org/projects/project/builds/",
"documentation": "http://project.readthedocs.io/en/latest/",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"subproject_of": null,
"tags": ["template tag", "test tag"],
"translation_of": null,
"readthedocs_yaml_path": null,
"urls": {
"builds": "https://readthedocs.org/projects/test-project/builds/",
"documentation": "http://test-project.readthedocs.io/en/latest/",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"slug": "subproject",
"tags": [],
"translation_of": null,
"readthedocs_yaml_path": null,
"urls": {
"builds": "https://readthedocs.org/projects/subproject/builds/",
"documentation": "http://project.readthedocs.io/projects/subproject/en/latest/",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"slug": "subproject",
"tags": [],
"translation_of": null,
"readthedocs_yaml_path": null,
"urls": {
"builds": "https://readthedocs.org/projects/subproject/builds/",
"documentation": "http://project.readthedocs.io/projects/subproject/en/latest/",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"slug": "new-project",
"tags": [],
"translation_of": null,
"readthedocs_yaml_path": null,
"urls": {
"builds": "https://readthedocs.org/projects/new-project/builds/",
"documentation": "http://project.readthedocs.io/projects/subproject-alias/en/latest/",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"test"
],
"translation_of": null,
"readthedocs_yaml_path": null,
"urls": {
"builds": "https://readthedocs.org/projects/project/builds/",
"documentation": "http://project.readthedocs.io/en/latest/",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"test"
],
"translation_of": null,
"readthedocs_yaml_path": null,
"urls": {
"builds": "https://readthedocs.org/projects/project/builds/",
"documentation": "http://project.readthedocs.io/en/latest/",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"subproject_of": null,
"tags": ["project", "tag", "test"],
"translation_of": null,
"readthedocs_yaml_path": null,
"urls": {
"builds": "https://readthedocs.org/projects/project/builds/",
"documentation": "http://project.readthedocs.io/en/latest/",
Expand Down
32 changes: 32 additions & 0 deletions readthedocs/api/v3/tests/test_projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,38 @@ def test_partial_update_project(self):
self.assertEqual(list(self.project.tags.names()), ["partial tags", "updated"])
self.assertNotEqual(self.project.default_version, "updated-default-branch")

def test_partial_update_project_readthedocs_yaml_path(self):
"""Test that readthedocs_yaml_path can be set via PATCH and is returned in GET."""
url = reverse(
"projects-detail",
kwargs={
"project_slug": self.project.slug,
},
)

self.client.credentials(HTTP_AUTHORIZATION=f"Token {self.token.key}")

# Verify the initial value is None
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertIsNone(response.json()["readthedocs_yaml_path"])

# Set the readthedocs_yaml_path field
yaml_path = " docs/.readthedocs.yaml "
yaml_path_expected = "docs/.readthedocs.yaml"
data = {"readthedocs_yaml_path": yaml_path}
response = self.client.patch(url, data)
self.assertEqual(response.status_code, 204)

# Verify it was saved to the database
self.project.refresh_from_db()
self.assertEqual(self.project.readthedocs_yaml_path, yaml_path_expected)

# Verify it's returned in the GET response
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()["readthedocs_yaml_path"], yaml_path_expected)

def test_partial_update_others_project(self):
data = {
"name": "Updated name",
Expand Down
4 changes: 2 additions & 2 deletions readthedocs/projects/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from readthedocs.projects.models import ProjectRelationship
from readthedocs.projects.models import WebHook
from readthedocs.projects.templatetags.projects_tags import sort_version_aware
from readthedocs.projects.validators import normalize_readthedocs_yaml_path
from readthedocs.redirects.models import Redirect


Expand Down Expand Up @@ -507,8 +508,7 @@ def clean_readthedocs_yaml_path(self):
only considered as helpful to a user, not a security measure.
"""
filename = self.cleaned_data.get("readthedocs_yaml_path")
filename = (filename or "").strip()
return filename
return normalize_readthedocs_yaml_path(filename)

def get_all_active_versions(self):
"""
Expand Down
5 changes: 5 additions & 0 deletions readthedocs/projects/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,3 +243,8 @@ def validate_environment_variable_size(project, new_env_value, error_class=Valid
raise error_class(
_("The total size of all environment variables in the project cannot exceed 256 KB.")
)


def normalize_readthedocs_yaml_path(value):
"""Normalize user input for the path to ``.readthedocs.yaml``."""
return (value or "").strip()
1 change: 1 addition & 0 deletions readthedocs/proxito/tests/responses/v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"type": "git",
"url": "https://github.com/readthedocs/project"
},
"readthedocs_yaml_path": null,
"single_version": false,
"versioning_scheme": "multiple_versions_with_translations",
"slug": "project",
Expand Down