Skip to content

Allow for period as a prefix and yaml extension for config file #4512

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 27, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 5 additions & 11 deletions readthedocs/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
)

ALL = 'all'
CONFIG_FILENAMES = ('readthedocs.yml', '.readthedocs.yml')
CONFIG_FILENAME_REGEX = r'\.?readthedocs.ya?ml'

CONFIG_NOT_SUPPORTED = 'config-not-supported'
VERSION_INVALID = 'version-invalid'
Expand All @@ -48,7 +48,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 = {
Expand Down Expand Up @@ -966,17 +966,11 @@ def load(path, env_config):
the version of the configuration a build object would be load and validated,
``BuildConfigV1`` is the default.
"""
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),
code=CONFIG_REQUIRED,
)
raise ConfigError('No configuration file found',
code=CONFIG_REQUIRED)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our style guide is something like

raise ConfigError(
    'Text',
    code=CONFIG_REQUIRED
)

build_configs = []
with open(filename, 'r') as configuration_file:
try:
Expand Down
15 changes: 8 additions & 7 deletions readthedocs/config/find.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,21 @@
from __future__ import division, print_function, unicode_literals

import os
import re


def find_all(path, filenames):
"""Find all files in ``path`` that match in ``filenames``."""
def find_all(path, filename_regex):
"""Find all files in ``path`` that match ``filename_regex`` 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):
"""Find the first file in ``path`` that match in ``filenames``."""
for _path in find_all(path, filenames):
def find_one(path, filename_regex):
"""Find the first file in ``path`` that match ``filename_regex`` regex."""
for _path in find_all(path, filename_regex):
return _path
return ''
28 changes: 27 additions & 1 deletion readthedocs/config/tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import os
import textwrap
import re

import pytest
from mock import DEFAULT, patch
Expand All @@ -13,7 +14,7 @@
ConfigOptionNotSupportedError, InvalidConfig, ProjectConfig, load)
from readthedocs.config.config import (
CONFIG_NOT_SUPPORTED, NAME_INVALID, NAME_REQUIRED, PYTHON_INVALID,
VERSION_INVALID)
VERSION_INVALID, CONFIG_FILENAME_REGEX)
from readthedocs.config.validation import (
INVALID_BOOL, INVALID_CHOICE, INVALID_LIST, INVALID_PATH, INVALID_STRING)

Expand Down Expand Up @@ -49,6 +50,13 @@
'nested': minimal_config_dir,
}

yaml_extension_config_dir = {
'readthedocs.yaml': '''\
name: docs
type: sphinx
'''
}


def get_build_config(config, env_config=None, source_file='readthedocs.yml',
source_position=0):
Expand Down Expand Up @@ -137,6 +145,14 @@ def test_load_unknow_version(tmpdir):
assert excinfo.value.code == VERSION_INVALID


def test_yaml_extension(tmpdir):
""" Make sure it's capable of loading the 'readthedocs' file with a 'yaml' extension. """
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are spaces in the sides of this docstring

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]
Expand Down Expand Up @@ -790,6 +806,13 @@ def test_raise_config_not_supported():
assert excinfo.value.code == CONFIG_NOT_SUPPORTED


@pytest.mark.parametrize("correct_config_filename",
[prefix + "readthedocs." + extension for prefix in {"", "."}
for extension in {"yml", "yaml"}])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use singlequotes

def test_config_filenames_regex(correct_config_filename):
assert re.match(CONFIG_FILENAME_REGEX, correct_config_filename)


class TestBuildConfigV2(object):

def get_build_config(self, config, env_config=None,
Expand Down Expand Up @@ -1620,3 +1643,6 @@ def test_submodules_recursive_explict_default(self):
assert build.submodules.include == []
assert build.submodules.exclude == []
assert build.submodules.recursive is False



Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this extra lines shouldn't be here

27 changes: 9 additions & 18 deletions readthedocs/config/tests/test_find.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@

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


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'))
]
Expand All @@ -42,11 +42,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):
Expand All @@ -66,21 +66,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')
Expand All @@ -92,5 +83,5 @@ def test_find_unicode_path(tmpdir):
assert path == ''
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 == ''