Skip to content

Commit fb84ad8

Browse files
committed
initial work at multiple .readthedocs.yml files per repo
1 parent ce1a81a commit fb84ad8

File tree

8 files changed

+62
-4
lines changed

8 files changed

+62
-4
lines changed

readthedocs/api/v2/serializers.py

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ class Meta(ProjectSerializer.Meta):
9393
'show_advertising',
9494
'environment_variables',
9595
'max_concurrent_builds',
96+
'rtd_conf_file',
9697
)
9798

9899

readthedocs/config/config.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -1369,15 +1369,20 @@ def search(self):
13691369
return Search(**self._config['search'])
13701370

13711371

1372-
def load(path, env_config):
1372+
def load(path, env_config, config_file=None):
13731373
"""
13741374
Load a project configuration and the top-most build config for a given path.
13751375
13761376
That is usually the root of the project, but will look deeper. According to
13771377
the version of the configuration a build object would be load and validated,
13781378
``BuildConfigV1`` is the default.
13791379
"""
1380-
filename = find_one(path, CONFIG_FILENAME_REGEX)
1380+
if config_file is None or config_file == '':
1381+
filename = find_one(path, CONFIG_FILENAME_REGEX)
1382+
else:
1383+
filename = os.path.join(path, config_file)
1384+
if not os.path.exists(filename):
1385+
raise ConfigError(f".readthedocs.yml not found at {config_file}", CONFIG_FILE_REQUIRED)
13811386

13821387
if not filename:
13831388
raise ConfigFileNotFound(path)

readthedocs/doc_builder/config.py

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ def load_yaml_config(version):
5656
config = load_config(
5757
path=checkout_path,
5858
env_config=env_config,
59+
config_file=project.rtd_conf_file,
5960
)
6061
except ConfigFileNotFound:
6162
# Default to use v1 with some defaults from the web interface

readthedocs/projects/forms.py

+12
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ class Meta:
207207
'single_version',
208208
'external_builds_enabled',
209209
'external_builds_privacy_level',
210+
'rtd_conf_file',
210211
)
211212
# These that can be set per-version using a config file.
212213
per_version_settings = (
@@ -357,6 +358,17 @@ def clean_conf_py_file(self):
357358
) # yapf: disable
358359
return filename
359360

361+
def clean_rtd_conf_file(self):
362+
filename = self.cleaned_data.get('rtd_conf_file', '').strip()
363+
if filename and '.readthedocs.yml' not in filename:
364+
raise forms.ValidationError(
365+
_(
366+
'Your configuration file is invalid, make sure it contains '
367+
'.readthedocs.yml in it.',
368+
),
369+
) # yapf: disable
370+
return filename
371+
360372
def get_all_active_versions(self):
361373
"""
362374
Returns all active versions.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Generated by Django 3.2.17 on 2023-02-07 16:42
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('projects', '0095_default_branch_helptext'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='historicalproject',
15+
name='rtd_conf_file',
16+
field=models.CharField(blank=True, default='', help_text='Path from project root to <code>.readthedocs.yml</code> file (ex. <code>docs/.readthedocs.yml</code>). Leave blank if you want us to find it for you.', max_length=255, verbose_name='.readthedocs.yml configuration file'),
17+
),
18+
migrations.AddField(
19+
model_name='project',
20+
name='rtd_conf_file',
21+
field=models.CharField(blank=True, default='', help_text='Path from project root to <code>.readthedocs.yml</code> file (ex. <code>docs/.readthedocs.yml</code>). Leave blank if you want us to find it for you.', max_length=255, verbose_name='.readthedocs.yml configuration file'),
22+
),
23+
]

readthedocs/projects/models.py

+11
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,17 @@ class Project(models.Model):
357357
'Leave blank if you want us to find it for you.',
358358
),
359359
)
360+
rtd_conf_file = models.CharField(
361+
_('.readthedocs.yml configuration file'),
362+
max_length=255,
363+
default='',
364+
blank=True,
365+
help_text=_(
366+
'Path from project root to <code>.readthedocs.yml</code> file '
367+
'(ex. <code>docs/.readthedocs.yml</code>). '
368+
'Leave blank if you want us to find it for you.',
369+
),
370+
)
360371

361372
featured = models.BooleanField(_('Featured'), default=False)
362373
skip = models.BooleanField(_('Skip'), default=False)

readthedocs/rtd_tests/tests/test_api.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -686,19 +686,22 @@ class APITests(TestCase):
686686
def test_user_doesnt_get_full_api_return(self):
687687
user_normal = get(User, is_staff=False)
688688
user_admin = get(User, is_staff=True)
689-
project = get(Project, main_language_project=None, conf_py_file='foo')
689+
project = get(Project, main_language_project=None, conf_py_file='foo', rtd_conf_file='bar')
690690
client = APIClient()
691691

692692
client.force_authenticate(user=user_normal)
693693
resp = client.get('/api/v2/project/%s/' % (project.pk))
694694
self.assertEqual(resp.status_code, 200)
695695
self.assertNotIn('conf_py_file', resp.data)
696+
self.assertNotIn('rtd_conf_file', resp.data)
696697

697698
client.force_authenticate(user=user_admin)
698699
resp = client.get('/api/v2/project/%s/' % (project.pk))
699700
self.assertEqual(resp.status_code, 200)
700701
self.assertIn('conf_py_file', resp.data)
701702
self.assertEqual(resp.data['conf_py_file'], 'foo')
703+
self.assertIn('rtd_conf_file', resp.data)
704+
self.assertEqual(resp.data['rtd_conf_file'], 'bar')
702705

703706
def test_project_features(self):
704707
user = get(User, is_staff=True)
@@ -2453,6 +2456,7 @@ def test_get_version_by_id(self):
24532456
"repo": "https://github.com/pypa/pip",
24542457
"repo_type": "git",
24552458
"requirements_file": None,
2459+
"rtd_conf_file": "",
24562460
"show_advertising": True,
24572461
"skip": False,
24582462
"slug": "pip",

readthedocs/rtd_tests/tests/test_config_integration.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def create_load(config=None):
2323
if config is None:
2424
config = {}
2525

26-
def inner(path=None, env_config=None):
26+
def inner(path=None, env_config=None, config_file=None):
2727
env_config_defaults = {
2828
'output_base': '',
2929
'name': '1',
@@ -99,6 +99,7 @@ def test_python_supported_versions_default_image_1_0(self, load_config):
9999
load_config.assert_called_once_with(
100100
path=mock.ANY,
101101
env_config=expected_env_config,
102+
config_file='',
102103
)
103104
self.assertEqual(config.python.version, '3')
104105

0 commit comments

Comments
 (0)