From a705f9d13009b0d28b77f45205d80dc68d523aef Mon Sep 17 00:00:00 2001 From: Eric Holscher Date: Tue, 5 Dec 2017 09:27:49 -0800 Subject: [PATCH] Address review feedback and remove most of my deleted code :) --- docs/yaml-config.rst | 15 +++--- readthedocs/doc_builder/config.py | 23 +++++++-- readthedocs/doc_builder/constants.py | 1 + .../rtd_tests/tests/test_config_wrapper.py | 48 +++++++++++++++++++ 4 files changed, 76 insertions(+), 11 deletions(-) diff --git a/docs/yaml-config.rst b/docs/yaml-config.rst index c1429b119..0a8b6eb69 100644 --- a/docs/yaml-config.rst +++ b/docs/yaml-config.rst @@ -80,19 +80,20 @@ The ``build`` block configures specific aspects of the documentation build. build.image ``````````` -* Default: ``2.0`` + +* Default: :djangosetting:`DOCKER_IMAGE` * Options: ``1.0``, ``2.0``, ``latest`` -The docker image to use for specific builds. -This lets users specify a more experimental builder, +The build image to use for specific builds. +This lets users specify a more experimental build image, if they want to be on the cutting edge. -Certain Python versions require a certain builder, +Certain Python versions require a certain build image, as defined here:: -* '1.0': 2, 2.7, 3, 3.4 -* '2.0': 2, 2.7, 3, 3.5 -* 'latest': 2, 2.7, 3, 3.3, 3.4, 3.5, 3.6 +* `'1.0': 2, 2.7, 3, 3.4` +* `'2.0': 2, 2.7, 3, 3.5` +* `'latest': 2, 2.7, 3, 3.3, 3.4, 3.5, 3.6` .. code-block:: yaml diff --git a/readthedocs/doc_builder/config.py b/readthedocs/doc_builder/config.py index 28aa5e9e7..913fb5d49 100644 --- a/readthedocs/doc_builder/config.py +++ b/readthedocs/doc_builder/config.py @@ -8,6 +8,8 @@ from builtins import filter, object from readthedocs_build.config import load as load_config from readthedocs_build.config import BuildConfig, ConfigError, InvalidConfig +from .constants import DOCKER_BUILD_IMAGES, DOCKER_IMAGE + class ConfigWrapper(object): @@ -57,7 +59,7 @@ class ConfigWrapper(object): list( filter( lambda x: x < ver + 1, - self._yaml_config.PYTHON_SUPPORTED_VERSIONS, + self._yaml_config.get_valid_python_versions(), ))) return 'python{0}'.format(ver) @@ -133,8 +135,22 @@ def load_yaml_config(version): parsing consistent between projects. """ checkout_path = version.project.checkout_path(version.slug) + env_config = {} + + # Get build image to set up the python version validation. Pass in the + # build image python limitations to the loaded config so that the versions + # can be rejected at validation + build_image = DOCKER_BUILD_IMAGES.get( + version.project.container_image, + DOCKER_BUILD_IMAGES.get(DOCKER_IMAGE, None), + ) + if build_image: + env_config = { + 'python': build_image['python'], + } + try: - sphinx_env_config = {} + sphinx_env_config = env_config.copy() sphinx_env_config.update({ 'output_base': '', 'type': 'sphinx', @@ -148,9 +164,8 @@ def load_yaml_config(version): # This is a subclass of ConfigError, so has to come first raise except ConfigError: - # Just fall back to defaults config = BuildConfig( - env_config={}, + env_config=env_config, raw_config={}, source_file='empty', source_position=0, diff --git a/readthedocs/doc_builder/constants.py b/readthedocs/doc_builder/constants.py index 9d12b5830..7c9a107ba 100644 --- a/readthedocs/doc_builder/constants.py +++ b/readthedocs/doc_builder/constants.py @@ -33,6 +33,7 @@ DOCKER_SOCKET = getattr( ) DOCKER_VERSION = getattr(settings, 'DOCKER_VERSION', 'auto') DOCKER_IMAGE = getattr(settings, 'DOCKER_IMAGE', 'readthedocs/build:2.0') +DOCKER_BUILD_IMAGES = getattr(settings, 'DOCKER_BUILD_IMAGES', {}) DOCKER_LIMITS = {'memory': '200m', 'time': 600} DOCKER_LIMITS.update(getattr(settings, 'DOCKER_LIMITS', {})) diff --git a/readthedocs/rtd_tests/tests/test_config_wrapper.py b/readthedocs/rtd_tests/tests/test_config_wrapper.py index bc5025726..aaa374ae7 100644 --- a/readthedocs/rtd_tests/tests/test_config_wrapper.py +++ b/readthedocs/rtd_tests/tests/test_config_wrapper.py @@ -46,6 +46,54 @@ class LoadConfigTests(TestCase): install_project=False, requirements_file='urls.py') self.version = get(Version, project=self.project) + def test_python_supported_versions_default_image_1_0(self, load_config): + load_config.side_effect = create_load() + self.project.container_image = 'readthedocs/build:1.0' + self.project.save() + config = load_yaml_config(self.version) + self.assertEqual(load_config.call_count, 1) + load_config.assert_has_calls([ + mock.call(path=mock.ANY, env_config={ + 'python': {'supported_versions': [2, 2.7, 3, 3.4]}, + 'type': 'sphinx', + 'output_base': '', + 'name': mock.ANY + }), + ]) + self.assertEqual(config.python_version, 2) + + def test_python_supported_versions_image_2_0(self, load_config): + load_config.side_effect = create_load() + self.project.container_image = 'readthedocs/build:2.0' + self.project.save() + config = load_yaml_config(self.version) + self.assertEqual(load_config.call_count, 1) + load_config.assert_has_calls([ + mock.call(path=mock.ANY, env_config={ + 'python': {'supported_versions': [2, 2.7, 3, 3.5]}, + 'type': 'sphinx', + 'output_base': '', + 'name': mock.ANY + }), + ]) + self.assertEqual(config.python_version, 2) + + def test_python_supported_versions_image_latest(self, load_config): + load_config.side_effect = create_load() + self.project.container_image = 'readthedocs/build:latest' + self.project.save() + config = load_yaml_config(self.version) + self.assertEqual(load_config.call_count, 1) + load_config.assert_has_calls([ + mock.call(path=mock.ANY, env_config={ + 'python': {'supported_versions': [2, 2.7, 3, 3.3, 3.4, 3.5, 3.6]}, + 'type': 'sphinx', + 'output_base': '', + 'name': mock.ANY + }), + ]) + self.assertEqual(config.python_version, 2) + def test_python_default_version(self, load_config): load_config.side_effect = create_load() config = load_yaml_config(self.version)