Skip to content

Commit

Permalink
Project: use a choicefield for selecting the versioning scheme (#10845)
Browse files Browse the repository at this point in the history
We may want to publish a small blog post communicating this change, when updating a project with API v3, `versioning_scheme` should be used instead of `single_version`.

This looks like this:

![Screenshot from 2023-10-24 18-35-50](https://github.com/readthedocs/readthedocs.org/assets/4975310/9f08ede0-603a-4a93-b1c4-179ae370558e)
![Screenshot 2023-10-24 at 18-35-30 Edit Advanced Project Settings Read the Docs](https://github.com/readthedocs/readthedocs.org/assets/4975310/a1c5878c-087a-44bd-8492-d206a9fff9ef)

Closes #10781

### How to deploy this change

- Deploy as usual web-extra
- Run migration 0109 projects
- Deploy webs
- Run migration 0110 projects
  • Loading branch information
stsewd authored Nov 16, 2023
1 parent 9c4546c commit b5e547d
Show file tree
Hide file tree
Showing 26 changed files with 198 additions and 51 deletions.
16 changes: 14 additions & 2 deletions docs/user/api/v3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ Project details
},
"privacy_level": "public",
"external_builds_privacy_level": "public",
"single_version": false,
"versioning_scheme": "multiple_versions_with_translations",
"_links": {
"_self": "/api/v3/projects/pip/",
"versions": "/api/v3/projects/pip/versions/",
Expand All @@ -295,6 +295,13 @@ Project details
Allowed values are ``active_versions``, ``active_versions.last_build`` and
``active_versions.last_build.config``. Multiple fields can be passed separated by commas.

.. note::

``versioning_scheme`` can be one of the following values:

- ``multiple_versions_with_translations``
- ``single_version_without_translations``

.. note::

.. FIXME: we can't use :query string: here because it doesn't render properly
Expand All @@ -305,6 +312,11 @@ Project details

* **expand** (*string*) -- with ``organization`` and ``teams``.

.. note::

The ``single_version`` attribute is deprecated,
use ``versioning_scheme`` instead.

Project create
++++++++++++++

Expand Down Expand Up @@ -434,7 +446,7 @@ Project update
"default_branch": "develop",
"analytics_code": "UA000000",
"analytics_disabled": false,
"single_version": false,
"versioning_scheme": "multiple_versions_with_translations",
"external_builds_enabled": true,
"privacy_level": "public",
"external_builds_privacy_level": "public"
Expand Down
2 changes: 1 addition & 1 deletion docs/user/single-version.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ You can see a live example of this at http://www.contribution-guide.org
Enabling
~~~~~~~~

In your project's :guilabel:`Admin` page, you can toggle the :guilabel:`Single version` option on or off for your project .
In your project's :guilabel:`Admin` page, you can change the :guilabel:`Versioning scheme` option to :guilabel:`Single version without translations`.
Check your :term:`dashboard` for a list of your projects.

Effects
Expand Down
6 changes: 5 additions & 1 deletion readthedocs/api/v3/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ class Meta:
"analytics_code",
"analytics_disabled",
"show_version_warning",
"single_version",
"versioning_scheme",
"external_builds_enabled",
"privacy_level",
"external_builds_privacy_level",
Expand Down Expand Up @@ -612,6 +612,7 @@ class ProjectSerializer(FlexFieldsModelSerializer):
default_branch = serializers.CharField(source="get_default_branch")
tags = serializers.StringRelatedField(many=True)
users = UserSerializer(many=True)
single_version = serializers.BooleanField(source="is_single_version")

_links = ProjectLinksSerializer(source="*")

Expand Down Expand Up @@ -640,6 +641,9 @@ class Meta:
"tags",
"privacy_level",
"external_builds_privacy_level",
"versioning_scheme",
# Kept for backwards compatibility,
# versioning_scheme should be used instead.
"single_version",
# NOTE: ``expandable_fields`` must not be included here. Otherwise,
# they will be tried to be rendered and fail
Expand Down
3 changes: 2 additions & 1 deletion readthedocs/api/v3/tests/responses/projects-detail.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,5 +108,6 @@
],
"privacy_level": "public",
"external_builds_privacy_level": "public",
"single_version": false
"single_version": false,
"versioning_scheme": "multiple_versions_with_translations"
}
3 changes: 2 additions & 1 deletion readthedocs/api/v3/tests/responses/projects-list.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@
},
"privacy_level": "public",
"external_builds_privacy_level": "public",
"single_version": false
"single_version": false,
"versioning_scheme": "multiple_versions_with_translations"
}
]
}
3 changes: 2 additions & 1 deletion readthedocs/api/v3/tests/responses/projects-list_POST.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,6 @@
],
"privacy_level": "public",
"external_builds_privacy_level": "public",
"single_version": false
"single_version": false,
"versioning_scheme": "multiple_versions_with_translations"
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
],
"privacy_level": "public",
"external_builds_privacy_level": "public",
"single_version": false
"single_version": false,
"versioning_scheme": "multiple_versions_with_translations"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@
],
"privacy_level": "public",
"external_builds_privacy_level": "public",
"single_version": false
"single_version": false,
"versioning_scheme": "multiple_versions_with_translations"
}
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
],
"privacy_level": "public",
"external_builds_privacy_level": "public",
"single_version": false
"single_version": false,
"versioning_scheme": "multiple_versions_with_translations"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,6 @@
],
"privacy_level": "public",
"external_builds_privacy_level": "public",
"single_version": false
"single_version": false,
"versioning_scheme": "multiple_versions_with_translations"
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@
],
"privacy_level": "public",
"external_builds_privacy_level": "public",
"single_version": false
"single_version": false,
"versioning_scheme": "multiple_versions_with_translations"
},
"triggered": true,
"version": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@
"users": [{ "username": "testuser" }],
"privacy_level": "public",
"external_builds_privacy_level": "public",
"single_version": false
"single_version": false,
"versioning_scheme": "multiple_versions_with_translations"
}],
"remote_organization": {
"avatar_url": "https://avatars.githubusercontent.com/u/366329?v=4",
Expand Down
5 changes: 3 additions & 2 deletions readthedocs/api/v3/tests/test_projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from django.urls import reverse

from readthedocs.oauth.models import RemoteRepository
from readthedocs.projects.constants import SINGLE_VERSION_WITHOUT_TRANSLATIONS
from readthedocs.projects.models import Project

from .mixins import APIEndpointMixin
Expand Down Expand Up @@ -404,7 +405,7 @@ def test_update_project(self):
"default_branch": "updated-default-branch",
"analytics_code": "UA-XXXXXX",
"show_version_warning": False,
"single_version": True,
"versioning_scheme": SINGLE_VERSION_WITHOUT_TRANSLATIONS,
"external_builds_enabled": True,
}
url = reverse(
Expand Down Expand Up @@ -437,7 +438,7 @@ def test_update_project(self):
self.assertEqual(self.project.default_branch, "updated-default-branch")
self.assertEqual(self.project.analytics_code, "UA-XXXXXX")
self.assertEqual(self.project.show_version_warning, False)
self.assertEqual(self.project.single_version, True)
self.assertEqual(self.project.is_single_version, True)
self.assertEqual(self.project.external_builds_enabled, True)

def test_partial_update_project(self):
Expand Down
2 changes: 1 addition & 1 deletion readthedocs/core/resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def resolve_path(
filename = self._fix_filename(filename)

parent_project, project_relationship = self._get_canonical_project(project)
single_version = bool(project.single_version or single_version)
single_version = bool(project.is_single_version or single_version)

# If the project is a subproject, we use the custom prefix
# of the child of the relationship, this is since the project
Expand Down
4 changes: 2 additions & 2 deletions readthedocs/core/unresolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ def _unresolve_path_with_parent_project(
:returns: A tuple with: project, version, and filename.
"""
# Multiversion project.
if not parent_project.single_version:
if not parent_project.is_single_version:
response = self._match_multiversion_project(
parent_project=parent_project,
path=path,
Expand All @@ -463,7 +463,7 @@ def _unresolve_path_with_parent_project(
return response

# Single version project.
if parent_project.single_version:
if parent_project.is_single_version:
response = self._match_single_version_project(
parent_project=parent_project,
path=path,
Expand Down
2 changes: 1 addition & 1 deletion readthedocs/doc_builder/templates/doc_builder/conf.py.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ context = {
'programming_language': u'{{ project.programming_language }}',
'canonical_url': '{{ project.get_canonical_url }}',
'analytics_code': '{{ project.analytics_code }}',
'single_version': {{ project.single_version }},
'single_version': {{ project.is_single_version }},
'conf_py_path': '{{ conf_py_path }}',
'api_host': '{{ api_host }}',
'github_user': '{{ github_user }}',
Expand Down
59 changes: 31 additions & 28 deletions readthedocs/projects/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,43 +383,46 @@
'https://bitbucket.org/{user}/{repo}/'
'src/{version}{docroot}{path}{source_suffix}'
)
BITBUCKET_COMMIT_URL = (
'https://bitbucket.org/{user}/{repo}/'
'commits/{commit}'
)
BITBUCKET_COMMIT_URL = "https://bitbucket.org/{user}/{repo}/commits/{commit}"
GITLAB_URL = (
'https://gitlab.com/{user}/{repo}/'
'{action}/{version}{docroot}{path}{source_suffix}'
)
GITLAB_COMMIT_URL = (
'https://gitlab.com/{user}/{repo}/'
'commit/{commit}'
"https://gitlab.com/{user}/{repo}/"
"{action}/{version}{docroot}{path}{source_suffix}"
)
GITLAB_COMMIT_URL = "https://gitlab.com/{user}/{repo}/commit/{commit}"
GITLAB_MERGE_REQUEST_COMMIT_URL = (
'https://gitlab.com/{user}/{repo}/'
'commit/{commit}?merge_request_iid={number}'
)
GITLAB_MERGE_REQUEST_URL = (
'https://gitlab.com/{user}/{repo}/'
'merge_requests/{number}'
"https://gitlab.com/{user}/{repo}/commit/{commit}?merge_request_iid={number}"
)
GITLAB_MERGE_REQUEST_URL = "https://gitlab.com/{user}/{repo}/merge_requests/{number}"

# Patterns to pull merge/pull request from providers
GITHUB_PR_PULL_PATTERN = 'pull/{id}/head:external-{id}'
GITLAB_MR_PULL_PATTERN = 'merge-requests/{id}/head:external-{id}'
GITHUB_PR_PULL_PATTERN = "pull/{id}/head:external-{id}"
GITLAB_MR_PULL_PATTERN = "merge-requests/{id}/head:external-{id}"

# Git provider names
GITHUB_BRAND = 'GitHub'
GITLAB_BRAND = 'GitLab'
GITHUB_BRAND = "GitHub"
GITLAB_BRAND = "GitLab"

# SSL statuses
SSL_STATUS_VALID = 'valid'
SSL_STATUS_INVALID = 'invalid'
SSL_STATUS_PENDING = 'pending'
SSL_STATUS_UNKNOWN = 'unknown'
SSL_STATUS_VALID = "valid"
SSL_STATUS_INVALID = "invalid"
SSL_STATUS_PENDING = "pending"
SSL_STATUS_UNKNOWN = "unknown"
SSL_STATUS_CHOICES = (
(SSL_STATUS_VALID, _('Valid and active')),
(SSL_STATUS_INVALID, _('Invalid')),
(SSL_STATUS_PENDING, _('Pending')),
(SSL_STATUS_UNKNOWN, _('Unknown')),
(SSL_STATUS_VALID, _("Valid and active")),
(SSL_STATUS_INVALID, _("Invalid")),
(SSL_STATUS_PENDING, _("Pending")),
(SSL_STATUS_UNKNOWN, _("Unknown")),
)

MULTIPLE_VERSIONS_WITH_TRANSLATIONS = "multiple_versions_with_translations"
SINGLE_VERSION_WITHOUT_TRANSLATIONS = "single_version_without_translations"
VERSIONING_SCHEME_CHOICES = (
(
MULTIPLE_VERSIONS_WITH_TRANSLATIONS,
_("Multiple versions with translations (/<language>/<version>/<filename>)"),
),
(
SINGLE_VERSION_WITHOUT_TRANSLATIONS,
_("Single version without translations (/<filename>)"),
),
)
9 changes: 8 additions & 1 deletion readthedocs/projects/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ class Meta:
"analytics_code",
"analytics_disabled",
"show_version_warning",
"single_version",
"versioning_scheme",
"external_builds_enabled",
"external_builds_privacy_level",
"readthedocs_yaml_path",
Expand All @@ -236,6 +236,13 @@ def __init__(self, *args, **kwargs):
self.fields['analytics_disabled'].widget = forms.CheckboxInput()
self.fields['analytics_disabled'].empty_value = False

# Remove empty choice from options, and add a preview to the choices.
self.fields["versioning_scheme"].choices = [
(key, value)
for key, value in self.fields["versioning_scheme"].choices
if key
]

self.helper = FormHelper()
help_text = render_to_string(
'projects/project_advanced_settings_helptext.html'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Generated by Django 4.2.5 on 2023-10-18 22:04

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("projects", "0108_migrate_language_code"),
]

operations = [
migrations.AddField(
model_name="historicalproject",
name="versioning_scheme",
field=models.CharField(
choices=[
(
"multiple_versions_with_translations",
"Multiple versions with translations (/<language>/<version>/<filename>)",
),
(
"single_version_without_translations",
"Single version without translations (/<filename>)",
),
],
default="multiple_versions_with_translations",
help_text="This affects how the URL of your documentation looks like, and if it supports translations or multiple versions. Changing the versioning scheme will break your current URLs.",
max_length=120,
null=True,
verbose_name="Versioning scheme",
),
),
migrations.AddField(
model_name="project",
name="versioning_scheme",
field=models.CharField(
choices=[
(
"multiple_versions_with_translations",
"Multiple versions with translations (/<language>/<version>/<filename>)",
),
(
"single_version_without_translations",
"Single version without translations (/<filename>)",
),
],
default="multiple_versions_with_translations",
help_text="This affects how the URL of your documentation looks like, and if it supports translations or multiple versions. Changing the versioning scheme will break your current URLs.",
max_length=120,
null=True,
verbose_name="Versioning scheme",
),
),
]
Loading

0 comments on commit b5e547d

Please sign in to comment.