diff --git a/docs/spec.rst b/docs/spec.rst index 810a120..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`` 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: diff --git a/readthedocs_build/config/config.py b/readthedocs_build/config/config.py index c84294e..4f6d61b 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_FILENAME_REGEX = r'\.?readthedocs.ya?ml' BASE_INVALID = 'base-invalid' @@ -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 = { @@ -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 configuration file found', 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_config.py b/readthedocs_build/config/test_config.py index 2515956..7a59535 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 @@ -48,6 +51,13 @@ ''' } +yaml_extension_config_dir = { + 'readthedocs.yaml': '''\ +name: docs +type: sphinx +''' +} + multiple_config_dir = { 'readthedocs.yml': ''' @@ -95,6 +105,14 @@ def test_minimal_config(tmpdir): assert isinstance(build, BuildConfig) +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 len(config) == 1 + + def test_build_config_has_source_file(tmpdir): base = str(apply_fs(tmpdir, minimal_config_dir)) build = load(base, env_config)[0] @@ -579,3 +597,10 @@ 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", + [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) diff --git a/readthedocs_build/config/test_find.py b/readthedocs_build/config/test_find.py index 3300302..06ace6c 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,11 +39,11 @@ def test_find_nested(tmpdir): apply_fs(tmpdir, {'first/readthedocs.yml': ''}) base = str(tmpdir) - paths = list(find_all(base, ('readthedocs.yml',))) - assert set(paths) == set([ + paths = set(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,21 +63,12 @@ def test_find_multiple_files(tmpdir): apply_fs(tmpdir, {'first/readthedocs.yml': ''}) base = str(tmpdir) - paths = list(find_all(base, ('readthedocs.yml', - '.readthedocs.yml'))) - assert paths == [ + paths = set(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') @@ -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'