From f0449690445fb93b2144f02a04ebd99e6c594c70 Mon Sep 17 00:00:00 2001 From: Stefano Chiodino Date: Tue, 22 May 2018 21:30:57 +0100 Subject: [PATCH 01/11] Test for yaml config file extension (fails). --- readthedocs_build/config/test_config.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/readthedocs_build/config/test_config.py b/readthedocs_build/config/test_config.py index 2515956..b2dff1f 100644 --- a/readthedocs_build/config/test_config.py +++ b/readthedocs_build/config/test_config.py @@ -48,6 +48,13 @@ ''' } +yaml_extension_config_dir = { + 'readthedocs.yaml': '''\ +name: docs +type: sphinx +''' +} + multiple_config_dir = { 'readthedocs.yml': ''' @@ -95,6 +102,16 @@ def test_minimal_config(tmpdir): assert isinstance(build, BuildConfig) +def test_yaml_extension(tmpdir): + apply_fs(tmpdir, yaml_extension_config_dir) + base = str(tmpdir) + config = load(base, env_config) + assert isinstance(config, ProjectConfig) + assert len(config) == 1 + build = config[0] + assert isinstance(build, BuildConfig) + + def test_build_config_has_source_file(tmpdir): base = str(apply_fs(tmpdir, minimal_config_dir)) build = load(base, env_config)[0] From 9c000fbf5e55bf792275b2ff74ae8dc8f5c906a4 Mon Sep 17 00:00:00 2001 From: Stefano Chiodino Date: Tue, 22 May 2018 21:42:33 +0100 Subject: [PATCH 02/11] Add a basic .yaml file and add it to the config filenames. --- integration_tests/minimal_project/readthedocs.yaml | 2 ++ readthedocs_build/config/config.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 integration_tests/minimal_project/readthedocs.yaml diff --git a/integration_tests/minimal_project/readthedocs.yaml b/integration_tests/minimal_project/readthedocs.yaml new file mode 100644 index 0000000..9072ff5 --- /dev/null +++ b/integration_tests/minimal_project/readthedocs.yaml @@ -0,0 +1,2 @@ +name: docs +type: sphinx diff --git a/readthedocs_build/config/config.py b/readthedocs_build/config/config.py index c84294e..56a3f02 100644 --- a/readthedocs_build/config/config.py +++ b/readthedocs_build/config/config.py @@ -14,7 +14,7 @@ 'load', 'BuildConfig', 'ConfigError', 'InvalidConfig', 'ProjectConfig') -CONFIG_FILENAMES = ('readthedocs.yml', '.readthedocs.yml') +CONFIG_FILENAMES = ('readthedocs.yml', '.readthedocs.yml', 'readthedocs.yaml') BASE_INVALID = 'base-invalid' From f1fa2db06c81d2005c31c73738f090a97cdd1998 Mon Sep 17 00:00:00 2001 From: Stefano Chiodino Date: Tue, 22 May 2018 21:53:05 +0100 Subject: [PATCH 03/11] Reduce test to just being able to load the file. Fix some typos and document the new file extension. --- docs/spec.rst | 4 ++-- readthedocs_build/config/config.py | 2 +- readthedocs_build/config/test_config.py | 4 +--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/spec.rst b/docs/spec.rst index 810a120..3e1c409 100644 --- a/docs/spec.rst +++ b/docs/spec.rst @@ -12,8 +12,8 @@ Creating a build works like this: ``rtd-build`` will then perform the following actions: -- it searches for all ``readthedocs.yml`` files below the current directory - and merges all found files into a list of configurations +- it searches for all ``readthedocs.yml``, ``.readthedocs.yml``, or ``readthedocs.yaml`` files below the current + directory and merges all found files into a list of configurations - it iterates over all configurations (order is not garuanteed) and performs the following actions for each: diff --git a/readthedocs_build/config/config.py b/readthedocs_build/config/config.py index 56a3f02..71d339e 100644 --- a/readthedocs_build/config/config.py +++ b/readthedocs_build/config/config.py @@ -29,7 +29,7 @@ DOCKER_DEFAULT_IMAGE = 'readthedocs/build' DOCKER_DEFAULT_VERSION = '2.0' -# These map to coordisponding settings in the .org, +# These map to corresponding settings in the .org, # so they haven't been renamed. DOCKER_IMAGE = '{}:{}'.format(DOCKER_DEFAULT_IMAGE, DOCKER_DEFAULT_VERSION) DOCKER_IMAGE_SETTINGS = { diff --git a/readthedocs_build/config/test_config.py b/readthedocs_build/config/test_config.py index b2dff1f..3033dea 100644 --- a/readthedocs_build/config/test_config.py +++ b/readthedocs_build/config/test_config.py @@ -103,13 +103,11 @@ def test_minimal_config(tmpdir): def test_yaml_extension(tmpdir): + """ Make sure it's capable of loading the 'readthedocs' file with a 'yaml' extension. """ apply_fs(tmpdir, yaml_extension_config_dir) base = str(tmpdir) config = load(base, env_config) - assert isinstance(config, ProjectConfig) assert len(config) == 1 - build = config[0] - assert isinstance(build, BuildConfig) def test_build_config_has_source_file(tmpdir): From d4c888ba745caeaf17c750277c660a5c7b411b56 Mon Sep 17 00:00:00 2001 From: Stefano Chiodino Date: Wed, 23 May 2018 07:10:29 +0100 Subject: [PATCH 04/11] Use regex to find the readthedocs yaml file. --- readthedocs_build/config/config.py | 10 +++------- readthedocs_build/config/find.py | 11 ++++++----- readthedocs_build/config/test_find.py | 19 +++++-------------- 3 files changed, 14 insertions(+), 26 deletions(-) diff --git a/readthedocs_build/config/config.py b/readthedocs_build/config/config.py index 71d339e..dd3e8ca 100644 --- a/readthedocs_build/config/config.py +++ b/readthedocs_build/config/config.py @@ -14,7 +14,7 @@ 'load', 'BuildConfig', 'ConfigError', 'InvalidConfig', 'ProjectConfig') -CONFIG_FILENAMES = ('readthedocs.yml', '.readthedocs.yml', 'readthedocs.yaml') +CONFIG_FILENAME_REGEX = r'\.?readthedocs.ya?ml' BASE_INVALID = 'base-invalid' @@ -433,14 +433,10 @@ def load(path, env_config): The config will be validated. """ - filename = find_one(path, CONFIG_FILENAMES) + filename = find_one(path, CONFIG_FILENAME_REGEX) if not filename: - files = '{}'.format(', '.join(map(repr, CONFIG_FILENAMES[:-1]))) - if files: - files += ' or ' - files += '{!r}'.format(CONFIG_FILENAMES[-1]) - raise ConfigError('No files {} found'.format(files), + raise ConfigError('No files with regex \'{}\' found'.format(CONFIG_FILENAME_REGEX), code=CONFIG_REQUIRED) build_configs = [] with open(filename, 'r') as file: diff --git a/readthedocs_build/config/find.py b/readthedocs_build/config/find.py index daf1cec..60044bd 100644 --- a/readthedocs_build/config/find.py +++ b/readthedocs_build/config/find.py @@ -1,16 +1,17 @@ import os +import re -def find_all(path, filenames): +def find_all(path, filename_regex): path = os.path.abspath(path) for root, dirs, files in os.walk(path, topdown=True): dirs.sort() - for filename in filenames: - if filename in files: + for filename in files: + if re.match(filename_regex, filename): yield os.path.abspath(os.path.join(root, filename)) -def find_one(path, filenames): - for _path in find_all(path, filenames): +def find_one(path, filename_regex): + for _path in find_all(path, filename_regex): return _path return '' diff --git a/readthedocs_build/config/test_find.py b/readthedocs_build/config/test_find.py index 3300302..a9bdd21 100644 --- a/readthedocs_build/config/test_find.py +++ b/readthedocs_build/config/test_find.py @@ -9,7 +9,7 @@ def test_find_no_files(tmpdir): with tmpdir.as_cwd(): - paths = list(find_all(os.getcwd(), ('readthedocs.yml',))) + paths = list(find_all(os.getcwd(), r'readthedocs.yml')) assert len(paths) == 0 @@ -17,7 +17,7 @@ def test_find_at_root(tmpdir): apply_fs(tmpdir, {'readthedocs.yml': '', 'otherfile.txt': ''}) base = str(tmpdir) - paths = list(find_all(base, ('readthedocs.yml',))) + paths = list(find_all(base, r'readthedocs\.yml')) assert paths == [ os.path.abspath(os.path.join(base, 'readthedocs.yml')) ] @@ -39,7 +39,7 @@ def test_find_nested(tmpdir): apply_fs(tmpdir, {'first/readthedocs.yml': ''}) base = str(tmpdir) - paths = list(find_all(base, ('readthedocs.yml',))) + paths = list(find_all(base, r'readthedocs\.yml')) assert set(paths) == set([ str(tmpdir.join('first', 'readthedocs.yml')), str(tmpdir.join('third', 'readthedocs.yml')), @@ -63,22 +63,13 @@ def test_find_multiple_files(tmpdir): apply_fs(tmpdir, {'first/readthedocs.yml': ''}) base = str(tmpdir) - paths = list(find_all(base, ('readthedocs.yml', - '.readthedocs.yml'))) + paths = list(find_all(base, r'\.?readthedocs.yml')) assert paths == [ str(tmpdir.join('first', 'readthedocs.yml')), str(tmpdir.join('first', '.readthedocs.yml')), str(tmpdir.join('third', 'readthedocs.yml')), ] - paths = list(find_all(base, ('.readthedocs.yml', - 'readthedocs.yml'))) - assert paths == [ - str(tmpdir.join('first', '.readthedocs.yml')), - str(tmpdir.join('first', 'readthedocs.yml')), - str(tmpdir.join('third', 'readthedocs.yml')), - ] - @pytest.mark.skipif(not six.PY2, reason='Only for python2') @pytest.mark.xfail(raises=UnicodeDecodeError) @@ -87,6 +78,6 @@ def test_find_unicode_path(tmpdir): assert isinstance(base_path, str) unicode_base_path = base_path.decode('utf-8') assert isinstance(unicode_base_path, unicode) - path = find_one(unicode_base_path, ('readthedocs.yml',)) + path = find_one(unicode_base_path, r'readthedocs\.yml') assert path == '' assert False, 'The UnicodeDecodeError was not raised' From d87677c99ac549361838220a86e1e995f7a282c3 Mon Sep 17 00:00:00 2001 From: Stefano Chiodino Date: Thu, 24 May 2018 07:00:11 +0100 Subject: [PATCH 05/11] Use sets for paths found now that order doesn't matter any more. --- readthedocs_build/config/test_find.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/readthedocs_build/config/test_find.py b/readthedocs_build/config/test_find.py index a9bdd21..50048ca 100644 --- a/readthedocs_build/config/test_find.py +++ b/readthedocs_build/config/test_find.py @@ -39,11 +39,11 @@ def test_find_nested(tmpdir): apply_fs(tmpdir, {'first/readthedocs.yml': ''}) base = str(tmpdir) - paths = list(find_all(base, r'readthedocs\.yml')) - assert set(paths) == set([ + paths = set(list(find_all(base, r'readthedocs\.yml'))) + assert paths == { str(tmpdir.join('first', 'readthedocs.yml')), str(tmpdir.join('third', 'readthedocs.yml')), - ]) + } def test_find_multiple_files(tmpdir): @@ -63,12 +63,12 @@ def test_find_multiple_files(tmpdir): apply_fs(tmpdir, {'first/readthedocs.yml': ''}) base = str(tmpdir) - paths = list(find_all(base, r'\.?readthedocs.yml')) - assert paths == [ + paths = set(list(find_all(base, r'\.?readthedocs\.yml'))) + assert paths == { str(tmpdir.join('first', 'readthedocs.yml')), str(tmpdir.join('first', '.readthedocs.yml')), str(tmpdir.join('third', 'readthedocs.yml')), - ] + } @pytest.mark.skipif(not six.PY2, reason='Only for python2') From 887e0ea7932d25db5c34eb97c7a62d5618adae82 Mon Sep 17 00:00:00 2001 From: Stefano Chiodino Date: Tue, 5 Jun 2018 20:43:19 +0100 Subject: [PATCH 06/11] Convert directly to sets --- readthedocs_build/config/test_find.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readthedocs_build/config/test_find.py b/readthedocs_build/config/test_find.py index 50048ca..06ace6c 100644 --- a/readthedocs_build/config/test_find.py +++ b/readthedocs_build/config/test_find.py @@ -39,7 +39,7 @@ def test_find_nested(tmpdir): apply_fs(tmpdir, {'first/readthedocs.yml': ''}) base = str(tmpdir) - paths = set(list(find_all(base, r'readthedocs\.yml'))) + paths = set(find_all(base, r'readthedocs\.yml')) assert paths == { str(tmpdir.join('first', 'readthedocs.yml')), str(tmpdir.join('third', 'readthedocs.yml')), @@ -63,7 +63,7 @@ def test_find_multiple_files(tmpdir): apply_fs(tmpdir, {'first/readthedocs.yml': ''}) base = str(tmpdir) - paths = set(list(find_all(base, r'\.?readthedocs\.yml'))) + paths = set(find_all(base, r'\.?readthedocs\.yml')) assert paths == { str(tmpdir.join('first', 'readthedocs.yml')), str(tmpdir.join('first', '.readthedocs.yml')), From cc2ef317d1d7873208ef572603afced275a69cd7 Mon Sep 17 00:00:00 2001 From: Stefano Chiodino Date: Fri, 8 Jun 2018 07:32:19 +0100 Subject: [PATCH 07/11] Remove .yaml file that was not actually necessary. --- integration_tests/minimal_project/readthedocs.yaml | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 integration_tests/minimal_project/readthedocs.yaml diff --git a/integration_tests/minimal_project/readthedocs.yaml b/integration_tests/minimal_project/readthedocs.yaml deleted file mode 100644 index 9072ff5..0000000 --- a/integration_tests/minimal_project/readthedocs.yaml +++ /dev/null @@ -1,2 +0,0 @@ -name: docs -type: sphinx From 0f1f4a623246a013d79289022817ed3f4283a433 Mon Sep 17 00:00:00 2001 From: Stefano Chiodino Date: Sat, 9 Jun 2018 08:55:11 +0100 Subject: [PATCH 08/11] Add test for possible config filenames. --- readthedocs_build/config/test_config.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/readthedocs_build/config/test_config.py b/readthedocs_build/config/test_config.py index 3033dea..39df151 100644 --- a/readthedocs_build/config/test_config.py +++ b/readthedocs_build/config/test_config.py @@ -1,10 +1,13 @@ +import re + +import pytest from mock import patch from mock import DEFAULT from pytest import raises import os from ..testing.utils import apply_fs -from .config import ConfigError +from .config import ConfigError, CONFIG_FILENAME_REGEX from .config import InvalidConfig from .config import load from .config import BuildConfig @@ -594,3 +597,9 @@ def test_project_set_output_base(): for build_config in project: assert ( build_config['output_base'] == os.path.join(os.getcwd(), 'random')) + + +@pytest.mark.parametrize("correct_config_filename", + {"readthedocs.yml", "readthedocs.yaml", ".readthedocs.yml", ".readthedocs.yaml"}) +def test_config_filenames_regex(correct_config_filename): + assert re.match(CONFIG_FILENAME_REGEX, correct_config_filename) From ec96e3bd56d09fcb2624f885d6b0f51cb84cc8b4 Mon Sep 17 00:00:00 2001 From: Stefano Chiodino Date: Sat, 9 Jun 2018 09:05:09 +0100 Subject: [PATCH 09/11] Improve code readability --- readthedocs_build/config/test_config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/readthedocs_build/config/test_config.py b/readthedocs_build/config/test_config.py index 39df151..7a59535 100644 --- a/readthedocs_build/config/test_config.py +++ b/readthedocs_build/config/test_config.py @@ -600,6 +600,7 @@ def test_project_set_output_base(): @pytest.mark.parametrize("correct_config_filename", - {"readthedocs.yml", "readthedocs.yaml", ".readthedocs.yml", ".readthedocs.yaml"}) + [prefix + "readthedocs." + extension for prefix in {"", "."} + for extension in {"yml", "yaml"}]) def test_config_filenames_regex(correct_config_filename): assert re.match(CONFIG_FILENAME_REGEX, correct_config_filename) From afffb2eee25652959ace9e5ad6a888742854b357 Mon Sep 17 00:00:00 2001 From: Stefano Chiodino Date: Sat, 9 Jun 2018 09:11:25 +0100 Subject: [PATCH 10/11] Improve file naming options --- docs/spec.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/spec.rst b/docs/spec.rst index 3e1c409..0d684ed 100644 --- a/docs/spec.rst +++ b/docs/spec.rst @@ -12,8 +12,9 @@ Creating a build works like this: ``rtd-build`` will then perform the following actions: -- it searches for all ``readthedocs.yml``, ``.readthedocs.yml``, or ``readthedocs.yaml`` files below the current - directory and merges all found files into a list of configurations +- it searches for all ``readthedocs.yml`` (optionally use ``.`` prefix or + extension ``yaml``) files below the current directory and merges all found + files into a list of configurations - it iterates over all configurations (order is not garuanteed) and performs the following actions for each: From 1b1ae9aa80f790c0cbcd9869099218799f9ea8b5 Mon Sep 17 00:00:00 2001 From: Stefano Chiodino Date: Tue, 19 Jun 2018 19:22:41 +0100 Subject: [PATCH 11/11] Make config error more generic. --- readthedocs_build/config/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs_build/config/config.py b/readthedocs_build/config/config.py index dd3e8ca..4f6d61b 100644 --- a/readthedocs_build/config/config.py +++ b/readthedocs_build/config/config.py @@ -436,7 +436,7 @@ def load(path, env_config): filename = find_one(path, CONFIG_FILENAME_REGEX) if not filename: - raise ConfigError('No files with regex \'{}\' found'.format(CONFIG_FILENAME_REGEX), + raise ConfigError('No configuration file found', code=CONFIG_REQUIRED) build_configs = [] with open(filename, 'r') as file: